diff --git a/Jenkinsfile b/Jenkinsfile index 6030f2b4a021d..277c5a9424cad 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -12,6 +12,7 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a 'kibana-intake-agent': kibanaPipeline.legacyJobRunner('kibana-intake'), 'x-pack-intake-agent': kibanaPipeline.legacyJobRunner('x-pack-intake'), 'kibana-oss-agent': kibanaPipeline.withWorkers('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ + 'oss-firefoxSmoke': kibanaPipeline.getPostBuildWorker('firefoxSmoke', { runbld('./test/scripts/jenkins_firefox_smoke.sh', 'Execute kibana-firefoxSmoke') }), 'oss-ciGroup1': kibanaPipeline.getOssCiGroupWorker(1), 'oss-ciGroup2': kibanaPipeline.getOssCiGroupWorker(2), 'oss-ciGroup3': kibanaPipeline.getOssCiGroupWorker(3), @@ -24,11 +25,11 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a 'oss-ciGroup10': kibanaPipeline.getOssCiGroupWorker(10), 'oss-ciGroup11': kibanaPipeline.getOssCiGroupWorker(11), 'oss-ciGroup12': kibanaPipeline.getOssCiGroupWorker(12), - 'oss-firefoxSmoke': kibanaPipeline.getPostBuildWorker('firefoxSmoke', { runbld('./test/scripts/jenkins_firefox_smoke.sh', 'Execute kibana-firefoxSmoke') }), 'oss-accessibility': kibanaPipeline.getPostBuildWorker('accessibility', { runbld('./test/scripts/jenkins_accessibility.sh', 'Execute kibana-accessibility') }), 'oss-visualRegression': kibanaPipeline.getPostBuildWorker('visualRegression', { runbld('./test/scripts/jenkins_visual_regression.sh', 'Execute kibana-visualRegression') }), ]), 'kibana-xpack-agent': kibanaPipeline.withWorkers('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ + 'xpack-firefoxSmoke': kibanaPipeline.getPostBuildWorker('xpack-firefoxSmoke', { runbld('./test/scripts/jenkins_xpack_firefox_smoke.sh', 'Execute xpack-firefoxSmoke') }), 'xpack-ciGroup1': kibanaPipeline.getXpackCiGroupWorker(1), 'xpack-ciGroup2': kibanaPipeline.getXpackCiGroupWorker(2), 'xpack-ciGroup3': kibanaPipeline.getXpackCiGroupWorker(3), @@ -39,7 +40,6 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a 'xpack-ciGroup8': kibanaPipeline.getXpackCiGroupWorker(8), 'xpack-ciGroup9': kibanaPipeline.getXpackCiGroupWorker(9), 'xpack-ciGroup10': kibanaPipeline.getXpackCiGroupWorker(10), - 'xpack-firefoxSmoke': kibanaPipeline.getPostBuildWorker('xpack-firefoxSmoke', { runbld('./test/scripts/jenkins_xpack_firefox_smoke.sh', 'Execute xpack-firefoxSmoke') }), 'xpack-accessibility': kibanaPipeline.getPostBuildWorker('xpack-accessibility', { runbld('./test/scripts/jenkins_xpack_accessibility.sh', 'Execute xpack-accessibility') }), 'xpack-visualRegression': kibanaPipeline.getPostBuildWorker('xpack-visualRegression', { runbld('./test/scripts/jenkins_xpack_visual_regression.sh', 'Execute xpack-visualRegression') }), ]), diff --git a/config/kibana.yml b/config/kibana.yml index 47482f9e6d59f..0780841ca057e 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -51,7 +51,7 @@ # Optional settings that provide the paths to the PEM-format SSL certificate and key files. # These files are used to verify the identity of Kibana to Elasticsearch and are required when -# xpack.ssl.verification_mode in Elasticsearch is set to either certificate or full. +# xpack.security.http.ssl.client_authentication in Elasticsearch is set to required. #elasticsearch.ssl.certificate: /path/to/your/client.crt #elasticsearch.ssl.key: /path/to/your/client.key diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index 0827cf5c73009..f3e7273adedee 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -9,7 +9,7 @@ https://github.com/elastic/kibana-docker/tree/{branch}[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/deb.asciidoc b/docs/setup/install/deb.asciidoc index 9cd83f44885cb..62ab661d9a66c 100644 --- a/docs/setup/install/deb.asciidoc +++ b/docs/setup/install/deb.asciidoc @@ -7,7 +7,7 @@ Kibana on any Debian-based system such as Debian and Ubuntu. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/rpm.asciidoc b/docs/setup/install/rpm.asciidoc index ddff35c61b5bb..77a16e67cf2a4 100644 --- a/docs/setup/install/rpm.asciidoc +++ b/docs/setup/install/rpm.asciidoc @@ -11,7 +11,7 @@ such as SLES 11 and CentOS 5. Please see <> instead. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/targz.asciidoc b/docs/setup/install/targz.asciidoc index e3104520292ff..d2143f39fba50 100644 --- a/docs/setup/install/targz.asciidoc +++ b/docs/setup/install/targz.asciidoc @@ -6,7 +6,7 @@ are the easiest formats to use when trying out Kibana. These packages are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/windows.asciidoc b/docs/setup/install/windows.asciidoc index b9f0224e67699..db55451f01aae 100644 --- a/docs/setup/install/windows.asciidoc +++ b/docs/setup/install/windows.asciidoc @@ -5,7 +5,7 @@ Kibana can be installed on Windows using the `.zip` package. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index f2c06a3737c7c..5605ed5c56688 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -258,6 +258,12 @@ running behind a proxy. Use the `server.rewriteBasePath` setting to tell Kibana if it should remove the basePath from requests it receives, and to prevent a deprecation warning at startup. This setting cannot end in a slash (`/`). +[[server-compression]]`server.compression.enabled:`:: *Default: `true`* Set to `false` to disable HTTP compression for all responses. + +`server.compression.referrerWhitelist:`:: *Default: none* Specifies an array of trusted hostnames, such as the Kibana host, or a reverse +proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request's `Referer` header. +This setting may not be used when `server.compression.enabled` is set to `false`. + [[server-cors]]`server.cors:`:: *Default: `false`* Set to `true` to enable CORS support. This setting is required to configure `server.cors.origin`. `server.cors.origin:`:: *Default: none* Specifies origins. "origin" must be an array. To use this setting, you must set `server.cors` to `true`. To accept all origins, use `server.cors.origin: ["*"]`. diff --git a/src/core/server/http/__snapshots__/http_config.test.ts.snap b/src/core/server/http/__snapshots__/http_config.test.ts.snap index 57d9db5e8c1e4..6c690f9da70c3 100644 --- a/src/core/server/http/__snapshots__/http_config.test.ts.snap +++ b/src/core/server/http/__snapshots__/http_config.test.ts.snap @@ -1,17 +1,35 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`accepts valid hostnames: valid host names 1`] = ` +exports[`accepts valid hostnames 1`] = ` Object { - "host1": "www.example.com", - "host2": "8.8.8.8", - "host3": "::1", - "host4": "localhost", + "host": "www.example.com", +} +`; + +exports[`accepts valid hostnames 2`] = ` +Object { + "host": "8.8.8.8", +} +`; + +exports[`accepts valid hostnames 3`] = ` +Object { + "host": "::1", +} +`; + +exports[`accepts valid hostnames 4`] = ` +Object { + "host": "localhost", } `; exports[`has defaults for config 1`] = ` Object { "autoListen": true, + "compression": Object { + "enabled": true, + }, "cors": false, "host": "localhost", "keepaliveTimeout": 120000, @@ -82,3 +100,18 @@ exports[`with TLS throws if TLS is enabled but \`certificate\` is not specified exports[`with TLS throws if TLS is enabled but \`key\` is not specified 1`] = `"[ssl]: must specify [certificate] and [key] when ssl is enabled"`; exports[`with TLS throws if TLS is enabled but \`redirectHttpFromPort\` is equal to \`port\` 1`] = `"Kibana does not accept http traffic to [port] when ssl is enabled (only https is allowed), so [ssl.redirectHttpFromPort] cannot be configured to the same value. Both are [1234]."`; + +exports[`with compression accepts valid referrer whitelist 1`] = ` +Array [ + "www.example.com", + "8.8.8.8", + "::1", + "localhost", +] +`; + +exports[`with compression throws if invalid referrer whitelist 1`] = `"[compression.referrerWhitelist.0]: value is [asdf$%^] but it must be a valid hostname (see RFC 1123)."`; + +exports[`with compression throws if invalid referrer whitelist 2`] = `"[compression.referrerWhitelist]: array size is [0], but cannot be smaller than [1]"`; + +exports[`with compression throws if referrer whitelist is specified and compression is disabled 1`] = `"cannot use [compression.referrerWhitelist] when [compression.enabled] is set to false"`; diff --git a/src/core/server/http/cookie_sesson_storage.test.ts b/src/core/server/http/cookie_session_storage.test.ts similarity index 99% rename from src/core/server/http/cookie_sesson_storage.test.ts rename to src/core/server/http/cookie_session_storage.test.ts index bf0585ad280d5..0e4f3972fe9dc 100644 --- a/src/core/server/http/cookie_sesson_storage.test.ts +++ b/src/core/server/http/cookie_session_storage.test.ts @@ -57,6 +57,7 @@ configService.atPath.mockReturnValue( ssl: { verificationMode: 'none', }, + compression: { enabled: true }, } as any) ); diff --git a/src/core/server/http/http_config.test.ts b/src/core/server/http/http_config.test.ts index 2b627c265dbba..1ee7e13d5e851 100644 --- a/src/core/server/http/http_config.test.ts +++ b/src/core/server/http/http_config.test.ts @@ -21,6 +21,9 @@ import { config, HttpConfig } from '.'; import { Env } from '../config'; import { getEnvOptions } from '../config/__mocks__/env'; +const validHostnames = ['www.example.com', '8.8.8.8', '::1', 'localhost']; +const invalidHostname = 'asdf$%^'; + test('has defaults for config', () => { const httpSchema = config.schema; const obj = {}; @@ -28,18 +31,16 @@ test('has defaults for config', () => { }); test('accepts valid hostnames', () => { - const { host: host1 } = config.schema.validate({ host: 'www.example.com' }); - const { host: host2 } = config.schema.validate({ host: '8.8.8.8' }); - const { host: host3 } = config.schema.validate({ host: '::1' }); - const { host: host4 } = config.schema.validate({ host: 'localhost' }); - - expect({ host1, host2, host3, host4 }).toMatchSnapshot('valid host names'); + for (const val of validHostnames) { + const { host } = config.schema.validate({ host: val }); + expect({ host }).toMatchSnapshot(); + } }); test('throws if invalid hostname', () => { const httpSchema = config.schema; const obj = { - host: 'asdf$%^', + host: invalidHostname, }; expect(() => httpSchema.validate(obj)).toThrowErrorMatchingSnapshot(); }); @@ -296,3 +297,44 @@ describe('with TLS', () => { expect(httpConfig.ssl.rejectUnauthorized).toBe(true); }); }); + +describe('with compression', () => { + test('accepts valid referrer whitelist', () => { + const { + compression: { referrerWhitelist }, + } = config.schema.validate({ + compression: { + referrerWhitelist: validHostnames, + }, + }); + + expect(referrerWhitelist).toMatchSnapshot(); + }); + + test('throws if invalid referrer whitelist', () => { + const httpSchema = config.schema; + const invalidHostnames = { + compression: { + referrerWhitelist: [invalidHostname], + }, + }; + const emptyArray = { + compression: { + referrerWhitelist: [], + }, + }; + expect(() => httpSchema.validate(invalidHostnames)).toThrowErrorMatchingSnapshot(); + expect(() => httpSchema.validate(emptyArray)).toThrowErrorMatchingSnapshot(); + }); + + test('throws if referrer whitelist is specified and compression is disabled', () => { + const httpSchema = config.schema; + const obj = { + compression: { + enabled: false, + referrerWhitelist: validHostnames, + }, + }; + expect(() => httpSchema.validate(obj)).toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index c4a61aaf83ac7..89676380610a9 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -72,12 +72,26 @@ export const config = { socketTimeout: schema.number({ defaultValue: 120000, }), + compression: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + referrerWhitelist: schema.maybe( + schema.arrayOf( + schema.string({ + hostname: true, + }), + { minSize: 1 } + ) + ), + }), }, { validate: rawConfig => { if (!rawConfig.basePath && rawConfig.rewriteBasePath) { return 'cannot use [rewriteBasePath] when [basePath] is not specified'; } + if (!rawConfig.compression.enabled && rawConfig.compression.referrerWhitelist) { + return 'cannot use [compression.referrerWhitelist] when [compression.enabled] is set to false'; + } if ( rawConfig.ssl.enabled && @@ -109,6 +123,7 @@ export class HttpConfig { public publicDir: string; public defaultRoute?: string; public ssl: SslConfig; + public compression: { enabled: boolean; referrerWhitelist?: string[] }; /** * @internal @@ -126,5 +141,6 @@ export class HttpConfig { this.publicDir = env.staticFilesDir; this.ssl = new SslConfig(rawConfig.ssl || {}); this.defaultRoute = rawConfig.defaultRoute; + this.compression = rawConfig.compression; } } diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index df47ffdc1176b..27d9f530050be 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -53,6 +53,7 @@ beforeEach(() => { maxPayload: new ByteSizeValue(1024), port: 10002, ssl: { enabled: false }, + compression: { enabled: true }, } as HttpConfig; configWithSSL = { @@ -578,6 +579,90 @@ test('exposes route details of incoming request to a route handler', async () => }); }); +describe('conditional compression', () => { + async function setupServer(innerConfig: HttpConfig) { + const { registerRouter, server: innerServer } = await server.setup(innerConfig); + const router = new Router('', logger, enhanceWithContext); + // we need the large body here so that compression would normally be used + const largeRequest = { + body: 'hello'.repeat(500), + headers: { 'Content-Type': 'text/html; charset=UTF-8' }, + }; + router.get({ path: '/', validate: false }, (_context, _req, res) => res.ok(largeRequest)); + registerRouter(router); + await server.start(); + return innerServer.listener; + } + + test('with `compression.enabled: true`', async () => { + const listener = await setupServer(config); + + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip'); + + expect(response.header).toHaveProperty('content-encoding', 'gzip'); + }); + + test('with `compression.enabled: false`', async () => { + const listener = await setupServer({ + ...config, + compression: { enabled: false }, + }); + + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip'); + + expect(response.header).not.toHaveProperty('content-encoding'); + }); + + describe('with defined `compression.referrerWhitelist`', () => { + let listener: Server; + beforeEach(async () => { + listener = await setupServer({ + ...config, + compression: { enabled: true, referrerWhitelist: ['foo'] }, + }); + }); + + test('enables compression for no referer', async () => { + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip'); + + expect(response.header).toHaveProperty('content-encoding', 'gzip'); + }); + + test('enables compression for whitelisted referer', async () => { + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip') + .set('referer', 'http://foo:1234'); + + expect(response.header).toHaveProperty('content-encoding', 'gzip'); + }); + + test('disables compression for non-whitelisted referer', async () => { + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip') + .set('referer', 'http://bar:1234'); + + expect(response.header).not.toHaveProperty('content-encoding'); + }); + + test('disables compression for invalid referer', async () => { + const response = await supertest(listener) + .get('/') + .set('accept-encoding', 'gzip') + .set('referer', 'http://asdf$%^'); + + expect(response.header).not.toHaveProperty('content-encoding'); + }); + }); +}); + test('exposes route details of incoming request to a route handler (POST + payload options)', async () => { const { registerRouter, server: innerServer } = await server.setup(config); diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index a587eed1f54ec..f77184fb79ab6 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -18,6 +18,7 @@ */ import { Request, Server } from 'hapi'; +import url from 'url'; import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; @@ -96,6 +97,7 @@ export class HttpServer { const basePathService = new BasePath(config.basePath); this.setupBasePathRewrite(config, basePathService); + this.setupConditionalCompression(config); return { registerRouter: this.registerRouter.bind(this), @@ -187,6 +189,33 @@ export class HttpServer { }); } + private setupConditionalCompression(config: HttpConfig) { + if (this.server === undefined) { + throw new Error('Server is not created yet'); + } + + const { enabled, referrerWhitelist: list } = config.compression; + if (!enabled) { + this.log.debug('HTTP compression is disabled'); + this.server.ext('onRequest', (request, h) => { + request.info.acceptEncoding = ''; + return h.continue; + }); + } else if (list) { + this.log.debug(`HTTP compression is only enabled for any referrer in the following: ${list}`); + this.server.ext('onRequest', (request, h) => { + const { referrer } = request.info; + if (referrer !== '') { + const { hostname } = url.parse(referrer); + if (!hostname || !list.includes(hostname)) { + request.info.acceptEncoding = ''; + } + } + return h.continue; + }); + } + } + private registerOnPostAuth(fn: OnPostAuthHandler) { if (this.server === undefined) { throw new Error('Server is not created yet'); diff --git a/src/core/server/http/http_tools.test.ts b/src/core/server/http/http_tools.test.ts index bed0ac8d77094..7195717d9d3fc 100644 --- a/src/core/server/http/http_tools.test.ts +++ b/src/core/server/http/http_tools.test.ts @@ -90,6 +90,7 @@ describe('timeouts', () => { host: '127.0.0.1', maxPayload: new ByteSizeValue(1024), ssl: {}, + compression: { enabled: true }, } as HttpConfig); registerRouter(router); diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts index 7c4a0097456ca..d5f9343f3e981 100644 --- a/src/core/server/http/integration_tests/lifecycle.test.ts +++ b/src/core/server/http/integration_tests/lifecycle.test.ts @@ -51,6 +51,7 @@ configService.atPath.mockReturnValue( ssl: { enabled: false, }, + compression: { enabled: true }, } as any) ); diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 481d8e1bbf49b..463f941ba84b4 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -51,6 +51,7 @@ configService.atPath.mockReturnValue( ssl: { enabled: false, }, + compression: { enabled: true }, } as any) ); diff --git a/src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap b/src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap index e59312cf8a948..172feec674677 100644 --- a/src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap +++ b/src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap @@ -4,6 +4,9 @@ exports[`#get correctly handles server config.: default 1`] = ` Object { "autoListen": true, "basePath": "/abc", + "compression": Object { + "enabled": true, + }, "cors": false, "host": "host", "keepaliveTimeout": 5000, @@ -23,6 +26,9 @@ exports[`#get correctly handles server config.: disabled ssl 1`] = ` Object { "autoListen": true, "basePath": "/abc", + "compression": Object { + "enabled": true, + }, "cors": false, "host": "host", "keepaliveTimeout": 5000, diff --git a/src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts b/src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts index 202a1e471af9b..201f761701a35 100644 --- a/src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts +++ b/src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts @@ -74,6 +74,7 @@ describe('#get', () => { port: 1234, rewriteBasePath: false, ssl: { enabled: true, keyPassphrase: 'some-phrase', someNewValue: 'new' }, + compression: { enabled: true }, someNotSupportedValue: 'val', }, }); @@ -90,6 +91,7 @@ describe('#get', () => { port: 1234, rewriteBasePath: false, ssl: { enabled: false, certificate: 'cert', key: 'key' }, + compression: { enabled: true }, someNotSupportedValue: 'val', }, }); diff --git a/src/core/server/legacy/config/legacy_object_to_config_adapter.ts b/src/core/server/legacy/config/legacy_object_to_config_adapter.ts index 0901458866fb3..6f0757dece165 100644 --- a/src/core/server/legacy/config/legacy_object_to_config_adapter.ts +++ b/src/core/server/legacy/config/legacy_object_to_config_adapter.ts @@ -70,6 +70,7 @@ export class LegacyObjectToConfigAdapter extends ObjectToConfigAdapter { ssl: configValue.ssl, keepaliveTimeout: configValue.keepaliveTimeout, socketTimeout: configValue.socketTimeout, + compression: configValue.compression, }; } diff --git a/src/legacy/core_plugins/data/public/index.scss b/src/legacy/core_plugins/data/public/index.scss index 94f02fe2d6049..78673525a5483 100644 --- a/src/legacy/core_plugins/data/public/index.scss +++ b/src/legacy/core_plugins/data/public/index.scss @@ -2,8 +2,4 @@ @import './query/query_bar/index'; -@import 'src/plugins/data/public/ui/filter_bar/index'; - -@import 'src/plugins/data/public/ui/typeahead/index'; - -@import './search/search_bar/index'; +@import '../../../../plugins/data/public/ui/index' \ No newline at end of file diff --git a/src/legacy/core_plugins/data/public/search/search_bar/_index.scss b/src/legacy/core_plugins/data/public/search/search_bar/_index.scss deleted file mode 100644 index 0c42a9426e41e..0000000000000 --- a/src/legacy/core_plugins/data/public/search/search_bar/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'components/saved_query_management/index'; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx index 0605b156a9669..b4fd3f4578544 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx @@ -38,7 +38,6 @@ const mockTimeHistory = { jest.mock('../../../../../../../plugins/data/public', () => { return { FilterBar: () =>
, - createSavedQueryService: () => {}, }; }); @@ -106,6 +105,11 @@ function wrapSearchBarInContext(testProps: any) { notifications: startMock.notifications, http: startMock.http, storage: createMockStorage(), + data: { + query: { + savedQueries: {}, + }, + }, }; return ( diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index da08165289afc..b24ea763ace75 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -26,8 +26,6 @@ import { get, isEqual } from 'lodash'; import { IndexPattern } from '../../../../../data/public'; import { QueryBarTopRow } from '../../../query'; -import { SavedQueryMeta, SaveQueryForm } from './saved_query_management/save_query_form'; -import { SavedQueryManagementComponent } from './saved_query_management/saved_query_management_component'; import { withKibana, @@ -40,10 +38,11 @@ import { esFilters, TimeHistoryContract, FilterBar, - SavedQueryService, - createSavedQueryService, SavedQuery, SavedQueryAttributes, + SavedQueryMeta, + SaveQueryForm, + SavedQueryManagementComponent, } from '../../../../../../../plugins/data/public'; interface SearchBarInjectedDeps { @@ -112,8 +111,8 @@ class SearchBarUI extends Component { showAutoRefreshOnly: false, }; - private savedQueryService!: SavedQueryService; private services = this.props.kibana.services; + private savedQueryService = this.services.data.query.savedQueries; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -368,9 +367,6 @@ class SearchBarUI extends Component { this.setFilterBarHeight(); this.ro.observe(this.filterBarRef); } - if (this.services.savedObjects) { - this.savedQueryService = createSavedQueryService(this.services.savedObjects.client); - } } public componentDidUpdate() { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html index 0b842fbfaeddc..4f41ab5d4fad6 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html @@ -12,7 +12,6 @@ show-filter-bar="showFilterBar()" show-save-query="showSaveQuery" - filters="model.filters" query="model.query" saved-query="savedQuery" screen-title="screenTitle" diff --git a/src/legacy/server/config/schema.js b/src/legacy/server/config/schema.js index 3f9b897730f51..9e06fa178c5d6 100644 --- a/src/legacy/server/config/schema.js +++ b/src/legacy/server/config/schema.js @@ -106,6 +106,7 @@ export default () => Joi.object({ maxPayloadBytes: HANDLED_IN_NEW_PLATFORM, socketTimeout: HANDLED_IN_NEW_PLATFORM, ssl: HANDLED_IN_NEW_PLATFORM, + compression: HANDLED_IN_NEW_PLATFORM, }).default(), uiSettings: HANDLED_IN_NEW_PLATFORM, diff --git a/src/plugins/data/public/index_patterns/index.ts b/src/plugins/data/public/index_patterns/index.ts index 7492f9372e44a..a22a8b8d85813 100644 --- a/src/plugins/data/public/index_patterns/index.ts +++ b/src/plugins/data/public/index_patterns/index.ts @@ -17,12 +17,12 @@ * under the License. */ -import { IndexPatternMissingIndices } from './errors'; import { ILLEGAL_CHARACTERS_KEY, CONTAINS_SPACES_KEY, ILLEGAL_CHARACTERS_VISIBLE, ILLEGAL_CHARACTERS, + IndexPatternMissingIndices, validateIndexPattern, } from './lib'; import { getRoutes, getFromSavedObject } from './utils'; diff --git a/src/plugins/data/public/index_patterns/errors.ts b/src/plugins/data/public/index_patterns/lib/errors.ts similarity index 95% rename from src/plugins/data/public/index_patterns/errors.ts rename to src/plugins/data/public/index_patterns/lib/errors.ts index 3eb43eaf460cc..12efab7a2ca40 100644 --- a/src/plugins/data/public/index_patterns/errors.ts +++ b/src/plugins/data/public/index_patterns/lib/errors.ts @@ -19,7 +19,7 @@ /* eslint-disable */ -import { KbnError } from '../../../kibana_utils/public'; +import { KbnError } from '../../../../kibana_utils/public'; /** * Tried to call a method that relies on SearchSource having an indexPattern assigned diff --git a/src/plugins/data/public/index_patterns/lib/index.ts b/src/plugins/data/public/index_patterns/lib/index.ts index 0f667e846af91..626881b721c33 100644 --- a/src/plugins/data/public/index_patterns/lib/index.ts +++ b/src/plugins/data/public/index_patterns/lib/index.ts @@ -20,3 +20,4 @@ export { getTitle } from './get_title'; export * from './types'; export { validateIndexPattern } from './validate_index_pattern'; +export { IndexPatternMissingIndices } from './errors'; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index 02aaaaf6f4689..9089105b4e3a8 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -17,9 +17,6 @@ * under the License. */ -// TODO: remove when index patterns are moved here. -jest.mock('ui/new_platform'); - import { stubIndexPattern, stubFields } from '../stubs'; import { getSuggestionsProvider } from './value_suggestions'; import { IUiSettingsClient } from 'kibana/public'; diff --git a/src/plugins/data/public/ui/_index.scss b/src/plugins/data/public/ui/_index.scss new file mode 100644 index 0000000000000..1fc673d5450c2 --- /dev/null +++ b/src/plugins/data/public/ui/_index.scss @@ -0,0 +1,6 @@ + +@import './filter_bar/index'; + +@import './typeahead/index'; + +@import './saved_query_management/index'; diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/lib/filter_editor_utils.test.ts b/src/plugins/data/public/ui/filter_bar/filter_editor/lib/filter_editor_utils.test.ts index 2cc7f16cfe261..fb3fbc10d7455 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/lib/filter_editor_utils.test.ts +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/lib/filter_editor_utils.test.ts @@ -36,8 +36,6 @@ import { import { existsOperator, isBetweenOperator, isOneOfOperator, isOperator } from './filter_operators'; -jest.mock('ui/new_platform'); - describe('Filter editor utils', () => { describe('getFieldFromFilter', () => { it('should return the field from the filter', () => { diff --git a/src/plugins/data/public/ui/index.ts b/src/plugins/data/public/ui/index.ts index 6fb8e260dd720..d549ceabde86d 100644 --- a/src/plugins/data/public/ui/index.ts +++ b/src/plugins/data/public/ui/index.ts @@ -21,5 +21,7 @@ export { SuggestionsComponent } from './typeahead/suggestions_component'; export { IndexPatternSelect } from './index_pattern_select'; export { FilterBar } from './filter_bar'; export { applyFiltersPopover } from './apply_filters'; -// temp export +// temp export - will be removed as final components are migrated to NP export { QueryLanguageSwitcher } from './query_string_input/language_switcher'; +export { SavedQueryManagementComponent } from './saved_query_management'; +export { SaveQueryForm, SavedQueryMeta } from './saved_query_form'; diff --git a/src/plugins/data/public/ui/saved_query_form/index.ts b/src/plugins/data/public/ui/saved_query_form/index.ts new file mode 100644 index 0000000000000..c52b6c92ef6d3 --- /dev/null +++ b/src/plugins/data/public/ui/saved_query_form/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { SavedQueryMeta, SaveQueryForm } from '../saved_query_form/save_query_form'; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/save_query_form.tsx b/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx similarity index 98% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/save_query_form.tsx rename to src/plugins/data/public/ui/saved_query_form/save_query_form.tsx index 4515c71baa267..f9a0ae4e803c4 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/save_query_form.tsx +++ b/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx @@ -35,11 +35,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { sortBy, isEqual } from 'lodash'; -import { - SavedQuery, - SavedQueryAttributes, - SavedQueryService, -} from '../../../../../../../../plugins/data/public'; +import { SavedQuery, SavedQueryAttributes, SavedQueryService } from '../..'; interface Props { savedQuery?: SavedQueryAttributes; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_index.scss b/src/plugins/data/public/ui/saved_query_management/_index.scss similarity index 100% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_index.scss rename to src/plugins/data/public/ui/saved_query_management/_index.scss diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_saved_query_list_item.scss b/src/plugins/data/public/ui/saved_query_management/_saved_query_list_item.scss similarity index 100% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_saved_query_list_item.scss rename to src/plugins/data/public/ui/saved_query_management/_saved_query_list_item.scss diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_saved_query_management_component.scss b/src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss similarity index 100% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/_saved_query_management_component.scss rename to src/plugins/data/public/ui/saved_query_management/_saved_query_management_component.scss diff --git a/src/plugins/data/public/ui/saved_query_management/index.ts b/src/plugins/data/public/ui/saved_query_management/index.ts new file mode 100644 index 0000000000000..be5ea0cd7c8e7 --- /dev/null +++ b/src/plugins/data/public/ui/saved_query_management/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { SavedQueryManagementComponent } from './saved_query_management_component'; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_list_item.tsx b/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx similarity index 98% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_list_item.tsx rename to src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx index bee32c347e6f4..09eeb8359dde7 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_list_item.tsx +++ b/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx @@ -22,7 +22,7 @@ import { EuiListGroupItem, EuiConfirmModal, EuiOverlayMask, EuiIconTip } from '@ import React, { Fragment, useState } from 'react'; import classNames from 'classnames'; import { i18n } from '@kbn/i18n'; -import { SavedQuery } from '../../../../../../../../plugins/data/public'; +import { SavedQuery } from '../..'; interface Props { savedQuery: SavedQuery; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_management_component.tsx b/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx similarity index 99% rename from src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_management_component.tsx rename to src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx index 65ed92c40741b..2a11531ee336d 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/saved_query_management/saved_query_management_component.tsx +++ b/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx @@ -35,7 +35,7 @@ import { import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, useEffect, useState, Fragment } from 'react'; import { sortBy } from 'lodash'; -import { SavedQuery, SavedQueryService } from '../../../../../../../../plugins/data/public'; +import { SavedQuery, SavedQueryService } from '../..'; import { SavedQueryListItem } from './saved_query_list_item'; const perPage = 50; diff --git a/test/api_integration/apis/core/index.js b/test/api_integration/apis/core/index.js index d617b2ad07351..7c4047ac1f537 100644 --- a/test/api_integration/apis/core/index.js +++ b/test/api_integration/apis/core/index.js @@ -16,21 +16,55 @@ * specific language governing permissions and limitations * under the License. */ +import expect from '@kbn/expect'; export default function ({ getService }) { const supertest = getService('supertest'); - describe('core request context', () => { - it('provides access to elasticsearch', async () => ( - await supertest - .get('/requestcontext/elasticsearch') - .expect(200, 'Elasticsearch: true') - )); + describe('core', () => { + describe('request context', () => { + it('provides access to elasticsearch', async () => ( + await supertest + .get('/requestcontext/elasticsearch') + .expect(200, 'Elasticsearch: true') + )); - it('provides access to SavedObjects client', async () => ( - await supertest - .get('/requestcontext/savedobjectsclient') - .expect(200, 'SavedObjects client: {"page":1,"per_page":20,"total":0,"saved_objects":[]}') - )); + it('provides access to SavedObjects client', async () => ( + await supertest + .get('/requestcontext/savedobjectsclient') + .expect(200, 'SavedObjects client: {"page":1,"per_page":20,"total":0,"saved_objects":[]}') + )); + }); + + describe('compression', () => { + it(`uses compression when there isn't a referer`, async () => { + await supertest + .get('/app/kibana') + .set('accept-encoding', 'gzip') + .then(response => { + expect(response.headers).to.have.property('content-encoding', 'gzip'); + }); + }); + + it(`uses compression when there is a whitelisted referer`, async () => { + await supertest + .get('/app/kibana') + .set('accept-encoding', 'gzip') + .set('referer', 'https://some-host.com') + .then(response => { + expect(response.headers).to.have.property('content-encoding', 'gzip'); + }); + }); + + it(`doesn't use compression when there is a non-whitelisted referer`, async () => { + await supertest + .get('/app/kibana') + .set('accept-encoding', 'gzip') + .set('referer', 'https://other.some-host.com') + .then(response => { + expect(response.headers).not.to.have.property('content-encoding'); + }); + }); + }); }); } diff --git a/test/api_integration/apis/index.js b/test/api_integration/apis/index.js index 9f2672959390c..de36ee678b10e 100644 --- a/test/api_integration/apis/index.js +++ b/test/api_integration/apis/index.js @@ -34,5 +34,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./status')); loadTestFile(require.resolve('./stats')); loadTestFile(require.resolve('./ui_metric')); + loadTestFile(require.resolve('./core')); }); } diff --git a/test/api_integration/config.js b/test/api_integration/config.js index d14630f932bf6..bd385b1ac8b96 100644 --- a/test/api_integration/config.js +++ b/test/api_integration/config.js @@ -40,6 +40,7 @@ export default async function ({ readConfigFile }) { '--optimize.enabled=false', '--elasticsearch.healthCheck.delay=3600000', '--server.xsrf.disableProtection=true', + '--server.compression.referrerWhitelist=["some-host.com"]', ], }, }; diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index 90df352e18a00..0058f21f2356b 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -11,6 +11,10 @@ def withWorkers(name, preWorkerClosure = {}, workerClosures = [:]) { nextWorker++ return { + // This delay helps smooth out CPU load caused by ES/Kibana instances starting up at the same time + def delay = (workerNumber-1)*20 + sleep(delay) + workerClosure(workerNumber) } } diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index 1784ed22a2b4d..b79e2801a0898 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -31,7 +31,7 @@ export const apm: LegacyPluginInitializer = kibana => { order: 8100 }, styleSheetPaths: resolve(__dirname, 'public/index.scss'), - home: ['plugins/apm/register_feature'], + home: ['plugins/apm/legacy_register_feature'], // TODO: get proper types injectDefaultVars(server: Server) { diff --git a/x-pack/legacy/plugins/apm/public/legacy_register_feature.js b/x-pack/legacy/plugins/apm/public/legacy_register_feature.js new file mode 100644 index 0000000000000..6e98d0784bee1 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/legacy_register_feature.js @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { npStart } from 'ui/new_platform'; +import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue'; +import { featureCatalogueEntry } from './new-platform/featureCatalogueEntry'; + +const { core } = npStart; +const apmUiEnabled = core.injectedMetadata.getInjectedVar('apmUiEnabled'); + +if (apmUiEnabled) { + FeatureCatalogueRegistryProvider.register(() => featureCatalogueEntry); +} diff --git a/x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts b/x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts new file mode 100644 index 0000000000000..7a150de6d5d02 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { FeatureCatalogueCategory } from '../../../../../../src/plugins/home/public'; + +export const featureCatalogueEntry = { + id: 'apm', + title: 'APM', + description: i18n.translate('xpack.apm.apmDescription', { + defaultMessage: + 'Automatically collect in-depth performance metrics and ' + + 'errors from inside your applications.' + }), + icon: 'apmApp', + path: '/app/apm', + showOnHomePage: true, + category: FeatureCatalogueCategory.DATA +}; diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index b5986610d3048..ac87671492b76 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -8,6 +8,7 @@ import React, { useContext, createContext } from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; +import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public'; import { CoreStart, LegacyCoreStart, @@ -29,6 +30,7 @@ import { MatchedRouteProvider } from '../context/MatchedRouteContext'; import { createStaticIndexPattern } from '../services/rest/index_pattern'; import { setHelpExtension } from './setHelpExtension'; import { setReadonlyBadge } from './updateBadge'; +import { featureCatalogueEntry } from './featureCatalogueEntry'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -53,7 +55,10 @@ const App = () => { export type ApmPluginSetup = void; export type ApmPluginStart = void; -export type ApmPluginSetupDeps = {}; // eslint-disable-line @typescript-eslint/consistent-type-definitions + +export interface ApmPluginSetupDeps { + home: HomePublicPluginSetup; +} export interface ApmPluginStartDeps { data: DataPublicPluginStart; @@ -74,11 +79,12 @@ export class ApmPlugin ApmPluginStartDeps > { // Take the DOM element as the constructor, so we can mount the app. - public setup(_core: CoreSetup, _plugins: ApmPluginSetupDeps) {} + public setup(_core: CoreSetup, plugins: ApmPluginSetupDeps) { + plugins.home.featureCatalogue.register(featureCatalogueEntry); + } public start(core: CoreStart, plugins: ApmPluginStartDeps) { const i18nCore = core.i18n; - // render APM feedback link in global help menu setHelpExtension(core); setReadonlyBadge(core); diff --git a/x-pack/legacy/plugins/apm/public/register_feature.js b/x-pack/legacy/plugins/apm/public/register_feature.js deleted file mode 100644 index 8994fac17e914..0000000000000 --- a/x-pack/legacy/plugins/apm/public/register_feature.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npStart } from 'ui/new_platform'; -import { i18n } from '@kbn/i18n'; -import { - FeatureCatalogueRegistryProvider, - FeatureCatalogueCategory -} from 'ui/registry/feature_catalogue'; - -const { core } = npStart; -const apmUiEnabled = core.injectedMetadata.getInjectedVar('apmUiEnabled'); - -if (apmUiEnabled) { - FeatureCatalogueRegistryProvider.register(() => { - return { - id: 'apm', - title: 'APM', - description: i18n.translate('xpack.apm.apmDescription', { - defaultMessage: - 'Automatically collect in-depth performance metrics and ' + - 'errors from inside your applications.' - }), - icon: 'apmApp', - path: '/app/apm', - showOnHomePage: true, - category: FeatureCatalogueCategory.DATA - }; - }); -} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 24d9c45510aef..57a43f924b7e6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -241,10 +241,17 @@ export class ESSearchSource extends AbstractESSource { const searchSource = await this._makeSearchSource(searchFilters, 0); searchSource.setField('aggs', { + totalEntities: { + cardinality: { + field: topHitsSplitField, + precision_threshold: 1, + } + }, entitySplit: { terms: { field: topHitsSplitField, - size: ES_SIZE_LIMIT + size: ES_SIZE_LIMIT, + shard_size: ES_SIZE_LIMIT, }, aggs: { entityHits: { @@ -256,24 +263,29 @@ export class ESSearchSource extends AbstractESSource { const resp = await this._runEsQuery(layerName, searchSource, registerCancelCallback, 'Elasticsearch document top hits request'); - let hasTrimmedResults = false; const allHits = []; const entityBuckets = _.get(resp, 'aggregations.entitySplit.buckets', []); + const totalEntities = _.get(resp, 'aggregations.totalEntities.value', 0); + // can not compare entityBuckets.length to totalEntities because totalEntities is an approximate + const areEntitiesTrimmed = entityBuckets.length >= ES_SIZE_LIMIT; + let areTopHitsTrimmed = false; entityBuckets.forEach(entityBucket => { const total = _.get(entityBucket, 'entityHits.hits.total', 0); const hits = _.get(entityBucket, 'entityHits.hits.hits', []); // Reverse hits list so top documents by sort are drawn on top allHits.push(...hits.reverse()); if (total > hits.length) { - hasTrimmedResults = true; + areTopHitsTrimmed = true; } }); return { hits: allHits, meta: { - areResultsTrimmed: hasTrimmedResults, + areResultsTrimmed: areEntitiesTrimmed || areTopHitsTrimmed, // used to force re-fetch when zooming in + areEntitiesTrimmed, entityCount: entityBuckets.length, + totalEntities, } }; } @@ -459,24 +471,28 @@ export class ESSearchSource extends AbstractESSource { } if (this._isTopHits()) { - const entitiesFoundMsg = i18n.translate('xpack.maps.esSearch.topHitsEntitiesCountMsg', { - defaultMessage: `Found {entityCount} entities.`, - values: { entityCount: meta.entityCount } - }); - if (meta.areResultsTrimmed) { - const trimmedMsg = i18n.translate('xpack.maps.esSearch.topHitsResultsTrimmedMsg', { - defaultMessage: `Results limited to most recent {topHitsSize} documents per entity.`, - values: { topHitsSize: this._descriptor.topHitsSize } + const entitiesFoundMsg = meta.areEntitiesTrimmed + ? i18n.translate('xpack.maps.esSearch.topHitsResultsTrimmedMsg', { + defaultMessage: `Results limited to first {entityCount} entities of ~{totalEntities}.`, + values: { + entityCount: meta.entityCount, + totalEntities: meta.totalEntities, + } + }) + : i18n.translate('xpack.maps.esSearch.topHitsEntitiesCountMsg', { + defaultMessage: `Found {entityCount} entities.`, + values: { entityCount: meta.entityCount } }); - return { - tooltipContent: `${entitiesFoundMsg} ${trimmedMsg}`, - areResultsTrimmed: false - }; - } + const docsPerEntityMsg = i18n.translate('xpack.maps.esSearch.topHitsSizeMsg', { + defaultMessage: `Showing top {topHitsSize} documents per entity.`, + values: { topHitsSize: this._descriptor.topHitsSize } + }); return { - tooltipContent: entitiesFoundMsg, - areResultsTrimmed: false + tooltipContent: `${entitiesFoundMsg} ${docsPerEntityMsg}`, + // Used to show trimmed icon in legend + // user only needs to be notified of trimmed results when entities are trimmed + areResultsTrimmed: meta.areEntitiesTrimmed }; } diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/_index.scss b/x-pack/legacy/plugins/maps/public/layers/styles/_index.scss index bd517f81517c2..9060a4a98a4bc 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/_index.scss +++ b/x-pack/legacy/plugins/maps/public/layers/styles/_index.scss @@ -1,3 +1,3 @@ @import './components/color_gradient'; -@import './components/static_dynamic_style_row'; +@import './vector/components/static_dynamic_style_row'; @import './vector/components/color/color_stops'; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/components/_static_dynamic_style_row.scss b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/_static_dynamic_style_row.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/layers/styles/components/_static_dynamic_style_row.scss rename to x-pack/legacy/plugins/maps/public/layers/styles/vector/components/_static_dynamic_style_row.scss diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/vector_style_color_editor.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/vector_style_color_editor.js index a39db57dc4883..c38c2054860ad 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/vector_style_color_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/vector_style_color_editor.js @@ -6,7 +6,7 @@ import React from 'react'; -import { StaticDynamicStyleRow } from '../../../components/static_dynamic_style_row'; +import { StaticDynamicStyleRow } from '../static_dynamic_style_row'; import { DynamicColorSelection } from './dynamic_color_selection'; import { StaticColorSelection } from './static_color_selection'; import { getVectorStyleLabel } from '../get_vector_style_label'; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/orientation/orientation_editor.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/orientation/orientation_editor.js index 65efddae90933..4c06739ced065 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/orientation/orientation_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/orientation/orientation_editor.js @@ -6,7 +6,7 @@ import React from 'react'; -import { StaticDynamicStyleRow } from '../../../components/static_dynamic_style_row'; +import { StaticDynamicStyleRow } from '../static_dynamic_style_row'; import { DynamicOrientationSelection } from './dynamic_orientation_selection'; import { StaticOrientationSelection } from './static_orientation_selection'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/size/vector_style_size_editor.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/size/vector_style_size_editor.js index ffaaace680a43..187ca17f95b49 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/size/vector_style_size_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/size/vector_style_size_editor.js @@ -6,7 +6,7 @@ import React from 'react'; -import { StaticDynamicStyleRow } from '../../../components/static_dynamic_style_row'; +import { StaticDynamicStyleRow } from '../static_dynamic_style_row'; import { DynamicSizeSelection } from './dynamic_size_selection'; import { StaticSizeSelection } from './static_size_selection'; import { getVectorStyleLabel } from '../get_vector_style_label'; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/components/static_dynamic_style_row.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/static_dynamic_style_row.js similarity index 98% rename from x-pack/legacy/plugins/maps/public/layers/styles/components/static_dynamic_style_row.js rename to x-pack/legacy/plugins/maps/public/layers/styles/vector/components/static_dynamic_style_row.js index 5537bb90fa245..cfe7a0741a194 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/components/static_dynamic_style_row.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/static_dynamic_style_row.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { VectorStyle } from '../vector/vector_style'; +import { VectorStyle } from '../vector_style'; import _ from 'lodash'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/__mocks__/results/farequote_job_caps.json b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/__mocks__/results/farequote_job_caps.json index c005d9a5b5aaa..9c10f9083be5e 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/__mocks__/results/farequote_job_caps.json +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/__mocks__/results/farequote_job_caps.json @@ -397,6 +397,7 @@ "min": "min" }, "fieldIds": [ + "airline", "responsetime" ] }, @@ -411,6 +412,7 @@ "min": "min" }, "fieldIds": [ + "airline", "responsetime" ] }, @@ -425,6 +427,7 @@ "min": "min" }, "fieldIds": [ + "airline", "responsetime" ] }, @@ -479,7 +482,10 @@ "aggIds": [ "distinct_count", "high_distinct_count", - "low_distinct_count" + "low_distinct_count", + "info_content", + "high_info_content", + "low_info_content" ] }, { diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/field_service.ts b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/field_service.ts index d53d5344adb64..af4d869274d73 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/field_service.ts +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/field_service.ts @@ -135,6 +135,7 @@ async function combineFieldsAndAggs( rollupFields: RollupFields ): Promise { const keywordFields = getKeywordFields(fields); + const textFields = getTextFields(fields); const numericalFields = getNumericalFields(fields); const ipFields = getIpFields(fields); const geoFields = getGeoFields(fields); @@ -148,6 +149,10 @@ async function combineFieldsAndAggs( case ML_JOB_AGGREGATION.LAT_LONG: geoFields.forEach(f => mix(f, a)); break; + case ML_JOB_AGGREGATION.INFO_CONTENT: + case ML_JOB_AGGREGATION.HIGH_INFO_CONTENT: + case ML_JOB_AGGREGATION.LOW_INFO_CONTENT: + textFields.forEach(f => mix(f, a)); case ML_JOB_AGGREGATION.DISTINCT_COUNT: case ML_JOB_AGGREGATION.HIGH_DISTINCT_COUNT: case ML_JOB_AGGREGATION.LOW_DISTINCT_COUNT: @@ -220,6 +225,10 @@ function getKeywordFields(fields: Field[]): Field[] { return fields.filter(f => f.type === ES_FIELD_TYPES.KEYWORD); } +function getTextFields(fields: Field[]): Field[] { + return fields.filter(f => f.type === ES_FIELD_TYPES.TEXT); +} + function getIpFields(fields: Field[]): Field[] { return fields.filter(f => f.type === ES_FIELD_TYPES.IP); } diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/hosts/selectors.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/hosts/selectors.ts index 1c900944752c4..ab2502676d6f7 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/hosts/selectors.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/hosts/selectors.ts @@ -16,6 +16,6 @@ export const ALL_HOSTS_WIDGET_DRAGGABLE_HOSTS = `${ALL_HOSTS_WIDGET} ${ALL_HOSTS /** Clicking this button displays the `Events` tab */ export const EVENTS_TAB_BUTTON = '[data-test-subj="navigation-events"]'; -export const NAVIGATION_HOSTS_ALL_HOSTS = '[data-test-subj="navigation-link-allHosts"]'; +export const NAVIGATION_HOSTS_ALL_HOSTS = '[data-test-subj="navigation-allHosts"]'; -export const NAVIGATION_HOSTS_ANOMALIES = '[data-test-subj="navigation-link-anomalies"]'; +export const NAVIGATION_HOSTS_ANOMALIES = '[data-test-subj="navigation-anomalies"]'; diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/url_state/url_state.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/url_state/url_state.spec.ts index b1867a437f7f4..21829a0c20228 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/url_state/url_state.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/url_state/url_state.spec.ts @@ -181,7 +181,7 @@ describe('url state', () => { cy.url().should('include', `query=(language:kuery,query:'source.ip:%20%2210.142.0.9%22%20')`); }); - it.skip('sets the url state when kql is set and check if href reflect this change', () => { + it('sets the url state when kql is set and check if href reflect this change', () => { loginAndWaitForPage(ABSOLUTE_DATE_RANGE.url); cy.get(KQL_INPUT, { timeout: 5000 }).type('source.ip: "10.142.0.9" {enter}'); cy.get(NAVIGATION_HOSTS) @@ -194,7 +194,7 @@ describe('url state', () => { ); }); - it.skip('sets KQL in host page and detail page and check if href match on breadcrumb, tabs and subTabs', () => { + it('sets KQL in host page and detail page and check if href match on breadcrumb, tabs and subTabs', () => { loginAndWaitForPage(ABSOLUTE_DATE_RANGE.urlHost); cy.get(KQL_INPUT, { timeout: 5000 }).type('host.name: "siem-kibana" {enter}'); cy.get(NAVIGATION_HOSTS_ALL_HOSTS, { timeout: 5000 }) diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx index 97cf9522f488f..fbeb1a2090cfd 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx @@ -11,50 +11,52 @@ import { CONSTANTS } from '../url_state/constants'; import { SiemNavigationComponent } from './'; import { setBreadcrumbs } from './breadcrumbs'; import { navTabs } from '../../pages/home/home_navigations'; -import { TabNavigationProps } from './tab_navigation/types'; import { HostsTableType } from '../../store/hosts/model'; import { RouteSpyState } from '../../utils/route/types'; +import { SiemNavigationProps, SiemNavigationComponentProps } from './types'; jest.mock('./breadcrumbs', () => ({ setBreadcrumbs: jest.fn(), })); describe('SIEM Navigation', () => { - const mockProps: TabNavigationProps & RouteSpyState = { + const mockProps: SiemNavigationComponentProps & SiemNavigationProps & RouteSpyState = { pageName: 'hosts', pathName: '/hosts', detailName: undefined, search: '', tabName: HostsTableType.authentications, navTabs, - [CONSTANTS.timerange]: { - global: { - [CONSTANTS.timerange]: { - from: 1558048243696, - fromStr: 'now-24h', - kind: 'relative', - to: 1558134643697, - toStr: 'now', - }, - linkTo: ['timeline'], + urlState: { + [CONSTANTS.timerange]: { + global: { + [CONSTANTS.timerange]: { + from: 1558048243696, + fromStr: 'now-24h', + kind: 'relative', + to: 1558134643697, + toStr: 'now', + }, + linkTo: ['timeline'], + }, + timeline: { + [CONSTANTS.timerange]: { + from: 1558048243696, + fromStr: 'now-24h', + kind: 'relative', + to: 1558134643697, + toStr: 'now', + }, + linkTo: ['global'], + }, }, - timeline: { - [CONSTANTS.timerange]: { - from: 1558048243696, - fromStr: 'now-24h', - kind: 'relative', - to: 1558134643697, - toStr: 'now', - }, - linkTo: ['global'], + [CONSTANTS.appQuery]: { query: '', language: 'kuery' }, + [CONSTANTS.filters]: [], + [CONSTANTS.timeline]: { + id: '', + isOpen: false, }, }, - [CONSTANTS.appQuery]: { query: '', language: 'kuery' }, - [CONSTANTS.filters]: [], - [CONSTANTS.timeline]: { - id: '', - isOpen: false, - }, }; const wrapper = mount(); test('it calls setBreadcrumbs with correct path on mount', () => { diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx index 7209be4d715f3..748187a01fc8e 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx @@ -14,54 +14,42 @@ import { useRouteSpy } from '../../utils/route/use_route_spy'; import { makeMapStateToProps } from '../url_state/helpers'; import { setBreadcrumbs } from './breadcrumbs'; import { TabNavigation } from './tab_navigation'; -import { TabNavigationProps } from './tab_navigation/types'; -import { SiemNavigationComponentProps } from './types'; +import { SiemNavigationProps, SiemNavigationComponentProps } from './types'; -export const SiemNavigationComponent = React.memo( - ({ - query, - detailName, - display, - filters, - navTabs, - pageName, - pathName, - savedQuery, - search, - tabName, - timeline, - timerange, - }) => { +export const SiemNavigationComponent = React.memo< + SiemNavigationComponentProps & SiemNavigationProps & RouteSpyState +>( + ({ detailName, display, navTabs, pageName, pathName, search, tabName, urlState }) => { useEffect(() => { if (pathName) { setBreadcrumbs({ - query, + query: urlState.query, detailName, - filters, + filters: urlState.filters, navTabs, pageName, pathName, - savedQuery, + savedQuery: urlState.savedQuery, search, tabName, - timerange, - timeline, + timerange: urlState.timerange, + timeline: urlState.timeline, }); } - }, [query, pathName, search, filters, navTabs, savedQuery, timerange, timeline]); + }, [pathName, search, navTabs, urlState]); return ( ); }, @@ -69,12 +57,8 @@ export const SiemNavigationComponent = React.memo + React.ComponentClass >(connect(makeMapStateToProps))(SiemNavigationComponent); -export const SiemNavigation = React.memo(props => { +export const SiemNavigation = React.memo(props => { const [routeProps] = useRouteSpy(); - const stateNavReduxProps: RouteSpyState & SiemNavigationComponentProps = { + const stateNavReduxProps: RouteSpyState & SiemNavigationProps = { ...routeProps, ...props, }; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts index 856651e6f97dc..1283691e65806 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts @@ -10,9 +10,9 @@ import { Timeline } from '../../url_state/types'; import { HostsTableType } from '../../../store/hosts/model'; import { esFilters, Query } from '../../../../../../../../src/plugins/data/public'; -import { SiemNavigationComponentProps } from '../types'; +import { SiemNavigationProps } from '../types'; -export interface TabNavigationProps extends SiemNavigationComponentProps { +export interface TabNavigationProps extends SiemNavigationProps { pathName: string; pageName: string; tabName: HostsTableType | undefined; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/types.ts b/x-pack/legacy/plugins/siem/public/components/navigation/types.ts index a8e16c82fbf80..845642256be8a 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/types.ts @@ -4,13 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UrlStateType } from '../url_state/constants'; +import { esFilters, Query } from '../../../../../../../src/plugins/data/public'; +import { HostsTableType } from '../../store/hosts/model'; +import { UrlInputsModel } from '../../store/inputs/model'; +import { CONSTANTS, UrlStateType } from '../url_state/constants'; +import { Timeline } from '../url_state/types'; -export interface SiemNavigationComponentProps { +export interface SiemNavigationProps { display?: 'default' | 'condensed'; navTabs: Record; } +export interface SiemNavigationComponentProps { + pathName: string; + pageName: string; + tabName: HostsTableType | undefined; + urlState: { + [CONSTANTS.appQuery]?: Query; + [CONSTANTS.filters]?: esFilters.Filter[]; + [CONSTANTS.savedQuery]?: string; + [CONSTANTS.timerange]: UrlInputsModel; + [CONSTANTS.timeline]: Timeline; + }; +} + export type SearchNavTab = NavTab | { urlKey: UrlStateType; isDetailPage: boolean }; export interface NavTab { diff --git a/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx b/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx index d4a7bb1f425d4..e573afaafc2d2 100644 --- a/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx +++ b/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx @@ -58,6 +58,11 @@ const services = { storage: { get: () => {}, }, + data: { + query: { + savedQueries: {}, + }, + }, }; const localStorageMock = () => { diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json index 8161f6ee06bf8..40fee07742cf6 100644 --- a/x-pack/plugins/apm/kibana.json +++ b/x-pack/plugins/apm/kibana.json @@ -3,12 +3,7 @@ "server": true, "version": "8.0.0", "kibanaVersion": "kibana", - "configPath": [ - "xpack", - "apm" - ], + "configPath": ["xpack", "apm"], "ui": false, - "requiredPlugins": [ - "apm_oss" - ] + "requiredPlugins": ["apm_oss", "data", "home"] } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index dc1be496d2877..3b7f3ded77290 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6406,7 +6406,6 @@ "xpack.maps.esSearch.featureCountMsg": "{count} 件のドキュメントが見つかりました。", "xpack.maps.esSearch.resultsTrimmedMsg": "結果は初めの {count} 件のドキュメントに制限されています。", "xpack.maps.esSearch.topHitsEntitiesCountMsg": "{entityCount} 件のエントリーを発見.", - "xpack.maps.esSearch.topHitsResultsTrimmedMsg": "結果は各エンティティにつき最も最近の {topHitsSize} 件のドキュメントに制限されています。", "xpack.maps.feature.appDescription": "Elasticsearch と Elastic Maps Service の地理空間データを閲覧します", "xpack.maps.featureRegistry.mapsFeatureName": "Maps", "xpack.maps.geoGrid.resolutionLabel": "グリッド解像度", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f4db392b494d2..017aa7d91d74b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6408,7 +6408,6 @@ "xpack.maps.esSearch.featureCountMsg": "找到 {count} 个文档。", "xpack.maps.esSearch.resultsTrimmedMsg": "结果仅限于前 {count} 个文档。", "xpack.maps.esSearch.topHitsEntitiesCountMsg": "找到 {entityCount} 个实体。", - "xpack.maps.esSearch.topHitsResultsTrimmedMsg": "结果仅限于每个实体的最近 {topHitsSize} 个文档。", "xpack.maps.feature.appDescription": "从 Elasticsearch 和 Elastic 地图服务浏览地理空间数据", "xpack.maps.featureRegistry.mapsFeatureName": "Maps", "xpack.maps.geoGrid.resolutionLabel": "网格分辨率", diff --git a/x-pack/test/functional/apps/snapshot_restore/index.ts b/x-pack/test/functional/apps/snapshot_restore/index.ts index f589555fe876d..f9bfafed37529 100644 --- a/x-pack/test/functional/apps/snapshot_restore/index.ts +++ b/x-pack/test/functional/apps/snapshot_restore/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext) => { describe('Snapshots app', function() { - this.tags('ciGroup1'); + this.tags(['ciGroup4', 'skipCloud']); loadTestFile(require.resolve('./home_page')); }); };