diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0e0099ff672fc..62abf281e659f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,7 +26,7 @@ /src/plugins/vis_type_vislib/ @elastic/kibana-app /src/plugins/vis_type_xy/ @elastic/kibana-app /src/plugins/visualize/ @elastic/kibana-app -/src/plugins/visualizations/ @elastic/kibana-application +/src/plugins/visualizations/ @elastic/kibana-app # Application Services /examples/bfetch_explorer/ @elastic/kibana-app-arch @@ -123,8 +123,8 @@ # ML team owns and maintains the transform plugin despite it living in the Elasticsearch management section. /x-pack/plugins/transform/ @elastic/ml-ui /x-pack/test/functional/apps/transform/ @elastic/ml-ui -/x-pack/test/functional/services/transform/ @elastic/ml-ui/ -x-pack/test/api_integration_basic/apis/ml/ @elastic/ml-ui +/x-pack/test/functional/services/transform/ @elastic/ml-ui +/x-pack/test/api_integration_basic/apis/ml/ @elastic/ml-ui /x-pack/test/functional_basic/apps/ml/ @elastic/ml-ui /x-pack/test/api_integration_basic/apis/transform/ @elastic/ml-ui @@ -261,6 +261,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib # Elasticsearch UI /src/plugins/dev_tools/ @elastic/es-ui /src/plugins/console/ @elastic/es-ui +/src/plugins/es_ui_shared/ @elastic/es-ui /x-pack/plugins/cross_cluster_replication/ @elastic/es-ui /x-pack/plugins/index_lifecycle_management/ @elastic/es-ui /x-pack/plugins/console_extensions/ @elastic/es-ui diff --git a/docs/maps/import-geospatial-data.asciidoc b/docs/maps/import-geospatial-data.asciidoc index ff0c9bf1f72ba..fb4250368086e 100644 --- a/docs/maps/import-geospatial-data.asciidoc +++ b/docs/maps/import-geospatial-data.asciidoc @@ -26,7 +26,7 @@ Choose an import tool based on the format of your geospatial data. *Upload GeoJSON* indexes GeoJSON features as a geo_point or geo_shape. -. <>. +. <>. . Click *Add layer*. . Select *Upload GeoJSON*. . Use the file chooser to select a GeoJSON file. diff --git a/docs/settings/ssl-settings.asciidoc b/docs/settings/ssl-settings.asciidoc deleted file mode 100644 index 3a0a474d9d597..0000000000000 --- a/docs/settings/ssl-settings.asciidoc +++ /dev/null @@ -1,99 +0,0 @@ -[float] -=== {component} TLS/SSL settings -You can configure the following TLS/SSL settings. If the settings are not -configured, the default values are used. See -{ref}/security-settings.html[Default TLS/SSL Settings]. - -ifdef::server[] -+{ssl-prefix}.ssl.enabled+:: -Used to enable or disable TLS/SSL. The default is `false`. -endif::server[] - -+{ssl-prefix}.ssl.supported_protocols+:: -Supported protocols with versions. Valid protocols: `SSLv2Hello`, -`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`. Defaults to `TLSv1.2`, `TLSv1.1`, -`TLSv1`. Defaults to the value of `xpack.ssl.supported_protocols`. - -ifdef::server[] -+{ssl-prefix}.ssl.client_authentication+:: -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. -ifndef::client-auth-default[] -Defaults to the value of `xpack.ssl.client_authentication`. -endif::client-auth-default[] -ifdef::client-auth-default[] -Defaults to +{client-auth-default}+. -endif::client-auth-default[] -endif::server[] - -ifdef::verifies[] -+{ssl-prefix}.ssl.verification_mode+:: -Controls the verification of certificates. Valid values are `none`, -`certificate`, and `full`. Defaults to the value of `xpack.ssl.verification_mode`. -endif::verifies[] - -+{ssl-prefix}.ssl.cipher_suites+:: -Supported cipher suites can be found in Oracle's http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html[ -Java Cryptography Architecture documentation]. Defaults to the value of -`xpack.ssl.cipher_suites`. - -[float] -==== {component} TLS/SSL key and trusted certificate settings - -The following settings are used to specify a private key, certificate, and the -trusted certificates that should be used when communicating over an SSL/TLS connection. -If none of the settings are specified, the default values are used. -See {ref}/security-settings.html[Default TLS/SSL settings]. - -ifdef::server[] -A private key and certificate must be configured. -endif::server[] -ifndef::server[] -A private key and certificate are optional and would be used if the server requires client authentication for PKI -authentication. -endif::server[] -If none of the settings bare specified, the defaults values are used. -See {ref}/security-settings.html[Default TLS/SSL settings]. - -[float] -===== PEM encoded files - -When using PEM encoded files, use the following settings: - -+{ssl-prefix}.ssl.key+:: -Path to a PEM encoded file containing the private key. - -+{ssl-prefix}.ssl.key_passphrase+:: -The passphrase that will be used to decrypt the private key. This value is -optional as the key may not be encrypted. - -+{ssl-prefix}.ssl.certificate+:: -Path to a PEM encoded file containing the certificate (or certificate chain) -that will be presented when requested. - -+{ssl-prefix}.ssl.certificate_authorities+:: -List of paths to the PEM encoded certificate files that should be trusted. - -[float] -===== Java keystore files - -When using Java keystore files (JKS), which contain the private key, certificate -and certificates that should be trusted, use the following settings: - -+{ssl-prefix}.ssl.keystore.path+:: -Path to the keystore that holds the private key and certificate. - -+{ssl-prefix}.ssl.keystore.password+:: -Password to the keystore. - -+{ssl-prefix}.ssl.keystore.key_password+:: -Password for the private key in the keystore. Defaults to the -same value as +{ssl-prefix}.ssl.keystore.password+. - -+{ssl-prefix}.ssl.truststore.path+:: -Path to the truststore file. - -+{ssl-prefix}.ssl.truststore.password+:: -Password to the truststore. diff --git a/docs/user/dashboard/url-drilldown.asciidoc b/docs/user/dashboard/url-drilldown.asciidoc index 872d83bfd9009..cf92016e23f19 100644 --- a/docs/user/dashboard/url-drilldown.asciidoc +++ b/docs/user/dashboard/url-drilldown.asciidoc @@ -3,7 +3,7 @@ beta[] -The URL template input uses https://handlebarsjs.com/guide/expressions.html#expressions[Handlebars] — a simple templating language. Handlebars templates look like regular text with embedded Handlebars expressions. +The URL template input uses https://ela.st/handlebars-docs#expressions[Handlebars] — a simple templating language. Handlebars templates look like regular text with embedded Handlebars expressions. [source, bash] ---- @@ -13,7 +13,7 @@ https://github.com/elastic/kibana/issues?q={{event.value}} A Handlebars expression is a `{{`, some contents, followed by a `}}`. When the drilldown is executed, these expressions are replaced by values from the dashboard and interaction context. [[helpers]] -In addition to https://handlebarsjs.com/guide/builtin-helpers.html[built-in] Handlebars helpers, you can use custom helpers. +In addition to https://ela.st/handlebars-helpers[built-in] Handlebars helpers, you can use custom helpers. Refer to Handlebars https://ela.st/handlebars-docs#expressions[documentation] to learn about advanced use cases. diff --git a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts index 6ee2d3bfe59b0..cf3f8f25476cb 100644 --- a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts +++ b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts @@ -102,6 +102,7 @@ export class KbnClientUiSettings { body: { changes: updates, }, + retries: 3, }); } diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index cf734f33cc3e4..b01dd205440a9 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -131,7 +131,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "category": Object { "euiIconType": "logoKibana", "id": "kibana", - "label": "Kibana", + "label": "Analytics", "order": 1000, }, "data-test-subj": "discover", @@ -187,7 +187,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "category": Object { "euiIconType": "logoKibana", "id": "kibana", - "label": "Kibana", + "label": "Analytics", "order": 1000, }, "data-test-subj": "visualize", @@ -201,7 +201,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "category": Object { "euiIconType": "logoKibana", "id": "kibana", - "label": "Kibana", + "label": "Analytics", "order": 1000, }, "data-test-subj": "dashboard", @@ -859,7 +859,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` isCollapsible={true} key="kibana" onToggle={[Function]} - title="Kibana" + title="Analytics" > - Kibana + Analytics @@ -971,7 +971,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` className="euiTitle euiTitle--xxsmall euiCollapsibleNavGroup__title" id="mockId__title" > - Kibana + Analytics @@ -996,7 +996,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` className="euiCollapsibleNavGroup__children" >
    - {lastCrumb.text} - - + +
    {lastCrumb.text}
    + +
    ); } - return ; } diff --git a/src/core/utils/default_app_categories.ts b/src/core/utils/default_app_categories.ts index 809aaddb74172..d31ed8a8eb307 100644 --- a/src/core/utils/default_app_categories.ts +++ b/src/core/utils/default_app_categories.ts @@ -25,7 +25,7 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze kibana: { id: 'kibana', label: i18n.translate('core.ui.kibanaNavList.label', { - defaultMessage: 'Kibana', + defaultMessage: 'Analytics', }), euiIconType: 'logoKibana', order: 1000, diff --git a/src/dev/typescript/run_check_ts_projects_cli.ts b/src/dev/typescript/run_check_ts_projects_cli.ts index a095bef047711..1d332badcd8ae 100644 --- a/src/dev/typescript/run_check_ts_projects_cli.ts +++ b/src/dev/typescript/run_check_ts_projects_cli.ts @@ -17,7 +17,7 @@ * under the License. */ -import { resolve } from 'path'; +import { resolve, relative } from 'path'; import execa from 'execa'; @@ -35,7 +35,7 @@ export async function runCheckTsProjectsCli() { }); const isNotInTsProject: File[] = []; - const isInMultipleTsProjects: File[] = []; + const isInMultipleTsProjects: string[] = []; for (const lineRaw of files.split('\n')) { const line = lineRaw.trim(); @@ -56,7 +56,11 @@ export async function runCheckTsProjectsCli() { isNotInTsProject.push(file); } if (projects.length > 1 && !file.isTypescriptAmbient()) { - isInMultipleTsProjects.push(file); + isInMultipleTsProjects.push( + ` - ${file.getRelativePath()}:\n${projects + .map((p) => ` - ${relative(process.cwd(), p.tsConfigPath)}`) + .join('\n')}` + ); } } @@ -74,10 +78,9 @@ export async function runCheckTsProjectsCli() { } if (isInMultipleTsProjects.length) { + const details = isInMultipleTsProjects.join('\n'); log.error( - `The following files belong to multiple tsconfig.json files listed in src/dev/typescript/projects.ts\n${isInMultipleTsProjects - .map((file) => ` - ${file.getRelativePath()}`) - .join('\n')}` + `The following files belong to multiple tsconfig.json files listed in src/dev/typescript/projects.ts\n${details}` ); } diff --git a/test/functional/apps/discover/_doc_navigation.js b/test/functional/apps/discover/_doc_navigation.js index 31aef96918ffa..59c4371b95d80 100644 --- a/test/functional/apps/discover/_doc_navigation.js +++ b/test/functional/apps/discover/_doc_navigation.js @@ -20,7 +20,6 @@ import expect from '@kbn/expect'; export default function ({ getService, getPageObjects }) { - const log = getService('log'); const docTable = getService('docTable'); const filterBar = getService('filterBar'); const testSubjects = getService('testSubjects'); @@ -28,15 +27,12 @@ export default function ({ getService, getPageObjects }) { const esArchiver = getService('esArchiver'); const retry = getService('retry'); - // FLAKY: https://github.com/elastic/kibana/issues/78373 - describe.skip('doc link in discover', function contextSize() { + describe('doc link in discover', function contextSize() { beforeEach(async function () { - log.debug('load kibana index with default index pattern'); - await esArchiver.loadIfNeeded('discover'); - await esArchiver.loadIfNeeded('logstash_functional'); + await esArchiver.loadIfNeeded('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.discover.waitForDocTableLoadingComplete(); }); diff --git a/test/functional/apps/discover/_field_data.js b/test/functional/apps/discover/_field_data.js index 118234d54626c..d45b8f4841cb6 100644 --- a/test/functional/apps/discover/_field_data.js +++ b/test/functional/apps/discover/_field_data.js @@ -27,8 +27,7 @@ export default function ({ getService, getPageObjects }) { const queryBar = getService('queryBar'); const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); - // FLAKY: https://github.com/elastic/kibana/issues/78689 - describe.skip('discover tab', function describeIndexTests() { + describe('discover tab', function describeIndexTests() { this.tags('includeFirefox'); before(async function () { await esArchiver.loadIfNeeded('logstash_functional'); diff --git a/test/functional/apps/discover/_inspector.js b/test/functional/apps/discover/_inspector.js index fcb66fbd52cf7..900ad28e14e69 100644 --- a/test/functional/apps/discover/_inspector.js +++ b/test/functional/apps/discover/_inspector.js @@ -34,8 +34,7 @@ export default function ({ getService, getPageObjects }) { return hitsCountStatsRow[STATS_ROW_VALUE_INDEX]; } - // FLAKY: https://github.com/elastic/kibana/issues/39842 - describe.skip('inspect', () => { + describe('inspect', () => { before(async () => { await esArchiver.loadIfNeeded('logstash_functional'); await esArchiver.load('discover'); diff --git a/test/functional/fixtures/es_archiver/discover/data.json b/test/functional/fixtures/es_archiver/discover/data.json new file mode 100644 index 0000000000000..9158a3023fc5e --- /dev/null +++ b/test/functional/fixtures/es_archiver/discover/data.json @@ -0,0 +1,42 @@ +{ + "type": "doc", + "value": { + "id": "index-pattern:logstash-*", + "index": ".kibana", + "source": { + "index-pattern": { + "fields": "[{\"name\":\"@message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@message.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@message\"}}},{\"name\":\"@tags\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@tags.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@tags\"}}},{\"name\":\"@timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"agent\"}}},{\"name\":\"bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extension\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extension.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"extension\"}}},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"headings\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"headings.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"headings\"}}},{\"name\":\"host\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"host\"}}},{\"name\":\"id\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"index\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"index\"}}},{\"name\":\"ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"links\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"links\"}}},{\"name\":\"machine.os\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"machine.os\"}}},{\"name\":\"machine.ram\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"memory\",\"type\":\"number\",\"esTypes\":[\"double\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.char\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nestedField.child\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"nested\":{\"path\":\"nestedField\"}}},{\"name\":\"phpmemory\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.article:section\"}}},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.article:tag\"}}},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:description\"}}},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:image\"}}},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:image:height\"}}},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:image:width\"}}},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:site_name\"}}},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:title\"}}},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:type\"}}},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.og:url\"}}},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.twitter:card\"}}},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.twitter:description\"}}},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.twitter:image\"}}},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.twitter:site\"}}},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.twitter:title\"}}},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"relatedContent.url\"}}},{\"name\":\"request\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"request\"}}},{\"name\":\"response\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"response\"}}},{\"name\":\"spaces\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"spaces.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"spaces\"}}},{\"name\":\"type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"url.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"url\"}}},{\"name\":\"utc_time\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"xss\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"xss\"}}}]", + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "type": "index-pattern" + } + } +} + +{ + "type": "doc", + "value": { + "id": "search:ab12e3c0-f231-11e6-9486-733b1ac9221a", + "index": ".kibana", + "source": { + "search": { + "columns": [ + "_source" + ], + "description": "A Saved Search Description", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\n \"index\": \"logstash-*\",\n \"highlightAll\": true,\n \"filter\": [],\n \"query\": {\n \"query_string\": {\n \"query\": \"*\",\n \"analyze_wildcard\": true\n }\n }\n}" + }, + "sort": [ + "@timestamp", + "desc" + ], + "title": "A Saved Search", + "version": 1 + }, + "type": "search" + } + } +} diff --git a/test/functional/fixtures/es_archiver/discover/data.json.gz b/test/functional/fixtures/es_archiver/discover/data.json.gz deleted file mode 100644 index 047d890f6d410..0000000000000 Binary files a/test/functional/fixtures/es_archiver/discover/data.json.gz and /dev/null differ diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts index f0d12fd16bf7a..e7dd03db6b63c 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { ERROR_GROUP_ID, PROCESSOR_EVENT, @@ -12,7 +13,6 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { UIProcessorEvent } from '../../../../common/processor_event'; -import { ESFilter } from '../../../../typings/elasticsearch'; import { IUrlParams } from '../../../context/UrlParamsContext/types'; export function getBoolFilter({ diff --git a/x-pack/plugins/apm/public/utils/testHelpers.tsx b/x-pack/plugins/apm/public/utils/testHelpers.tsx index f990c4387ddf1..87dfeb95b6326 100644 --- a/x-pack/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/plugins/apm/public/utils/testHelpers.tsx @@ -6,26 +6,26 @@ /* global jest */ -import React from 'react'; -import { ReactWrapper, mount, MountRendererProps } from 'enzyme'; +import { render, waitFor } from '@testing-library/react'; +import { mount, MountRendererProps, ReactWrapper } from 'enzyme'; import enzymeToJson from 'enzyme-to-json'; import { Location } from 'history'; import moment from 'moment'; import { Moment } from 'moment-timezone'; -import { render, waitFor } from '@testing-library/react'; +import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { APMConfig } from '../../server'; -import { PromiseReturnType } from '../../typings/common'; -import { EuiThemeProvider } from '../../../observability/public'; import { ESFilter, - ESSearchResponse, ESSearchRequest, -} from '../../typings/elasticsearch'; + ESSearchResponse, +} from '../../../../typings/elasticsearch'; +import { EuiThemeProvider } from '../../../observability/public'; +import { PromiseReturnType } from '../../../observability/typings/common'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { APMConfig } from '../../server'; +import { UIFilters } from '../../typings/ui_filters'; import { MockApmPluginContextWrapper } from '../context/ApmPluginContext/MockApmPluginContext'; import { UrlParamsProvider } from '../context/UrlParamsContext'; -import { UIFilters } from '../../typings/ui_filters'; const originalConsoleWarn = console.warn; // eslint-disable-line no-console /** diff --git a/x-pack/plugins/apm/scripts/shared/get_es_client.ts b/x-pack/plugins/apm/scripts/shared/get_es_client.ts index 86dfd92190fdf..912c8943b1edf 100644 --- a/x-pack/plugins/apm/scripts/shared/get_es_client.ts +++ b/x-pack/plugins/apm/scripts/shared/get_es_client.ts @@ -6,7 +6,10 @@ import { Client } from '@elastic/elasticsearch'; import { ApiKeyAuth, BasicAuth } from '@elastic/elasticsearch/lib/pool'; -import { ESSearchResponse, ESSearchRequest } from '../../typings/elasticsearch'; +import { + ESSearchResponse, + ESSearchRequest, +} from '../../../../typings/elasticsearch'; export type ESClient = ReturnType; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts index ecda5b0e8504b..464a737c50ea2 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts @@ -9,6 +9,7 @@ import { isEmpty } from 'lodash'; import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; import { APMConfig } from '../..'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; import { AlertingPlugin } from '../../../../alerts/server'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; import { @@ -17,7 +18,6 @@ import { SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; -import { ESSearchResponse } from '../../../typings/elasticsearch'; import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts index d9e69c8f3b7d7..602ee99970f8a 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts @@ -7,21 +7,21 @@ import { schema } from '@kbn/config-schema'; import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; -import { getDurationFormatter } from '../../../common/utils/formatters'; -import { ProcessorEvent } from '../../../common/processor_event'; +import { APMConfig } from '../..'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; +import { AlertingPlugin } from '../../../../alerts/server'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; -import { ESSearchResponse } from '../../../typings/elasticsearch'; import { PROCESSOR_EVENT, + SERVICE_ENVIRONMENT, SERVICE_NAME, - TRANSACTION_TYPE, TRANSACTION_DURATION, - SERVICE_ENVIRONMENT, + TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { AlertingPlugin } from '../../../../alerts/server'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; -import { APMConfig } from '../..'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { getDurationFormatter } from '../../../common/utils/formatters'; import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; interface RegisterAlertParams { diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts index 06b296db5a485..0506e1b4c3aed 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts @@ -5,25 +5,25 @@ */ import { schema } from '@kbn/config-schema'; +import { isEmpty } from 'lodash'; import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; -import { isEmpty } from 'lodash'; -import { asDecimalOrInteger } from '../../../common/utils/formatters'; -import { ProcessorEvent } from '../../../common/processor_event'; -import { EventOutcome } from '../../../common/event_outcome'; +import { APMConfig } from '../..'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; +import { AlertingPlugin } from '../../../../alerts/server'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; -import { ESSearchResponse } from '../../../typings/elasticsearch'; import { + EVENT_OUTCOME, PROCESSOR_EVENT, + SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_TYPE, - EVENT_OUTCOME, - SERVICE_ENVIRONMENT, } from '../../../common/elasticsearch_fieldnames'; -import { AlertingPlugin } from '../../../../alerts/server'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; -import { APMConfig } from '../..'; +import { EventOutcome } from '../../../common/event_outcome'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { asDecimalOrInteger } from '../../../common/utils/formatters'; import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; interface RegisterAlertParams { diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts index e53a0e24b4723..730645c609cb6 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts @@ -9,7 +9,7 @@ import { IndicesStatsParams, Client } from 'elasticsearch'; import { ESSearchRequest, ESSearchResponse, -} from '../../../../typings/elasticsearch'; +} from '../../../../../../typings/elasticsearch'; import { ApmIndicesConfig } from '../../settings/apm_indices/get_apm_indices'; import { tasks } from './tasks'; import { APMDataTelemetry } from '../types'; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index ac82d353417b4..ec2eb7c8dd99a 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -5,7 +5,7 @@ */ import { ValuesType } from 'utility-types'; import { flatten, merge, sortBy, sum, pickBy } from 'lodash'; -import { AggregationOptionsByType } from '../../../../typings/elasticsearch/aggregations'; +import { AggregationOptionsByType } from '../../../../../../typings/elasticsearch/aggregations'; import { ProcessorEvent } from '../../../../common/processor_event'; import { TelemetryTask } from '.'; import { AGENT_NAMES, RUM_AGENT_NAMES } from '../../../../common/agent_name'; diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts index b12dd73a20986..9e18c81e4aaeb 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ProcessorEvent } from '../../../../common/processor_event'; -import { ESFilter } from '../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { ERROR_GROUP_ID, SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; +import { ProcessorEvent } from '../../../../common/processor_event'; import { rangeFilter } from '../../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts index dea518cad8e40..7866c99353451 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PromiseReturnType } from '../../../../typings/common'; +import { PromiseReturnType } from '../../../../../observability/typings/common'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; -import { getBuckets } from './get_buckets'; import { BUCKET_TARGET_COUNT } from '../../transactions/constants'; +import { getBuckets } from './get_buckets'; function getBucketSize({ start, end }: SetupTimeRange) { return Math.floor((end - start) / BUCKET_TARGET_COUNT); diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts index 0fbc7720f7111..37be72beedeb1 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ProcessorEvent } from '../../../common/processor_event'; +import { PromiseReturnType } from '../../../../observability/typings/common'; import { ERROR_GROUP_ID, SERVICE_NAME, TRANSACTION_SAMPLED, } from '../../../common/elasticsearch_fieldnames'; -import { PromiseReturnType } from '../../../typings/common'; +import { ProcessorEvent } from '../../../common/processor_event'; import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getTransaction } from '../transactions/get_transaction'; diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts index 006d2fae3d4fb..d734a1395fc5e 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { SortOptions } from '../../../../../typings/elasticsearch/aggregations'; +import { PromiseReturnType } from '../../../../observability/typings/common'; import { ERROR_CULPRIT, ERROR_EXC_HANDLED, @@ -12,11 +14,9 @@ import { ERROR_GROUP_ID, ERROR_LOG_MESSAGE, } from '../../../common/elasticsearch_fieldnames'; -import { PromiseReturnType } from '../../../typings/common'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getErrorGroupsProjection } from '../../projections/errors'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { SortOptions } from '../../../typings/elasticsearch/aggregations'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export type ErrorGroupListAPIResponse = PromiseReturnType< typeof getErrorGroups diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts index ea8d02eb833cf..dd9f0b0333c01 100644 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts +++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { ENVIRONMENT_NOT_DEFINED, ENVIRONMENT_ALL, diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts index 1b8f32d4de8b9..0592f13bdf54f 100644 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts +++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { UIFilters } from '../../../../typings/ui_filters'; import { getEnvironmentUiFilterES } from './get_environment_ui_filter_es'; import { diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts index 494cd6cbf0eec..921b46daee2a9 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts @@ -9,7 +9,7 @@ import { OBSERVER_VERSION_MAJOR } from '../../../../../common/elasticsearch_fiel import { ESSearchRequest, ESFilter, -} from '../../../../../typings/elasticsearch'; +} from '../../../../../../../typings/elasticsearch'; /* Adds a range query to the ES request to exclude legacy data diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts index d23d729db3924..870997efb77de 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts @@ -14,7 +14,7 @@ import { ProcessorEvent } from '../../../../../common/processor_event'; import { ESSearchRequest, ESSearchResponse, -} from '../../../../../typings/elasticsearch'; +} from '../../../../../../../typings/elasticsearch'; import { ApmIndicesConfig } from '../../../settings/apm_indices/get_apm_indices'; import { addFilterToExcludeLegacyData } from './add_filter_to_exclude_legacy_data'; import { callClientWithDebug } from '../call_client_with_debug'; diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts index 736c7ad2d1089..add522a5c7f84 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts @@ -10,7 +10,7 @@ import { ProcessorEvent } from '../../../../../common/processor_event'; import { ESSearchRequest, ESFilter, -} from '../../../../../typings/elasticsearch'; +} from '../../../../../../../typings/elasticsearch'; import { APMEventESSearchRequest } from '.'; import { ApmIndicesConfig, diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts index 072391606d574..8e74a7992e9ea 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts @@ -15,7 +15,7 @@ import { APMRequestHandlerContext } from '../../../../routes/typings'; import { ESSearchResponse, ESSearchRequest, -} from '../../../../../typings/elasticsearch'; +} from '../../../../../../../typings/elasticsearch'; import { callClientWithDebug } from '../call_client_with_debug'; // `type` was deprecated in 7.0 diff --git a/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts b/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts index e0bb9ad354f58..097538076de25 100644 --- a/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { CoreSetup } from 'src/core/server'; -import { PromiseReturnType } from '../../../typings/common'; +import { PromiseReturnType } from '../../../../observability/typings/common'; export type InternalSavedObjectsClient = PromiseReturnType< typeof getInternalSavedObjectsClient diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts index 363c4128137e0..65d36c8b36af8 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts @@ -4,20 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import moment from 'moment'; import { Logger } from 'kibana/server'; -import { isActivePlatinumLicense } from '../../../common/service_map'; -import { UI_SETTINGS } from '../../../../../../src/plugins/data/common'; -import { KibanaRequest } from '../../../../../../src/core/server'; +import moment from 'moment'; import { APMConfig } from '../..'; +import { KibanaRequest } from '../../../../../../src/core/server'; +import { UI_SETTINGS } from '../../../../../../src/plugins/data/common'; +import { ESFilter } from '../../../../../typings/elasticsearch'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { isActivePlatinumLicense } from '../../../common/service_map'; +import { UIFilters } from '../../../typings/ui_filters'; +import { APMRequestHandlerContext } from '../../routes/typings'; import { - getApmIndices, ApmIndicesConfig, + getApmIndices, } from '../settings/apm_indices/get_apm_indices'; -import { ESFilter } from '../../../typings/elasticsearch'; import { getEsFilter } from './convert_ui_filters/get_es_filter'; -import { APMRequestHandlerContext } from '../../routes/typings'; -import { ProcessorEvent } from '../../../common/processor_event'; import { APMEventClient, createApmEventClient, @@ -26,7 +27,6 @@ import { APMInternalClient, createInternalESClient, } from './create_es_client/create_internal_es_client'; -import { UIFilters } from '../../../typings/ui_filters'; // Explicitly type Setup to prevent TS initialization errors // https://github.com/microsoft/TypeScript/issues/34933 diff --git a/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts b/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts index ccc7ba7e22b50..03a44e77ba2d3 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts @@ -9,7 +9,7 @@ import { EventOutcome } from '../../../common/event_outcome'; import { AggregationOptionsByType, AggregationResultOf, -} from '../../../typings/elasticsearch/aggregations'; +} from '../../../../../typings/elasticsearch/aggregations'; import { getTransactionDurationFieldForAggregatedTransactions } from './aggregated_transactions'; export function getOutcomeAggregation({ diff --git a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts index 3ccba8c7586dc..57eae26593305 100644 --- a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Unionize, Overwrite } from 'utility-types'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { getMetricsDateHistogramParams } from '../helpers/metrics'; -import { ChartBase } from './types'; -import { transformDataToMetricsChart } from './transform_metrics_chart'; +import { Overwrite, Unionize } from 'utility-types'; +import { AggregationOptionsByType } from '../../../../../typings/elasticsearch'; import { getMetricsProjection } from '../../projections/metrics'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { AggregationOptionsByType } from '../../../typings/elasticsearch/aggregations'; import { APMEventESSearchRequest } from '../helpers/create_es_client/create_apm_event_client'; +import { getMetricsDateHistogramParams } from '../helpers/metrics'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; +import { transformDataToMetricsChart } from './transform_metrics_chart'; +import { ChartBase } from './types'; type MetricsAggregationMap = Unionize<{ min: AggregationOptionsByType['min']; diff --git a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts index a191d5400e36c..bcf8b412f350a 100644 --- a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { ChartBase } from './types'; -import { ESSearchResponse } from '../../../typings/elasticsearch'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; import { getVizColorForIndex } from '../../../common/viz_colors'; import { GenericMetricsRequest } from './fetch_and_transform_metrics'; +import { ChartBase } from './types'; export type GenericMetricsChart = ReturnType< typeof transformDataToMetricsChart diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts index 5f4bc61af4c69..8f8d7763970b7 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts @@ -4,21 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from '@hapi/boom'; +import { MlPluginSetup } from '../../../../ml/server'; +import { PromiseReturnType } from '../../../../observability/typings/common'; +import { + getSeverity, + ML_ERRORS, + ServiceAnomalyStats, +} from '../../../common/anomaly_detection'; +import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; import { getServiceHealthStatus } from '../../../common/service_health_status'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { PromiseReturnType } from '../../../typings/common'; import { TRANSACTION_PAGE_LOAD, TRANSACTION_REQUEST, } from '../../../common/transaction_types'; -import { - ServiceAnomalyStats, - getSeverity, - ML_ERRORS, -} from '../../../common/anomaly_detection'; import { getMlJobsWithAPMGroup } from '../anomaly_detection/get_ml_jobs_with_apm_group'; -import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; -import { MlPluginSetup } from '../../../../ml/server'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export const DEFAULT_ANOMALIES = { mlJobIds: [], serviceAnomalies: {} }; diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 330bb936c9e88..ccebbfa44538a 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { chunk } from 'lodash'; import { Logger } from 'kibana/server'; +import { chunk } from 'lodash'; +import { PromiseReturnType } from '../../../../observability/typings/common'; import { AGENT_NAME, SERVICE_ENVIRONMENT, @@ -12,17 +13,16 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { getServicesProjection } from '../../projections/services'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { PromiseReturnType } from '../../../typings/common'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; -import { transformServiceMapResponses } from './transform_service_map_responses'; -import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids'; -import { getTraceSampleIds } from './get_trace_sample_ids'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { + DEFAULT_ANOMALIES, getServiceAnomalies, ServiceAnomaliesResponse, - DEFAULT_ANOMALIES, } from './get_service_anomalies'; +import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids'; +import { getTraceSampleIds } from './get_trace_sample_ids'; +import { transformServiceMapResponses } from './transform_service_map_responses'; export interface IEnvOptions { setup: Setup & SetupTimeRange; diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts index 37b34641435fb..82d339686f7ec 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts @@ -4,33 +4,33 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ESFilter } from '../../../../../typings/elasticsearch'; import { - TRANSACTION_REQUEST, - TRANSACTION_PAGE_LOAD, -} from '../../../common/transaction_types'; -import { - SERVICE_NAME, + METRIC_CGROUP_MEMORY_USAGE_BYTES, METRIC_SYSTEM_CPU_PERCENT, METRIC_SYSTEM_FREE_MEMORY, METRIC_SYSTEM_TOTAL_MEMORY, - METRIC_CGROUP_MEMORY_USAGE_BYTES, + SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; +import { + TRANSACTION_PAGE_LOAD, + TRANSACTION_REQUEST, +} from '../../../common/transaction_types'; import { rangeFilter } from '../../../common/utils/range_filter'; -import { ESFilter } from '../../../typings/elasticsearch'; +import { + getDocumentTypeFilterForAggregatedTransactions, + getProcessorEventForAggregatedTransactions, + getTransactionDurationFieldForAggregatedTransactions, +} from '../helpers/aggregated_transactions'; +import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { percentCgroupMemoryUsedScript, percentSystemMemoryUsedScript, } from '../metrics/by_agent/shared/memory'; -import { - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, - getDocumentTypeFilterForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; import { getErrorRate } from '../transaction_groups/get_error_rate'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; interface Options { setup: Setup & SetupTimeRange; diff --git a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts index 22c655bb96f50..db11ab2d9ce3a 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts @@ -3,20 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { uniq, take, sortBy } from 'lodash'; import Boom from '@hapi/boom'; -import { ProcessorEvent } from '../../../common/processor_event'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { rangeFilter } from '../../../common/utils/range_filter'; -import { ESFilter } from '../../../typings/elasticsearch'; +import { sortBy, take, uniq } from 'lodash'; +import { ESFilter } from '../../../../../typings/elasticsearch'; import { - SERVICE_NAME, SERVICE_ENVIRONMENT, - TRACE_ID, + SERVICE_NAME, SPAN_DESTINATION_SERVICE_RESOURCE, + TRACE_ID, } from '../../../common/elasticsearch_fieldnames'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { ProcessorEvent } from '../../../common/processor_event'; import { SERVICE_MAP_TIMEOUT_ERROR } from '../../../common/service_map'; +import { rangeFilter } from '../../../common/utils/range_filter'; +import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; const MAX_TRACES_TO_INSPECT = 1000; diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts index b80e86d53f292..367cf2faf6a8e 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts @@ -4,19 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ import { isNumber } from 'lodash'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { Annotation, AnnotationType } from '../../../../common/annotations'; -import { SetupTimeRange, Setup } from '../../helpers/setup_request'; -import { ESFilter } from '../../../../typings/elasticsearch'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { SERVICE_NAME, SERVICE_VERSION, } from '../../../../common/elasticsearch_fieldnames'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, } from '../../helpers/aggregated_transactions'; +import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; export async function getDerivedServiceAnnotations({ setup, diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts index 6e3ae0181ddee..623abf6930297 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts @@ -5,13 +5,13 @@ */ import { LegacyAPICaller, Logger } from 'kibana/server'; -import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; -import { ESSearchResponse } from '../../../../typings/elasticsearch'; +import { ESSearchResponse } from '../../../../../../typings/elasticsearch'; +import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations'; import { ScopedAnnotationsClient } from '../../../../../observability/server'; import { Annotation, AnnotationType } from '../../../../common/annotations'; -import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations'; -import { SetupTimeRange, Setup } from '../../helpers/setup_request'; +import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; export async function getStoredAnnotations({ setup, diff --git a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts index f30b77f147710..16c46be78cb28 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts @@ -6,7 +6,7 @@ import { ESSearchRequest, ESSearchResponse, -} from '../../../../typings/elasticsearch'; +} from '../../../../../../typings/elasticsearch'; import { inspectSearchParams, SearchParamsMock, diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts index 5ea3714e81b6f..89915e798b7cd 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts @@ -4,17 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ import { Logger } from '@kbn/logging'; +import { PromiseReturnType } from '../../../../../observability/typings/common'; import { joinByKey } from '../../../../common/utils/join_by_key'; -import { PromiseReturnType } from '../../../../typings/common'; -import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getServicesProjection } from '../../../projections/services'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { - getTransactionDurationAverages, getAgentNames, - getTransactionRates, - getTransactionErrorRates, getEnvironments, getHealthStatuses, + getTransactionDurationAverages, + getTransactionErrorRates, + getTransactionRates, } from './get_services_items_stats'; export type ServiceListAPIResponse = PromiseReturnType; diff --git a/x-pack/plugins/apm/server/lib/services/get_services/index.ts b/x-pack/plugins/apm/server/lib/services/get_services/index.ts index 5f39d6c836930..9d450804e421d 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/index.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEmpty } from 'lodash'; import { Logger } from '@kbn/logging'; -import { PromiseReturnType } from '../../../../typings/common'; +import { isEmpty } from 'lodash'; +import { PromiseReturnType } from '../../../../../observability/typings/common'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; -import { hasHistoricalAgentData } from './has_historical_agent_data'; import { getLegacyDataStatus } from './get_legacy_data_status'; import { getServicesItems } from './get_services_items'; +import { hasHistoricalAgentData } from './has_historical_agent_data'; export type ServiceListAPIResponse = PromiseReturnType; diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts index ab01a68733a7a..6791bf85a7b6a 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchHit } from '../../../../typings/elasticsearch'; +import { ESSearchHit } from '../../../../../../typings/elasticsearch'; import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types'; // needed for backwards compatability diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts index 3a9623c777516..bd10df76b85c7 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ESSearchHit } from '../../../../../../typings/elasticsearch'; +import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types'; import { - SERVICE_NAME, SERVICE_ENVIRONMENT, + SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../helpers/setup_request'; -import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types'; -import { ESSearchHit } from '../../../../typings/elasticsearch'; import { convertConfigSettingsToString } from './convert_settings_to_string'; export async function findExactConfiguration({ diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts index 2585f88c2aa43..43ae4995ce672 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchHit } from '../../../../typings/elasticsearch'; +import { ESSearchHit } from '../../../../../../typings/elasticsearch'; import { SERVICE_NAME, SERVICE_ENVIRONMENT, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts index 3efc65afdfd28..76e595c928cf2 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { asDuration } from '../../../../common/utils/formatters'; -import { ESFilter } from '../../../../typings/elasticsearch'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { SERVICE_NAME, TRANSACTION_DURATION, @@ -14,6 +12,8 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; +import { asDuration } from '../../../../common/utils/formatters'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getDurationForPercentile } from './get_duration_for_percentile'; import { diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts index 37ee19ff40f62..a94540df10fff 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts index 1cf0787c1d970..c5ab8d8f1d111 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../typings/elasticsearch'; import { SignificantTermsScoring } from './scoring_rt'; export function getSignificantTermsAgg({ diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts index 0a4d9748f2597..89fff260a7d23 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -3,24 +3,24 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { take, sortBy } from 'lodash'; -import { Unionize } from 'utility-types'; +import { sortBy, take } from 'lodash'; import moment from 'moment'; -import { joinByKey } from '../../../common/utils/join_by_key'; +import { Unionize } from 'utility-types'; +import { AggregationOptionsByType } from '../../../../../typings/elasticsearch'; +import { PromiseReturnType } from '../../../../observability/typings/common'; import { SERVICE_NAME, TRANSACTION_NAME, } from '../../../common/elasticsearch_fieldnames'; +import { joinByKey } from '../../../common/utils/join_by_key'; import { getTransactionGroupsProjection } from '../../projections/transaction_groups'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { PromiseReturnType } from '../../../../observability/typings/common'; -import { AggregationOptionsByType } from '../../../typings/elasticsearch/aggregations'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getAverages, - getSums, - getPercentiles, getCounts, + getPercentiles, + getSums, } from './get_transaction_group_stats'; interface TopTransactionOptions { diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts index 2550bd70c527d..cfd3540446172 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts @@ -6,7 +6,7 @@ import { merge } from 'lodash'; import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; import { arrayUnionToCallable } from '../../../common/utils/array_union_to_callable'; -import { AggregationInputMap } from '../../../typings/elasticsearch/aggregations'; +import { AggregationInputMap } from '../../../../../typings/elasticsearch'; import { TransactionGroupRequestBase, TransactionGroupSetup } from './fetcher'; import { getTransactionDurationFieldForAggregatedTransactions } from '../helpers/aggregated_transactions'; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts index 8c999b445d799..aad67c43f48e2 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts @@ -5,7 +5,7 @@ */ import { Logger } from 'kibana/server'; -import { ESSearchResponse } from '../../../../../typings/elasticsearch'; +import { ESSearchResponse } from '../../../../../../../typings/elasticsearch'; import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts index e2edbbec63d47..a2da3977b81c7 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts @@ -4,22 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../../../../typings/elasticsearch'; +import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { SERVICE_NAME, TRANSACTION_NAME, TRANSACTION_RESULT, TRANSACTION_TYPE, } from '../../../../../common/elasticsearch_fieldnames'; -import { PromiseReturnType } from '../../../../../../observability/typings/common'; -import { getBucketSize } from '../../../helpers/get_bucket_size'; import { rangeFilter } from '../../../../../common/utils/range_filter'; -import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { + getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, - getDocumentTypeFilterForAggregatedTransactions, } from '../../../helpers/aggregated_transactions'; +import { getBucketSize } from '../../../helpers/get_bucket_size'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; export type ESResponse = PromiseReturnType; export function timeseriesFetcher({ diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index 34d01627a2869..010acd09239a3 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { ValuesType } from 'utility-types'; -import { PromiseReturnType } from '../../../../../typings/common'; -import { joinByKey } from '../../../../../common/utils/join_by_key'; -import { ProcessorEvent } from '../../../../../common/processor_event'; +import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { SERVICE_NAME, TRACE_ID, @@ -16,13 +14,15 @@ import { TRANSACTION_SAMPLED, TRANSACTION_TYPE, } from '../../../../../common/elasticsearch_fieldnames'; +import { ProcessorEvent } from '../../../../../common/processor_event'; +import { joinByKey } from '../../../../../common/utils/join_by_key'; import { rangeFilter } from '../../../../../common/utils/range_filter'; -import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, } from '../../../helpers/aggregated_transactions'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; function getHistogramAggOptions({ bucketSize, diff --git a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts index b9f25e20f9f73..8109becbed45e 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts @@ -4,16 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ProcessorEvent } from '../../../common/processor_event'; +import { ESFilter } from '../../../../../typings/elasticsearch'; import { SERVICE_ENVIRONMENT, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../common/utils/range_filter'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; -import { ESFilter } from '../../../typings/elasticsearch'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export async function getEnvironments({ setup, diff --git a/x-pack/plugins/apm/server/projections/typings.ts b/x-pack/plugins/apm/server/projections/typings.ts index 332ac533e78c6..b6d6ffbb7ddbf 100644 --- a/x-pack/plugins/apm/server/projections/typings.ts +++ b/x-pack/plugins/apm/server/projections/typings.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchBody } from '../../typings/elasticsearch'; import { AggregationOptionsByType, AggregationInputMap, -} from '../../typings/elasticsearch/aggregations'; + ESSearchBody, +} from '../../../../typings/elasticsearch'; import { APMEventESSearchRequest } from '../lib/helpers/create_es_client/create_apm_event_client'; export type Projection = Omit & { diff --git a/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts b/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts index ea7267dd337c2..2782b039958e1 100644 --- a/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts +++ b/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts @@ -3,12 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { mergeWith, isPlainObject, cloneDeep } from 'lodash'; +import { cloneDeep, isPlainObject, mergeWith } from 'lodash'; import { DeepPartial } from 'utility-types'; -import { AggregationInputMap } from '../../../../typings/elasticsearch/aggregations'; -import { ESSearchBody } from '../../../../typings/elasticsearch'; -import { Projection } from '../../typings'; +import { + AggregationInputMap, + ESSearchBody, +} from '../../../../../../typings/elasticsearch'; import { APMEventESSearchRequest } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { Projection } from '../../typings'; type PlainObject = Record; diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx index 21b59dc516d06..9093b16fada0d 100644 --- a/x-pack/plugins/apm/server/utils/test_helpers.tsx +++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx @@ -3,14 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { APMConfig } from '../'; +import { PromiseReturnType } from '../../../observability/typings/common'; import { ESFilter, - ESSearchResponse, ESSearchRequest, -} from '../../typings/elasticsearch'; -import { PromiseReturnType } from '../../typings/common'; + ESSearchResponse, +} from '../../../../typings/elasticsearch'; import { UIFilters } from '../../typings/ui_filters'; -import { APMConfig } from '..'; interface Options { mockResponse?: ( diff --git a/x-pack/plugins/apm/typings/common.d.ts b/x-pack/plugins/apm/typings/common.d.ts index 754529a198552..9133315c4c16a 100644 --- a/x-pack/plugins/apm/typings/common.d.ts +++ b/x-pack/plugins/apm/typings/common.d.ts @@ -25,10 +25,4 @@ export type PromiseValueType = Value extends Promise ? Value : Value; -export type PromiseReturnType = Func extends ( - ...args: any[] -) => Promise - ? Value - : Func; - export type Maybe = T | null | undefined; diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts new file mode 100644 index 0000000000000..1508f27c00377 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts @@ -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 { ShallowWrapper } from 'enzyme'; + +/** + * Quick and easy helper for re-rendering a React component in Enzyme + * after (e.g.) updating Kea values + */ +export const rerender = (wrapper: ShallowWrapper) => { + wrapper.setProps({}); // Re-renders + wrapper.update(); // Just in case +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts index bdf555311d154..e8944b15978a9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts @@ -15,4 +15,5 @@ export { mockAllValues, mockAllActions, setMockValues, setMockActions } from './ export { mountAsync } from './mount_async.mock'; export { mountWithIntl } from './mount_with_i18n.mock'; export { shallowWithIntl } from './shallow_with_i18n.mock'; +export { rerender } from './enzyme_rerender.mock'; // Note: shallow_useeffect must be imported directly as a file diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx index b4b092f17a6aa..d0bbf868aa90c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx @@ -5,6 +5,7 @@ */ import { setMockValues, setMockActions } from '../../../../../__mocks__/kea.mock'; +import { rerender } from '../../../../../__mocks__'; import React from 'react'; import { shallow } from 'enzyme'; @@ -60,7 +61,7 @@ describe('FormKeyEngineAccess', () => { ...values, fullEngineAccessChecked: false, }); - wrapper.setProps({}); // Re-render + rerender(wrapper); expect(wrapper.find('#all_engines').prop('checked')).toEqual(false); expect(wrapper.find('#all_engines').prop('value')).toEqual('false'); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss index d7740724204a7..529fb9c4bd63e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss @@ -15,3 +15,11 @@ margin-top: $euiSizeXS; } } + +.appSearchNavIcons { + // EUI override + &.euiFlexItem { + flex-grow: 0; + flex-direction: row; + } +} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx index 7bdc3c86a50d6..0d2ce654d4a0a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx @@ -4,134 +4,189 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../../__mocks__/react_router_history.mock'; import { setMockValues } from '../../../__mocks__/kea.mock'; +import { rerender } from '../../../__mocks__'; import React from 'react'; -import { shallow, mount } from 'enzyme'; -import { Switch, useParams } from 'react-router-dom'; -import { EuiBadge } from '@elastic/eui'; +import { shallow } from 'enzyme'; +import { EuiBadge, EuiIcon } from '@elastic/eui'; -import { EngineRouter, EngineNav } from './'; +import { EngineNav } from './'; -describe('EngineRouter', () => { - it('renders a default engine overview', () => { - setMockValues({ myRole: {} }); - const wrapper = shallow(); - - expect(wrapper.find(Switch)).toHaveLength(1); - expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1); - }); - - it('renders an analytics view', () => { - setMockValues({ myRole: { canViewEngineAnalytics: true } }); - const wrapper = shallow(); +describe('EngineNav', () => { + const values = { myRole: {}, engineName: 'some-engine', dataLoading: false, engine: {} }; - expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1); + beforeEach(() => { + setMockValues(values); }); -}); -describe('EngineNav', () => { - beforeEach(() => { - (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' }); + it('does not render if async data is still loading', () => { + setMockValues({ ...values, dataLoading: true }); + const wrapper = shallow(); + expect(wrapper.isEmptyRender()).toBe(true); }); it('does not render without an engine name', () => { - setMockValues({ myRole: {} }); - (useParams as jest.Mock).mockReturnValue({ engineName: '' }); + setMockValues({ ...values, engineName: '' }); const wrapper = shallow(); expect(wrapper.isEmptyRender()).toBe(true); }); - it('renders an engine label', () => { - setMockValues({ myRole: {} }); - const wrapper = mount(); + it('renders an engine label and badges', () => { + setMockValues({ ...values, isSampleEngine: false, isMetaEngine: false }); + const wrapper = shallow(); + const label = wrapper.find('[data-test-subj="EngineLabel"]').find('.eui-textTruncate'); + + expect(label.text()).toEqual('SOME-ENGINE'); + expect(wrapper.find(EuiBadge)).toHaveLength(0); - const label = wrapper.find('[data-test-subj="EngineLabel"]').last(); - expect(label.text()).toEqual(expect.stringContaining('SOME-ENGINE')); + setMockValues({ ...values, isSampleEngine: true }); + rerender(wrapper); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('SAMPLE ENGINE'); - // TODO: Test sample & meta engine conditional rendering - expect(label.find(EuiBadge).text()).toEqual('SAMPLE ENGINE'); + setMockValues({ ...values, isMetaEngine: true }); + rerender(wrapper); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('META ENGINE'); }); it('renders a default engine overview link', () => { - setMockValues({ myRole: {} }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineOverviewLink"]')).toHaveLength(1); }); it('renders an analytics link', () => { - setMockValues({ myRole: { canViewEngineAnalytics: true } }); + setMockValues({ ...values, myRole: { canViewEngineAnalytics: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineAnalyticsLink"]')).toHaveLength(1); }); it('renders a documents link', () => { - setMockValues({ myRole: { canViewEngineDocuments: true } }); + setMockValues({ ...values, myRole: { canViewEngineDocuments: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineDocumentsLink"]')).toHaveLength(1); }); it('renders a schema link', () => { - setMockValues({ myRole: { canViewEngineSchema: true } }); + setMockValues({ ...values, myRole: { canViewEngineSchema: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineSchemaLink"]')).toHaveLength(1); + }); + + describe('schema nav icons', () => { + const myRole = { canViewEngineSchema: true }; + + it('renders unconfirmed schema fields info icon', () => { + setMockValues({ ...values, myRole, hasUnconfirmedSchemaFields: true }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineNavSchemaUnconfirmedFields"]')).toHaveLength(1); + }); - // TODO: Schema warning icon + it('renders schema conflicts alert icon', () => { + setMockValues({ ...values, myRole, hasSchemaConflicts: true }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineNavSchemaConflicts"]')).toHaveLength(1); + }); }); - // TODO: Unskip when EngineLogic is migrated - it.skip('renders a crawler link', () => { - setMockValues({ myRole: { canViewEngineCrawler: true } }); - const wrapper = shallow(); - expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1); + describe('crawler link', () => { + const myRole = { canViewEngineCrawler: true }; + + it('renders', () => { + setMockValues({ ...values, myRole }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1); + }); + + it('does not render for meta engines', () => { + setMockValues({ ...values, myRole, isMetaEngine: true }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0); + }); - // TODO: Test that the crawler link does NOT show up for meta/sample engines + it('does not render for sample engine', () => { + setMockValues({ ...values, myRole, isSampleEngine: true }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0); + }); }); - // TODO: Unskip when EngineLogic is migrated - it.skip('renders a meta engine source engines link', () => { - setMockValues({ myRole: { canViewMetaEngineSourceEngines: true } }); - const wrapper = shallow(); - expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1); + describe('meta engine source engines link', () => { + const myRole = { canViewMetaEngineSourceEngines: true }; + + it('renders', () => { + setMockValues({ ...values, myRole, isMetaEngine: true }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1); + }); - // TODO: Test that the crawler link does NOT show up for non-meta engines + it('does not render for non meta engines', () => { + setMockValues({ ...values, myRole, isMetaEngine: false }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(0); + }); }); it('renders a relevance tuning link', () => { - setMockValues({ myRole: { canManageEngineRelevanceTuning: true } }); + setMockValues({ ...values, myRole: { canManageEngineRelevanceTuning: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineRelevanceTuningLink"]')).toHaveLength(1); + }); + + describe('relevance tuning nav icons', () => { + const myRole = { canManageEngineRelevanceTuning: true }; + + it('renders unconfirmed schema fields info icon', () => { + const engine = { unsearchedUnconfirmedFields: true }; + setMockValues({ ...values, myRole, engine }); + const wrapper = shallow(); + expect( + wrapper.find('[data-test-subj="EngineNavRelevanceTuningUnsearchedFields"]') + ).toHaveLength(1); + }); + + it('renders schema conflicts alert icon', () => { + const engine = { invalidBoosts: true }; + setMockValues({ ...values, myRole, engine }); + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineNavRelevanceTuningInvalidBoosts"]')).toHaveLength( + 1 + ); + }); - // TODO: Boost error icon + it('can render multiple icons', () => { + const engine = { invalidBoosts: true, unsearchedUnconfirmedFields: true }; + setMockValues({ ...values, myRole, engine }); + const wrapper = shallow(); + expect(wrapper.find(EuiIcon)).toHaveLength(2); + }); }); it('renders a synonyms link', () => { - setMockValues({ myRole: { canManageEngineSynonyms: true } }); + setMockValues({ ...values, myRole: { canManageEngineSynonyms: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineSynonymsLink"]')).toHaveLength(1); }); it('renders a curations link', () => { - setMockValues({ myRole: { canManageEngineCurations: true } }); + setMockValues({ ...values, myRole: { canManageEngineCurations: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineCurationsLink"]')).toHaveLength(1); }); it('renders a results settings link', () => { - setMockValues({ myRole: { canManageEngineResultSettings: true } }); + setMockValues({ ...values, myRole: { canManageEngineResultSettings: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineResultSettingsLink"]')).toHaveLength(1); }); it('renders a Search UI link', () => { - setMockValues({ myRole: { canManageEngineSearchUi: true } }); + setMockValues({ ...values, myRole: { canManageEngineSearchUi: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineSearchUILink"]')).toHaveLength(1); }); it('renders an API logs link', () => { - setMockValues({ myRole: { canViewEngineApiLogs: true } }); + setMockValues({ ...values, myRole: { canViewEngineApiLogs: true } }); const wrapper = shallow(); expect(wrapper.find('[data-test-subj="EngineAPILogsLink"]')).toHaveLength(1); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx index f92fefc7124b8..77aca8a71994d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx @@ -5,18 +5,15 @@ */ import React from 'react'; -import { Route, Switch, useParams } from 'react-router-dom'; import { useValues } from 'kea'; -import { EuiText, EuiBadge } from '@elastic/eui'; +import { EuiText, EuiBadge, EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { SideNavLink, SideNavItem } from '../../../shared/layout'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { AppLogic } from '../../app_logic'; import { getEngineRoute, - ENGINE_PATH, ENGINE_ANALYTICS_PATH, ENGINE_DOCUMENTS_PATH, ENGINE_SCHEMA_PATH, @@ -45,34 +42,10 @@ import { API_LOGS_TITLE, } from './constants'; -import './engine_nav.scss'; - -export const EngineRouter: React.FC = () => { - const { - myRole: { canViewEngineAnalytics }, - } = useValues(AppLogic); +import { EngineLogic } from './'; +import { EngineDetails } from './types'; - // TODO: EngineLogic - - const { engineName } = useParams() as { engineName: string }; - const engineBreadcrumb = [ENGINES_TITLE, engineName]; - - return ( - // TODO: Add more routes as we migrate them - - {canViewEngineAnalytics && ( - - -
    Just testing right now
    -
    - )} - - -
    Overview
    -
    -
    - ); -}; +import './engine_nav.scss'; export const EngineNav: React.FC = () => { const { @@ -91,14 +64,22 @@ export const EngineNav: React.FC = () => { }, } = useValues(AppLogic); - // TODO: Use EngineLogic - const isSampleEngine = true; - const isMetaEngine = false; - const { engineName } = useParams() as { engineName: string }; - const engineRoute = engineName && getEngineRoute(engineName); + const { + engineName, + dataLoading, + isSampleEngine, + isMetaEngine, + hasSchemaConflicts, + hasUnconfirmedSchemaFields, + engine, + } = useValues(EngineLogic); + if (dataLoading) return null; if (!engineName) return null; + const engineRoute = getEngineRoute(engineName); + const { invalidBoosts, unsearchedUnconfirmedFields } = engine as Required; + return ( <> @@ -143,8 +124,33 @@ export const EngineNav: React.FC = () => { to={getAppSearchUrl(engineRoute + ENGINE_SCHEMA_PATH)} data-test-subj="EngineSchemaLink" > - {SCHEMA_TITLE} - {/* TODO: Engine schema warning icon */} + + {SCHEMA_TITLE} + + {hasUnconfirmedSchemaFields && ( + + )} + {hasSchemaConflicts && ( + + )} + + )} {canViewEngineCrawler && !isMetaEngine && !isSampleEngine && ( @@ -171,8 +177,33 @@ export const EngineNav: React.FC = () => { to={getAppSearchUrl(engineRoute + ENGINE_RELEVANCE_TUNING_PATH)} data-test-subj="EngineRelevanceTuningLink" > - {RELEVANCE_TUNING_TITLE} - {/* TODO: invalid boosts error icon */} + + {RELEVANCE_TUNING_TITLE} + + {invalidBoosts && ( + + )} + {unsearchedUnconfirmedFields && ( + + )} + + )} {canManageEngineSynonyms && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx new file mode 100644 index 0000000000000..e38381cad32ba --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx @@ -0,0 +1,81 @@ +/* + * 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 '../../../__mocks__/react_router_history.mock'; +import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; +import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow } from 'enzyme'; +import { Switch, Redirect, useParams } from 'react-router-dom'; + +jest.mock('../../../shared/flash_messages', () => ({ + setQueuedErrorMessage: jest.fn(), +})); +import { setQueuedErrorMessage } from '../../../shared/flash_messages'; + +import { EngineRouter } from './'; + +describe('EngineRouter', () => { + const values = { dataLoading: false, engineNotFound: false, myRole: {} }; + const actions = { setEngineName: jest.fn(), initializeEngine: jest.fn(), clearEngine: jest.fn() }; + + beforeEach(() => { + setMockValues(values); + setMockActions(actions); + }); + + describe('useEffect', () => { + beforeEach(() => { + (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' }); + shallow(); + }); + + it('sets engineName based on the current route parameters', () => { + expect(actions.setEngineName).toHaveBeenCalledWith('some-engine'); + }); + + it('initializes/fetches engine API data', () => { + expect(actions.initializeEngine).toHaveBeenCalled(); + }); + + it('clears engine on unmount', () => { + unmountHandler(); + expect(actions.clearEngine).toHaveBeenCalled(); + }); + }); + + it('redirects to engines list and flashes an error if the engine param was not found', () => { + (useParams as jest.Mock).mockReturnValue({ engineName: '404-engine' }); + setMockValues({ ...values, engineNotFound: true }); + const wrapper = shallow(); + + expect(wrapper.find(Redirect).prop('to')).toEqual('/engines'); + expect(setQueuedErrorMessage).toHaveBeenCalledWith( + "No engine with name '404-engine' could be found." + ); + }); + + it('does not render if async data is still loading', () => { + setMockValues({ ...values, dataLoading: true }); + const wrapper = shallow(); + expect(wrapper.isEmptyRender()).toBe(true); + }); + + it('renders a default engine overview', () => { + const wrapper = shallow(); + + expect(wrapper.find(Switch)).toHaveLength(1); + expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1); + }); + + it('renders an analytics view', () => { + setMockValues({ myRole: { canViewEngineAnalytics: true } }); + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx new file mode 100644 index 0000000000000..3e6856771f7d9 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx @@ -0,0 +1,105 @@ +/* + * 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 React, { useEffect } from 'react'; +import { Route, Switch, Redirect, useParams } from 'react-router-dom'; +import { useValues, useActions } from 'kea'; + +import { i18n } from '@kbn/i18n'; + +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { setQueuedErrorMessage } from '../../../shared/flash_messages'; +import { AppLogic } from '../../app_logic'; + +// TODO: Uncomment and add more routes as we migrate them +import { + ENGINES_PATH, + ENGINE_PATH, + ENGINE_ANALYTICS_PATH, + // ENGINE_DOCUMENTS_PATH, + // ENGINE_SCHEMA_PATH, + // ENGINE_CRAWLER_PATH, + // META_ENGINE_SOURCE_ENGINES_PATH, + // ENGINE_RELEVANCE_TUNING_PATH, + // ENGINE_SYNONYMS_PATH, + // ENGINE_CURATIONS_PATH, + // ENGINE_RESULT_SETTINGS_PATH, + // ENGINE_SEARCH_UI_PATH, + // ENGINE_API_LOGS_PATH, +} from '../../routes'; +import { ENGINES_TITLE } from '../engines'; +import { + OVERVIEW_TITLE, + ANALYTICS_TITLE, + // DOCUMENTS_TITLE, + // SCHEMA_TITLE, + // CRAWLER_TITLE, + // RELEVANCE_TUNING_TITLE, + // SYNONYMS_TITLE, + // CURATIONS_TITLE, + // RESULT_SETTINGS_TITLE, + // SEARCH_UI_TITLE, + // API_LOGS_TITLE, +} from './constants'; + +import { EngineLogic } from './'; + +export const EngineRouter: React.FC = () => { + const { + myRole: { + canViewEngineAnalytics, + // canViewEngineDocuments, + // canViewEngineSchema, + // canViewEngineCrawler, + // canViewMetaEngineSourceEngines, + // canManageEngineSynonyms, + // canManageEngineCurations, + // canManageEngineRelevanceTuning, + // canManageEngineResultSettings, + // canManageEngineSearchUi, + // canViewEngineApiLogs, + }, + } = useValues(AppLogic); + + const { dataLoading, engineNotFound } = useValues(EngineLogic); + const { setEngineName, initializeEngine, clearEngine } = useActions(EngineLogic); + + const { engineName } = useParams() as { engineName: string }; + const engineBreadcrumb = [ENGINES_TITLE, engineName]; + + useEffect(() => { + setEngineName(engineName); + initializeEngine(); + return clearEngine; + }, [engineName]); + + if (engineNotFound) { + setQueuedErrorMessage( + i18n.translate('xpack.enterpriseSearch.appSearch.engine.notFound', { + defaultMessage: "No engine with name '{engineName}' could be found.", + values: { engineName }, + }) + ); + return ; + } + + if (dataLoading) return null; + + return ( + + {canViewEngineAnalytics && ( + + +
    Just testing right now
    +
    + )} + + +
    Overview
    +
    +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts index 3d8f343312cc6..4e7d81f73fb8d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts @@ -4,5 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EngineRouter, EngineNav } from './engine_nav'; +export { EngineRouter } from './engine_router'; +export { EngineNav } from './engine_nav'; export { EngineLogic } from './engine_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx new file mode 100644 index 0000000000000..f1eac1a009ecf --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx @@ -0,0 +1,81 @@ +/* + * 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 React from 'react'; +import { shallow } from 'enzyme'; + +import { GenericConfirmationModal } from './generic_confirmation_modal'; + +describe('GenericConfirmationModal', () => { + let wrapper: any; + const onClose = jest.fn(); + const onSave = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + wrapper = shallow( + + ); + }); + + it('calls onSave callback when save is pressed', () => { + const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]'); + button.simulate('click'); + expect(onSave).toHaveBeenCalled(); + }); + + it('calls onClose callback when Cancel is pressed', () => { + const button = wrapper.find('[data-test-subj="GenericConfirmationModalCancel"]'); + button.simulate('click'); + expect(onClose).toHaveBeenCalled(); + }); + + it('disables the Save button when the input is empty', () => { + const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]'); + expect(button.prop('disabled')).toEqual(true); + }); + + it('disables the Save button when the input is not equal to the target', () => { + const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]'); + input.prop('onChange')({ + target: { + value: 'NOT_GOOD', + }, + }); + + const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]'); + expect(button.prop('disabled')).toEqual(true); + }); + + it('enables the Save button when the current input equals the target prop', () => { + const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]'); + input.prop('onChange')({ + target: { + value: 'DISABLE', + }, + }); + const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]'); + expect(button.prop('disabled')).toEqual(false); + }); + + it('is not case sensitive', () => { + const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]'); + input.prop('onChange')({ + target: { + value: 'diSable', + }, + }); + const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]'); + expect(button.prop('disabled')).toEqual(false); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx new file mode 100644 index 0000000000000..6d802b0c5cfaf --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx @@ -0,0 +1,95 @@ +/* + * 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 React, { ReactNode, useState } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiFormRow, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +interface GenericConfirmationModalProps { + description: ReactNode; + subheading: ReactNode; + target: string; + title: string; + onClose(): void; + onSave(): void; +} + +export const GenericConfirmationModal: React.FC = ({ + description, + onClose, + onSave, + subheading, + target, + title, +}) => { + const [inputValue, setInputValue] = useState(''); + + const onConfirm = () => { + setInputValue(''); + onSave(); + }; + + return ( + + + {title} + + + +

    + {subheading} +

    +

    {description}

    +
    + + + setInputValue(e.target.value)} + /> + +
    + + + {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.modal.cancel', { + defaultMessage: 'Cancel', + })} + + + {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.modal.save', { + defaultMessage: 'Save setting', + })} + + +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx new file mode 100644 index 0000000000000..d77089d52fbdd --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx @@ -0,0 +1,129 @@ +/* + * 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 '../../../../__mocks__/kea.mock'; +import { setMockActions, setMockValues } from '../../../../__mocks__'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { LogRetentionConfirmationModal } from './log_retention_confirmation_modal'; +import { LogRetentionOptions } from './types'; +import { GenericConfirmationModal } from './generic_confirmation_modal'; + +describe('', () => { + const actions = { + closeModals: jest.fn(), + saveLogRetention: jest.fn(), + }; + + const values = { + openedModal: null, + logRetention: { + analytics: { + enabled: true, + retentionPolicy: { + isDefault: true, + minAgeDays: 180, + }, + }, + api: { + enabled: true, + retentionPolicy: { + isDefault: true, + minAgeDays: 7, + }, + }, + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockActions(actions); + setMockValues(values); + }); + + it('renders nothing by default', () => { + const logRetentionPanel = shallow(); + expect(logRetentionPanel.isEmptyRender()).toBe(true); + }); + + describe('analytics', () => { + it('renders the Analytics panel when openedModal is set to Analytics', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.Analytics, + }); + + const logRetentionPanel = shallow(); + expect( + logRetentionPanel.find('[data-test-subj="AnalyticsLogRetentionConfirmationModal"]').length + ).toBe(1); + }); + + it('calls saveLogRetention on save when showing analytics', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.Analytics, + }); + + const logRetentionPanel = shallow(); + const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal); + genericConfirmationModal.prop('onSave')(); + expect(actions.saveLogRetention).toHaveBeenCalledWith(LogRetentionOptions.Analytics, false); + }); + + it('calls closeModals on close', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.Analytics, + }); + + const logRetentionPanel = shallow(); + const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal); + genericConfirmationModal.prop('onClose')(); + expect(actions.closeModals).toHaveBeenCalled(); + }); + }); + + describe('api', () => { + it('renders the API panel when openedModal is set to API', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.API, + }); + + const logRetentionPanel = shallow(); + expect( + logRetentionPanel.find('[data-test-subj="APILogRetentionConfirmationModal"]').length + ).toBe(1); + }); + + it('calls saveLogRetention on save when showing api', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.API, + }); + + const logRetentionPanel = shallow(); + const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal); + genericConfirmationModal.prop('onSave')(); + expect(actions.saveLogRetention).toHaveBeenCalledWith(LogRetentionOptions.API, false); + }); + + it('calls closeModals on close', () => { + setMockValues({ + ...values, + openedModal: LogRetentionOptions.API, + }); + + const logRetentionPanel = shallow(); + const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal); + genericConfirmationModal.prop('onClose')(); + expect(actions.closeModals).toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx new file mode 100644 index 0000000000000..67421bb78fa71 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx @@ -0,0 +1,137 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { EuiTextColor, EuiOverlayMask } from '@elastic/eui'; +import { useActions, useValues } from 'kea'; + +import { GenericConfirmationModal } from './generic_confirmation_modal'; +import { LogRetentionLogic } from './log_retention_logic'; + +import { LogRetentionOptions } from './types'; + +export const LogRetentionConfirmationModal: React.FC = () => { + const CANNOT_BE_RECOVERED_TEXT = i18n.translate( + 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.recovery', + { + defaultMessage: 'Once your data has been removed, it cannot be recovered.', + } + ); + + const DISABLE_TEXT = i18n.translate( + 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.disable', + { + defaultMessage: 'DISABLE', + } + ); + + const { closeModals, saveLogRetention } = useActions(LogRetentionLogic); + + const { logRetention, openedModal } = useValues(LogRetentionLogic); + + if (openedModal === null) { + return null; + } + + return ( + + {openedModal === LogRetentionOptions.Analytics && ( + +

    + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.analytics.description', + { + defaultMessage: + 'When disabling Analytics Logs, all your engines will immediately stop indexing Analytics Logs. Your existing data will be deleted in accordance with the storage timeframes outlined above.', + } + )} +

    +

    + + {CANNOT_BE_RECOVERED_TEXT} + +

    + + } + target={DISABLE_TEXT} + onClose={closeModals} + onSave={() => saveLogRetention(LogRetentionOptions.Analytics, false)} + /> + )} + {openedModal === LogRetentionOptions.API && ( + +

    + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.api.description', + { + defaultMessage: + 'When disabling API Logs, all your engines will immediately stop indexing API Logs. Your existing data will be deleted in accordance with the storage timeframes outlined above.', + } + )} +

    +

    + + {CANNOT_BE_RECOVERED_TEXT} + +

    + + } + target={DISABLE_TEXT} + onClose={closeModals} + onSave={() => saveLogRetention(LogRetentionOptions.API, false)} + /> + )} +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx index 7bd3683919bc1..dbd6627a3b9ce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; + import { EuiPageHeader, EuiPageHeaderSection, @@ -16,6 +17,7 @@ import { import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; import { LogRetentionPanel } from './log_retention/log_retention_panel'; +import { LogRetentionConfirmationModal } from './log_retention/log_retention_confirmation_modal'; import { SETTINGS_TITLE } from './'; @@ -33,6 +35,7 @@ export const Settings: React.FC = () => { + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx index 0e929c9191e0f..7f638c64b445d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { setMockValues } from '../__mocks__/kea.mock'; +import { rerender } from '../__mocks__'; import { EnterpriseSearch } from './'; import { SetupGuide } from './components/setup_guide'; @@ -40,7 +41,7 @@ describe('EnterpriseSearch', () => { errorConnecting: true, config: { host: '' }, }); - wrapper.setProps({}); // Re-render + rerender(wrapper); expect(wrapper.find(ErrorConnecting)).toHaveLength(0); expect(wrapper.find(ProductSelector)).toHaveLength(1); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts index 8792c26f9bad4..a109640f09bbe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts @@ -7,4 +7,9 @@ export { FlashMessages } from './flash_messages'; export { FlashMessagesLogic, IFlashMessage, mountFlashMessagesLogic } from './flash_messages_logic'; export { flashAPIErrors } from './handle_api_errors'; -export { setSuccessMessage, setErrorMessage, setQueuedSuccessMessage } from './set_message_helpers'; +export { + setSuccessMessage, + setErrorMessage, + setQueuedSuccessMessage, + setQueuedErrorMessage, +} from './set_message_helpers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts index 46027fdfb22b1..c5ee8200c490d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts @@ -15,6 +15,7 @@ import { setSuccessMessage, setErrorMessage, setQueuedSuccessMessage, + setQueuedErrorMessage, } from './'; describe('Flash Message Helpers', () => { @@ -56,4 +57,15 @@ describe('Flash Message Helpers', () => { }, ]); }); + + it('setQueuedErrorMessage()', () => { + setQueuedErrorMessage(message); + + expect(FlashMessagesLogic.values.queuedMessages).toEqual([ + { + message, + type: 'error', + }, + ]); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts index 6abb540b7c14b..cb73d54fd7b1e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts @@ -26,3 +26,10 @@ export const setQueuedSuccessMessage = (message: string) => { message, }); }; + +export const setQueuedErrorMessage = (message: string) => { + FlashMessagesLogic.actions.setQueuedMessages({ + type: 'error', + message, + }); +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts index 3bfe8abf8a2df..b7009c1b76fbc 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts @@ -6,7 +6,7 @@ import { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__'; -import { registerEnginesRoute } from './engines'; +import { registerEnginesRoutes } from './engines'; describe('engine routes', () => { describe('GET /api/app_search/engines', () => { @@ -31,7 +31,7 @@ describe('engine routes', () => { payload: 'query', }); - registerEnginesRoute({ + registerEnginesRoutes({ ...mockDependencies, router: mockRouter.router, }); @@ -107,4 +107,30 @@ describe('engine routes', () => { }); }); }); + + describe('GET /api/app_search/engines/{name}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/app_search/engines/{name}', + payload: 'params', + }); + + registerEnginesRoutes({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request to enterprise search', () => { + mockRouter.callRoute({ params: { name: 'some-engine' } }); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/as/engines/some-engine/details', + }); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts index 6cbd60e494fe3..2c4e235556ae3 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts @@ -14,7 +14,7 @@ interface EnginesResponse { meta: { page: { total_results: number } }; } -export function registerEnginesRoute({ +export function registerEnginesRoutes({ router, enterpriseSearchRequestHandler, }: RouteDependencies) { @@ -43,4 +43,21 @@ export function registerEnginesRoute({ })(context, request, response); } ); + + // Single engine endpoints + router.get( + { + path: '/api/app_search/engines/{name}', + validate: { + params: schema.object({ + name: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/as/engines/${request.params.name}/details`, + })(context, request, response); + } + ); } diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts index 7ce3ee9654f42..faf74203cf17d 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts @@ -6,12 +6,12 @@ import { RouteDependencies } from '../../plugin'; -import { registerEnginesRoute } from './engines'; +import { registerEnginesRoutes } from './engines'; import { registerCredentialsRoutes } from './credentials'; import { registerSettingsRoutes } from './settings'; export const registerAppSearchRoutes = (dependencies: RouteDependencies) => { - registerEnginesRoute(dependencies); + registerEnginesRoutes(dependencies); registerCredentialsRoutes(dependencies); registerSettingsRoutes(dependencies); }; diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts index 130898806ad51..1df7a1d6875a6 100644 --- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts @@ -8,8 +8,10 @@ import { RouteDependencies } from '../../plugin'; import { registerOverviewRoute } from './overview'; import { registerGroupsRoutes } from './groups'; +import { registerSourcesRoutes } from './sources'; export const registerWorkplaceSearchRoutes = (dependencies: RouteDependencies) => { registerOverviewRoute(dependencies); registerGroupsRoutes(dependencies); + registerSourcesRoutes(dependencies); }; diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts new file mode 100644 index 0000000000000..9f2b4121351bc --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts @@ -0,0 +1,828 @@ +/* + * 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 { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__'; + +import { + registerAccountSourceRoute, + registerAccountCreateSourceRoute, + registerAccountSourceDocumentsRoute, + registerAccountSourceFederatedSummaryRoute, + registerAccountSourceReauthPrepareRoute, + registerAccountSourceSettingsRoute, + registerAccountPreSourceRoute, + registerAccountPrepareSourcesRoute, + registerOrgSourceRoute, + registerOrgCreateSourceRoute, + registerOrgSourceDocumentsRoute, + registerOrgSourceFederatedSummaryRoute, + registerOrgSourceReauthPrepareRoute, + registerOrgSourceSettingsRoute, + registerOrgPreSourceRoute, + registerOrgPrepareSourcesRoute, + registerOrgSourceOauthConfigurationsRoute, + registerOrgSourceOauthConfigurationRoute, +} from './sources'; + +const mockConfig = { + base_url: 'http://search', + client_id: 'asd', + client_secret: '234KKDFksdf22', + service_type: 'zendesk', + private_key: 'gsdfgsdfg', + public_key: 'gadfgsdfgss', + consumer_key: 'sf44argsr', +}; + +describe('sources routes', () => { + describe('GET /api/workplace_search/account/sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/account/sources/{id}', + payload: 'params', + }); + + registerAccountSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123', + }); + }); + }); + + describe('DELETE /api/workplace_search/account/sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'delete', + path: '/api/workplace_search/account/sources/{id}', + payload: 'params', + }); + + registerAccountSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123', + }); + }); + }); + + describe('POST /api/workplace_search/account/create_source', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/account/create_source', + payload: 'body', + }); + + registerAccountCreateSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + body: { + service_type: 'google', + name: 'Google', + login: 'user', + password: 'changeme', + organizations: 'swiftype', + indexPermissions: true, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/form_create', + body: mockRequest.body, + }); + }); + }); + + describe('POST /api/workplace_search/account/sources/{id}/documents', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/account/sources/{id}/documents', + payload: 'body', + }); + + registerAccountSourceDocumentsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { id: '123' }, + body: { + query: 'foo', + page: { + current: 1, + size: 10, + total_pages: 1, + total_results: 10, + }, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123/documents', + body: mockRequest.body, + }); + }); + }); + + describe('GET /api/workplace_search/account/sources/{id}/federated_summary', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/account/sources/{id}/federated_summary', + payload: 'params', + }); + + registerAccountSourceFederatedSummaryRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123/federated_summary', + }); + }); + }); + + describe('GET /api/workplace_search/account/sources/{id}/reauth_prepare', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/account/sources/{id}/reauth_prepare', + payload: 'params', + }); + + registerAccountSourceReauthPrepareRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123/reauth_prepare', + }); + }); + }); + + describe('PATCH /api/workplace_search/account/sources/{id}/settings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'patch', + path: '/api/workplace_search/account/sources/{id}/settings', + payload: 'body', + }); + + registerAccountSourceSettingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { id: '123' }, + body: { + query: { + content_source: { + name: 'foo', + }, + }, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/sources/123/settings', + body: mockRequest.body, + }); + }); + }); + + describe('GET /api/workplace_search/account/pre_sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/account/pre_sources/{id}', + payload: 'params', + }); + + registerAccountPreSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/pre_content_sources/123', + }); + }); + }); + + describe('GET /api/workplace_search/account/sources/{service_type}/prepare', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/account/sources/{service_type}/prepare', + payload: 'params', + }); + + registerAccountPrepareSourcesRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/pre_content_sources/zendesk', + }); + }); + }); + + describe('GET /api/workplace_search/org/sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/sources/{id}', + payload: 'params', + }); + + registerOrgSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123', + }); + }); + }); + + describe('DELETE /api/workplace_search/org/sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'delete', + path: '/api/workplace_search/org/sources/{id}', + payload: 'params', + }); + + registerOrgSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123', + }); + }); + }); + + describe('POST /api/workplace_search/org/create_source', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/org/create_source', + payload: 'body', + }); + + registerOrgCreateSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + body: { + service_type: 'google', + name: 'Google', + login: 'user', + password: 'changeme', + organizations: 'swiftype', + indexPermissions: true, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/form_create', + body: mockRequest.body, + }); + }); + }); + + describe('POST /api/workplace_search/org/sources/{id}/documents', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/org/sources/{id}/documents', + payload: 'body', + }); + + registerOrgSourceDocumentsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { id: '123' }, + body: { + query: 'foo', + page: { + current: 1, + size: 10, + total_pages: 1, + total_results: 10, + }, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123/documents', + body: mockRequest.body, + }); + }); + }); + + describe('GET /api/workplace_search/org/sources/{id}/federated_summary', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/sources/{id}/federated_summary', + payload: 'params', + }); + + registerOrgSourceFederatedSummaryRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123/federated_summary', + }); + }); + }); + + describe('GET /api/workplace_search/org/sources/{id}/reauth_prepare', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/sources/{id}/reauth_prepare', + payload: 'params', + }); + + registerOrgSourceReauthPrepareRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123/reauth_prepare', + }); + }); + }); + + describe('PATCH /api/workplace_search/org/sources/{id}/settings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'patch', + path: '/api/workplace_search/org/sources/{id}/settings', + payload: 'body', + }); + + registerOrgSourceSettingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + const mockRequest = { + params: { id: '123' }, + body: { + query: { + content_source: { + name: 'foo', + }, + }, + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/sources/123/settings', + body: mockRequest.body, + }); + }); + }); + + describe('GET /api/workplace_search/org/pre_sources/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/pre_sources/{id}', + payload: 'params', + }); + + registerOrgPreSourceRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + id: '123', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/pre_content_sources/123', + }); + }); + }); + + describe('GET /api/workplace_search/org/sources/{service_type}/prepare', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/sources/{service_type}/prepare', + payload: 'params', + }); + + registerOrgPrepareSourcesRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/pre_content_sources/zendesk', + }); + }); + }); + + describe('GET /api/workplace_search/org/settings/connectors', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/settings/connectors', + }); + + registerOrgSourceOauthConfigurationsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + mockRouter.callRoute({}); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/settings/connectors', + }); + }); + }); + + describe('GET /api/workplace_search/org/settings/connectors/{service_type}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/settings/connectors/{service_type}', + payload: 'params', + }); + + registerOrgSourceOauthConfigurationRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/settings/connectors/zendesk', + }); + }); + }); + + describe('POST /api/workplace_search/org/settings/connectors/{service_type}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/org/settings/connectors/{service_type}', + payload: 'body', + }); + + registerOrgSourceOauthConfigurationRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + body: mockConfig, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/settings/connectors/zendesk', + body: mockRequest.body, + }); + }); + }); + + describe('PUT /api/workplace_search/org/settings/connectors/{service_type}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'put', + path: '/api/workplace_search/org/settings/connectors/{service_type}', + payload: 'body', + }); + + registerOrgSourceOauthConfigurationRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + body: mockConfig, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/settings/connectors/zendesk', + body: mockRequest.body, + }); + }); + }); + + describe('DELETE /api/workplace_search/org/settings/connectors/{service_type}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('creates a request handler', () => { + mockRouter = new MockRouter({ + method: 'delete', + path: '/api/workplace_search/org/settings/connectors/{service_type}', + payload: 'params', + }); + + registerOrgSourceOauthConfigurationRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + + const mockRequest = { + params: { + service_type: 'zendesk', + }, + }; + + mockRouter.callRoute(mockRequest); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/settings/connectors/zendesk', + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts new file mode 100644 index 0000000000000..f496628d02379 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts @@ -0,0 +1,543 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../plugin'; + +const pageSchema = schema.object({ + current: schema.number(), + size: schema.number(), + total_pages: schema.number(), + total_results: schema.number(), +}); + +const oAuthConfigSchema = schema.object({ + base_url: schema.maybe(schema.string()), + client_id: schema.maybe(schema.string()), + client_secret: schema.maybe(schema.string()), + service_type: schema.string(), + private_key: schema.string(), + public_key: schema.string(), + consumer_key: schema.string(), +}); + +export function registerAccountSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/account/sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}`, + })(context, request, response); + } + ); + + router.delete( + { + path: '/api/workplace_search/account/sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}`, + })(context, request, response); + } + ); +} + +export function registerAccountCreateSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.post( + { + path: '/api/workplace_search/account/create_source', + validate: { + body: schema.object({ + service_type: schema.string(), + name: schema.maybe(schema.string()), + login: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + organizations: schema.maybe(schema.arrayOf(schema.string())), + indexPermissions: schema.boolean(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: '/ws/sources/form_create', + body: request.body, + })(context, request, response); + } + ); +} + +export function registerAccountSourceDocumentsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.post( + { + path: '/api/workplace_search/account/sources/{id}/documents', + validate: { + body: schema.object({ + query: schema.string(), + page: pageSchema, + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}/documents`, + body: request.body, + })(context, request, response); + } + ); +} + +export function registerAccountSourceFederatedSummaryRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/account/sources/{id}/federated_summary', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}/federated_summary`, + })(context, request, response); + } + ); +} + +export function registerAccountSourceReauthPrepareRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/account/sources/{id}/reauth_prepare', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}/reauth_prepare`, + })(context, request, response); + } + ); +} + +export function registerAccountSourceSettingsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.patch( + { + path: '/api/workplace_search/account/sources/{id}/settings', + validate: { + body: schema.object({ + query: schema.object({ + content_source: schema.object({ + name: schema.string(), + }), + }), + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/sources/${request.params.id}/settings`, + body: request.body, + })(context, request, response); + } + ); +} + +export function registerAccountPreSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/account/pre_sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/pre_content_sources/${request.params.id}`, + })(context, request, response); + } + ); +} + +export function registerAccountPrepareSourcesRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/account/sources/{service_type}/prepare', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/pre_content_sources/${request.params.service_type}`, + })(context, request, response); + } + ); +} + +export function registerOrgSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}`, + })(context, request, response); + } + ); + + router.delete( + { + path: '/api/workplace_search/org/sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}`, + })(context, request, response); + } + ); +} + +export function registerOrgCreateSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.post( + { + path: '/api/workplace_search/org/create_source', + validate: { + body: schema.object({ + service_type: schema.string(), + name: schema.maybe(schema.string()), + login: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + organizations: schema.maybe(schema.arrayOf(schema.string())), + indexPermissions: schema.boolean(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/sources/form_create', + body: request.body, + })(context, request, response); + } + ); +} + +export function registerOrgSourceDocumentsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.post( + { + path: '/api/workplace_search/org/sources/{id}/documents', + validate: { + body: schema.object({ + query: schema.string(), + page: pageSchema, + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}/documents`, + body: request.body, + })(context, request, response); + } + ); +} + +export function registerOrgSourceFederatedSummaryRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/sources/{id}/federated_summary', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}/federated_summary`, + })(context, request, response); + } + ); +} + +export function registerOrgSourceReauthPrepareRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/sources/{id}/reauth_prepare', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}/reauth_prepare`, + })(context, request, response); + } + ); +} + +export function registerOrgSourceSettingsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.patch( + { + path: '/api/workplace_search/org/sources/{id}/settings', + validate: { + body: schema.object({ + query: schema.object({ + content_source: schema.object({ + name: schema.string(), + }), + }), + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/sources/${request.params.id}/settings`, + body: request.body, + })(context, request, response); + } + ); +} + +export function registerOrgPreSourceRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/pre_sources/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/pre_content_sources/${request.params.id}`, + })(context, request, response); + } + ); +} + +export function registerOrgPrepareSourcesRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/sources/{service_type}/prepare', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/pre_content_sources/${request.params.service_type}`, + })(context, request, response); + } + ); +} + +export function registerOrgSourceOauthConfigurationsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/settings/connectors', + validate: false, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/settings/connectors', + })(context, request, response); + } + ); +} + +export function registerOrgSourceOauthConfigurationRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/settings/connectors/{service_type}', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/settings/connectors/${request.params.service_type}`, + })(context, request, response); + } + ); + + router.post( + { + path: '/api/workplace_search/org/settings/connectors/{service_type}', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + body: oAuthConfigSchema, + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/settings/connectors/${request.params.service_type}`, + body: request.body, + })(context, request, response); + } + ); + + router.put( + { + path: '/api/workplace_search/org/settings/connectors/{service_type}', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + body: oAuthConfigSchema, + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/settings/connectors/${request.params.service_type}`, + body: request.body, + })(context, request, response); + } + ); + + router.delete( + { + path: '/api/workplace_search/org/settings/connectors/{service_type}', + validate: { + params: schema.object({ + service_type: schema.string(), + }), + }, + }, + async (context, request, response) => { + return enterpriseSearchRequestHandler.createRequest({ + path: `/ws/org/settings/connectors/${request.params.service_type}`, + })(context, request, response); + } + ); +} + +export const registerSourcesRoutes = (dependencies: RouteDependencies) => { + registerAccountSourceRoute(dependencies); + registerAccountCreateSourceRoute(dependencies); + registerAccountSourceDocumentsRoute(dependencies); + registerAccountSourceFederatedSummaryRoute(dependencies); + registerAccountSourceReauthPrepareRoute(dependencies); + registerAccountSourceSettingsRoute(dependencies); + registerAccountPreSourceRoute(dependencies); + registerAccountPrepareSourcesRoute(dependencies); + registerOrgSourceRoute(dependencies); + registerOrgCreateSourceRoute(dependencies); + registerOrgSourceDocumentsRoute(dependencies); + registerOrgSourceFederatedSummaryRoute(dependencies); + registerOrgSourceReauthPrepareRoute(dependencies); + registerOrgSourceSettingsRoute(dependencies); + registerOrgPreSourceRoute(dependencies); + registerOrgPrepareSourcesRoute(dependencies); + registerOrgSourceOauthConfigurationsRoute(dependencies); + registerOrgSourceOauthConfigurationRoute(dependencies); +}; diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index c5fc208bfb2dc..5d79d41b7a631 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -30,7 +30,7 @@ export type InstallSource = 'registry' | 'upload'; export type EpmPackageInstallStatus = 'installed' | 'installing'; -export type DetailViewPanelName = 'overview' | 'usages' | 'settings'; +export type DetailViewPanelName = 'overview' | 'policies' | 'settings'; export type ServiceName = 'kibana' | 'elasticsearch'; export type AgentAssetType = typeof agentAssetTypes; export type AssetType = KibanaAssetType | ElasticsearchAssetType | ValueOf; @@ -47,7 +47,7 @@ export enum KibanaAssetType { } /* - Enum of saved object types that are allowed to be installed + Enum of saved object types that are allowed to be installed */ export enum KibanaSavedObjectType { dashboard = 'dashboard', diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/header.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/header.tsx index e0623108e7d39..4a0a2a1b28033 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/header.tsx @@ -36,6 +36,7 @@ export interface HeaderProps { rightColumn?: JSX.Element; rightColumnGrow?: EuiFlexItemProps['grow']; tabs?: EuiTabProps[]; + tabsClassName?: string; 'data-test-subj'?: string; } @@ -54,6 +55,7 @@ export const Header: React.FC = ({ rightColumnGrow, tabs, maxWidth, + tabsClassName, 'data-test-subj': dataTestSubj, }) => ( @@ -67,7 +69,7 @@ export const Header: React.FC = ({ {tabs ? ( - + {tabs.map((props) => ( {props.name} diff --git a/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx b/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx index 58ca989850bf1..4b21a15a73645 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx @@ -12,14 +12,14 @@ const Page = styled(EuiPage)` background: ${(props) => props.theme.eui.euiColorEmptyShade}; `; -interface Props extends HeaderProps { +export interface WithHeaderLayoutProps extends HeaderProps { restrictWidth?: number; restrictHeaderWidth?: number; 'data-test-subj'?: string; children?: React.ReactNode; } -export const WithHeaderLayout: React.FC = ({ +export const WithHeaderLayout: React.FC = ({ restrictWidth, restrictHeaderWidth, children, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx index 0661567c7166b..7004a602627c1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx @@ -10,6 +10,7 @@ import { usePackageIconType, UsePackageIconType } from '../../../hooks'; import { Loading } from '../../../components'; const PanelWrapper = styled.div` + // NOTE: changes to the width here will impact navigation tabs page layout under integration package details width: ${(props) => parseFloat(props.theme.eui.euiSize) * 6 + parseFloat(props.theme.eui.spacerSizes.xl) * 2}px; height: 1px; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx index 0443915d8224c..40346cde7f50f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx @@ -7,12 +7,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { DEFAULT_PANEL, DetailParams } from '.'; +import { DetailParams } from '.'; import { PackageInfo } from '../../../../types'; import { AssetsFacetGroup } from '../../components/assets_facet_group'; import { CenterColumn, LeftColumn, RightColumn } from './layout'; import { OverviewPanel } from './overview_panel'; -import { SideNavLinks } from './side_nav_links'; import { PackagePoliciesPanel } from './package_policies_panel'; import { SettingsPanel } from './settings_panel'; @@ -31,12 +30,9 @@ const ContentFlexGroup = styled(EuiFlexGroup)` `; export function Content(props: ContentProps) { - const { name, panel, version } = props; return ( - - - + @@ -62,7 +58,7 @@ export function ContentPanel(props: ContentPanelProps) { latestVersion={latestVersion} /> ); - case 'usages': + case 'policies': return ; case 'overview': default: diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx index 7e7958ce91afe..2535a53589bd9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx @@ -20,7 +20,7 @@ import { EuiDescriptionListTitle, EuiDescriptionListDescription, } from '@elastic/eui'; -import { DetailViewPanelName, InstallStatus, PackageInfo } from '../../../../types'; +import { DetailViewPanelName, entries, InstallStatus, PackageInfo } from '../../../../types'; import { Loading, Error } from '../../../../components'; import { useGetPackageInfoByKey, @@ -34,6 +34,7 @@ import { IconPanel, LoadingIconPanel } from '../../components/icon_panel'; import { RELEASE_BADGE_LABEL, RELEASE_BADGE_DESCRIPTION } from '../../components/release_badge'; import { UpdateIcon } from '../../components/icons'; import { Content } from './content'; +import { WithHeaderLayoutProps } from '../../../../layouts/with_header'; export const DEFAULT_PANEL: DetailViewPanelName = 'overview'; @@ -42,6 +43,28 @@ export interface DetailParams { panel?: DetailViewPanelName; } +const PanelDisplayNames: Record = { + overview: i18n.translate('xpack.fleet.epm.packageDetailsNav.overviewLinkText', { + defaultMessage: 'Overview', + }), + policies: i18n.translate('xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText', { + defaultMessage: 'Policies', + }), + settings: i18n.translate('xpack.fleet.epm.packageDetailsNav.settingsLinkText', { + defaultMessage: 'Settings', + }), +}; + +const DetailWrapper = styled.div` + // Class name here is in sync with 'PanelWrapper' in 'IconPanel' component + .shiftNavTabs { + margin-left: ${(props) => + parseFloat(props.theme.eui.euiSize) * 6 + + parseFloat(props.theme.eui.spacerSizes.xl) * 2 + + parseFloat(props.theme.eui.spacerSizes.l)}px; + } +`; + const Divider = styled.div` width: 0; height: 100%; @@ -216,28 +239,57 @@ export function Detail() { [getHref, hasWriteCapabilites, packageInfo, pkgkey, updateAvailable] ); + const tabs = useMemo(() => { + if (!packageInfo) { + return []; + } + + return (entries(PanelDisplayNames) + .filter(([panelId]) => { + return ( + panelId !== 'policies' || + (packageInfoData?.response.status === InstallStatus.installed && false) // Remove `false` when ready to implement policies tab + ); + }) + .map(([panelId, display]) => { + return { + id: panelId, + name: display, + isSelected: panelId === panel, + href: getHref('integration_details', { + pkgkey: `${packageInfo?.name}-${packageInfo?.version}`, + panel: panelId, + }), + }; + }) as unknown) as WithHeaderLayoutProps['tabs']; + }, [getHref, packageInfo, packageInfoData?.response?.status, panel]); + return ( - - {packageInfo ? : null} - {packageInfoError ? ( - - } - error={packageInfoError} - /> - ) : isLoading || !packageInfo ? ( - - ) : ( - - )} - + + + {packageInfo ? : null} + {packageInfoError ? ( + + } + error={packageInfoError} + /> + ) : isLoading || !packageInfo ? ( + + ) : ( + + )} + + ); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/side_nav_links.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/side_nav_links.tsx deleted file mode 100644 index 1d3d5009f599f..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/side_nav_links.tsx +++ /dev/null @@ -1,54 +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 React, { Fragment } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { PackageInfo, entries, DetailViewPanelName, InstallStatus } from '../../../../types'; -import { useLink } from '../../../../hooks'; -import { useGetPackageInstallStatus } from '../../hooks'; - -export type NavLinkProps = Pick & { - active: DetailViewPanelName; -}; - -const PanelDisplayNames: Record = { - overview: i18n.translate('xpack.fleet.epm.packageDetailsNav.overviewLinkText', { - defaultMessage: 'Overview', - }), - usages: i18n.translate('xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText', { - defaultMessage: 'Usages', - }), - settings: i18n.translate('xpack.fleet.epm.packageDetailsNav.settingsLinkText', { - defaultMessage: 'Settings', - }), -}; - -export function SideNavLinks({ name, version, active }: NavLinkProps) { - const { getHref } = useLink(); - const getPackageInstallStatus = useGetPackageInstallStatus(); - const packageInstallStatus = getPackageInstallStatus(name); - - return ( - - {entries(PanelDisplayNames).map(([panel, display]) => { - // Don't display usages tab as we haven't implemented this yet - // FIXME: Restore when we implement usages page - if (panel === 'usages' && (true || packageInstallStatus.status !== InstallStatus.installed)) - return null; - - return ( -
    - - {active === panel ? {display} : display} - -
    - ); - })} -
    - ); -} diff --git a/x-pack/plugins/fleet/server/services/epm/archive/index.ts b/x-pack/plugins/fleet/server/services/epm/archive/index.ts index 28f635e9412ae..810740d697fcb 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/index.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ArchivePackage } from '../../../../common/types'; +import { ArchivePackage, AssetParts } from '../../../../common/types'; import { PackageInvalidArchiveError, PackageUnsupportedMediaTypeError } from '../../../errors'; import { + cacheGet, cacheSet, cacheDelete, getArchiveFilelist, @@ -100,3 +101,40 @@ export const deletePackageCache = (name: string, version: string) => { // this has been populated in unpackArchiveToCache() paths?.forEach((path) => cacheDelete(path)); }; + +export function getPathParts(path: string): AssetParts { + let dataset; + + let [pkgkey, service, type, file] = path.split('/'); + + // if it's a data stream + if (service === 'data_stream') { + // save the dataset name + dataset = type; + // drop the `data_stream/dataset-name` portion & re-parse + [pkgkey, service, type, file] = path.replace(`data_stream/${dataset}/`, '').split('/'); + } + + // This is to cover for the fields.yml files inside the "fields" directory + if (file === undefined) { + file = type; + type = 'fields'; + service = ''; + } + + return { + pkgkey, + service, + type, + file, + dataset, + path, + } as AssetParts; +} + +export function getAsset(key: string) { + const buffer = cacheGet(key); + if (buffer === undefined) throw new Error(`Cannot find asset ${key}`); + + return buffer; +} diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index c5253e4902cab..46c0729a650d0 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -5,15 +5,15 @@ */ import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types'; -import * as Registry from '../../registry'; +import { getAsset, getPathParts } from '../../archive'; export async function installILMPolicy(paths: string[], callCluster: CallESAsCurrentUser) { const ilmPaths = paths.filter((path) => isILMPolicy(path)); if (!ilmPaths.length) return; await Promise.all( ilmPaths.map(async (path) => { - const body = Registry.getAsset(path).toString('utf-8'); - const { file } = Registry.pathParts(path); + const body = getAsset(path).toString('utf-8'); + const { file } = getPathParts(path); const name = file.substr(0, file.lastIndexOf('.')); try { await callCluster('transport.request', { @@ -28,7 +28,7 @@ export async function installILMPolicy(paths: string[], callCluster: CallESAsCur ); } const isILMPolicy = (path: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return pathParts.type === ElasticsearchAssetType.ilmPolicy; }; export async function policyExists( diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts index 58abdeb0d443d..c5c9e8ac2c01b 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts @@ -11,7 +11,8 @@ import { ElasticsearchAssetType, InstallablePackage, } from '../../../../types'; -import * as Registry from '../../registry'; +import { ArchiveEntry } from '../../registry'; +import { getAsset, getPathParts } from '../../archive'; import { CallESAsCurrentUser } from '../../../../types'; import { saveInstalledEsRefs } from '../../packages/install'; import { getInstallationObject } from '../../packages'; @@ -127,7 +128,7 @@ export async function installPipelinesForDataStream({ dataStream, packageVersion: pkgVersion, }); - const content = Registry.getAsset(path).toString('utf-8'); + const content = getAsset(path).toString('utf-8'); pipelines.push({ name, nameForInstallation, @@ -192,10 +193,10 @@ async function installPipeline({ return { id: pipeline.nameForInstallation, type: ElasticsearchAssetType.ingestPipeline }; } -const isDirectory = ({ path }: Registry.ArchiveEntry) => path.endsWith('/'); +const isDirectory = ({ path }: ArchiveEntry) => path.endsWith('/'); const isDataStreamPipeline = (path: string, dataStreamDataset: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return ( !isDirectory({ path }) && pathParts.type === ElasticsearchAssetType.ingestPipeline && @@ -204,7 +205,7 @@ const isDataStreamPipeline = (path: string, dataStreamDataset: string) => { ); }; const isPipeline = (path: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return pathParts.type === ElasticsearchAssetType.ingestPipeline; }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index 25d412b685904..199026da30c11 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -17,7 +17,7 @@ import { CallESAsCurrentUser } from '../../../../types'; import { Field, loadFieldsFromYaml, processFields } from '../../fields/field'; import { getPipelineNameForInstallation } from '../ingest_pipeline/install'; import { generateMappings, generateTemplateName, getTemplate } from './template'; -import * as Registry from '../../registry'; +import { getAsset, getPathParts } from '../../archive'; import { removeAssetsFromInstalledEsByType, saveInstalledEsRefs } from '../../packages/install'; export const installTemplates = async ( @@ -76,9 +76,9 @@ export const installTemplates = async ( const installPreBuiltTemplates = async (paths: string[], callCluster: CallESAsCurrentUser) => { const templatePaths = paths.filter((path) => isTemplate(path)); const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = Registry.pathParts(path); + const { file } = getPathParts(path); const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse(Registry.getAsset(path).toString('utf8')); + const content = JSON.parse(getAsset(path).toString('utf8')); let templateAPIPath = '_template'; // v2 index templates need to be installed through the new API endpoint. @@ -121,9 +121,9 @@ const installPreBuiltComponentTemplates = async ( ) => { const templatePaths = paths.filter((path) => isComponentTemplate(path)); const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = Registry.pathParts(path); + const { file } = getPathParts(path); const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse(Registry.getAsset(path).toString('utf8')); + const content = JSON.parse(getAsset(path).toString('utf8')); const callClusterParams: { method: string; @@ -151,12 +151,12 @@ const installPreBuiltComponentTemplates = async ( }; const isTemplate = (path: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return pathParts.type === ElasticsearchAssetType.indexTemplate; }; const isComponentTemplate = (path: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return pathParts.type === ElasticsearchAssetType.componentTemplate; }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/common.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/common.ts index 46f36dba96747..764e1b51f1bca 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/common.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/common.ts @@ -4,8 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as Registry from '../../registry'; - -export const getAsset = (path: string): Buffer => { - return Registry.getAsset(path); -}; +export { getAsset } from '../../archive'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index 1002eedc48740..9da5e8cd0a937 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -7,7 +7,7 @@ import { SavedObjectsClientContract } from 'kibana/server'; import { saveInstalledEsRefs } from '../../packages/install'; -import * as Registry from '../../registry'; +import { getPathParts } from '../../archive'; import { ElasticsearchAssetType, EsAssetReference, @@ -104,7 +104,7 @@ export const installTransform = async ( }; const isTransform = (path: string) => { - const pathParts = Registry.pathParts(path); + const pathParts = getPathParts(path); return !path.endsWith('/') && pathParts.type === ElasticsearchAssetType.transform; }; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index e7b251ef133c5..fe93ed84b32f2 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -10,7 +10,7 @@ import { SavedObjectsClientContract, } from 'src/core/server'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; -import * as Registry from '../../registry'; +import { getAsset, getPathParts } from '../../archive'; import { AssetType, KibanaAssetType, @@ -57,7 +57,7 @@ const AssetInstallers: Record< }; export async function getKibanaAsset(key: string): Promise { - const buffer = Registry.getAsset(key); + const buffer = getAsset(key); // cache values are buffers. convert to string / JSON return JSON.parse(buffer.toString('utf8')); @@ -117,14 +117,14 @@ export async function getKibanaAssets( ): Promise> { const kibanaAssetTypes = Object.values(KibanaAssetType); const isKibanaAssetType = (path: string) => { - const parts = Registry.pathParts(path); + const parts = getPathParts(path); return parts.service === 'kibana' && (kibanaAssetTypes as string[]).includes(parts.type); }; const filteredPaths = paths .filter(isKibanaAssetType) - .map<[string, AssetParts]>((path) => [path, Registry.pathParts(path)]); + .map<[string, AssetParts]>((path) => [path, getPathParts(path)]); const assetArrays: Array> = []; for (const assetType of kibanaAssetTypes) { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index a83d9428b7c93..4d36c3919198c 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -16,12 +16,10 @@ import { } from '../../../types'; import { installIndexPatterns } from '../kibana/index_pattern/install'; import { installTemplates } from '../elasticsearch/template/install'; -import { generateESIndexPatterns } from '../elasticsearch/template/template'; import { installPipelines, deletePreviousPipelines } from '../elasticsearch/ingest_pipeline/'; import { installILMPolicy } from '../elasticsearch/ilm/install'; import { installKibanaAssets, getKibanaAssets } from '../kibana/assets/install'; import { updateCurrentWriteIndices } from '../elasticsearch/template/template'; -import { isRequiredPackage } from './index'; import { deleteKibanaSavedObjectsAssets } from './remove'; import { installTransform } from '../elasticsearch/transform/install'; import { createInstallation, saveKibanaAssetsRefs, updateVersion } from './install'; @@ -47,30 +45,22 @@ export async function _installPackage({ installType: InstallType; installSource: InstallSource; }): Promise { - const { internal = false, name: pkgName, version: pkgVersion } = packageInfo; - const removable = !isRequiredPackage(pkgName); - const toSaveESIndexPatterns = generateESIndexPatterns(packageInfo.data_streams); + const { name: pkgName, version: pkgVersion } = packageInfo; // add the package installation to the saved object. // if some installation already exists, just update install info - if (!installedPkg) { - await createInstallation({ - savedObjectsClient, - pkgName, - pkgVersion, - internal, - removable, - installed_kibana: [], - installed_es: [], - toSaveESIndexPatterns, - installSource, - }); - } else { + if (installedPkg) { await savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { install_version: pkgVersion, install_status: 'installing', install_started_at: new Date().toISOString(), install_source: installSource, }); + } else { + await createInstallation({ + savedObjectsClient, + packageInfo, + installSource, + }); } // kick off `installIndexPatterns` & `installKibanaAssets` as early as possible because they're the longest running operations diff --git a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts index 2e2090312c9ae..50d8f2f4d2fb2 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts @@ -6,7 +6,7 @@ import { InstallablePackage } from '../../../types'; import * as Registry from '../registry'; -import { getArchiveFilelist } from '../archive/cache'; +import { getArchiveFilelist, getAsset } from '../archive'; // paths from RegistryPackage are routes to the assets on EPR // e.g. `/package/nginx/1.2.0/data_stream/access/fields/fields.yml` @@ -59,7 +59,7 @@ export async function getAssetsData( // Gather all asset data const assets = getAssets(packageInfo, filter, datasetName); const entries: Registry.ArchiveEntry[] = assets.map((path) => { - const buffer = Registry.getAsset(path); + const buffer = getAsset(path); return { path, buffer }; }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index e49aa4848809c..023691cad1913 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -4,18 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; import semver from 'semver'; import Boom from '@hapi/boom'; import { UnwrapPromise } from '@kbn/utility-types'; -import { BulkInstallPackageInfo, InstallSource, defaultPackages } from '../../../../common'; +import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import { generateESIndexPatterns } from '../elasticsearch/template/template'; +import { isRequiredPackage } from './index'; +import { + BulkInstallPackageInfo, + InstallablePackage, + InstallSource, + defaultPackages, +} from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; import { AssetReference, Installation, CallESAsCurrentUser, AssetType, - KibanaAssetReference, EsAssetReference, InstallType, KibanaAssetType, @@ -346,31 +352,19 @@ export const updateVersion = async ( }; export async function createInstallation(options: { savedObjectsClient: SavedObjectsClientContract; - pkgName: string; - pkgVersion: string; - internal: boolean; - removable: boolean; - installed_kibana: KibanaAssetReference[]; - installed_es: EsAssetReference[]; - toSaveESIndexPatterns: Record; + packageInfo: InstallablePackage; installSource: InstallSource; }) { - const { - savedObjectsClient, - pkgName, - pkgVersion, - internal, - removable, - installed_kibana: installedKibana, - installed_es: installedEs, - toSaveESIndexPatterns, - installSource, - } = options; - await savedObjectsClient.create( + const { savedObjectsClient, packageInfo, installSource } = options; + const { internal = false, name: pkgName, version: pkgVersion } = packageInfo; + const removable = !isRequiredPackage(pkgName); + const toSaveESIndexPatterns = generateESIndexPatterns(packageInfo.data_streams); + + const created = await savedObjectsClient.create( PACKAGES_SAVED_OBJECT_TYPE, { - installed_kibana: installedKibana, - installed_es: installedEs, + installed_kibana: [], + installed_es: [], es_index_patterns: toSaveESIndexPatterns, name: pkgName, version: pkgVersion, @@ -383,7 +377,8 @@ export async function createInstallation(options: { }, { id: pkgName, overwrite: true } ); - return [...installedKibana, ...installedEs]; + + return created; } export const saveKibanaAssetsRefs = async ( diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts index a2d5c8147002d..1208ffdaefe4a 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts @@ -5,7 +5,8 @@ */ import { AssetParts } from '../../../types'; -import { getBufferExtractor, pathParts, splitPkgKey } from './index'; +import { getPathParts } from '../archive'; +import { getBufferExtractor, splitPkgKey } from './index'; import { untarBuffer, unzipBuffer } from './extract'; const testPaths = [ @@ -46,7 +47,7 @@ const testPaths = [ test('testPathParts', () => { for (const value of testPaths) { - expect(pathParts(value.path)).toStrictEqual(value.assetParts as AssetParts); + expect(getPathParts(value.path)).toStrictEqual(value.assetParts as AssetParts); } }); diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.ts index 52a1894570b2a..c35e91bdf580b 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.ts @@ -8,7 +8,6 @@ import semver from 'semver'; import { Response } from 'node-fetch'; import { URL } from 'url'; import { - AssetParts, AssetsGroupedByServiceByType, CategoryId, CategorySummaryList, @@ -18,8 +17,12 @@ import { RegistrySearchResults, RegistrySearchResult, } from '../../../types'; -import { unpackArchiveToCache } from '../archive'; -import { cacheGet, getArchiveFilelist, setArchiveFilelist } from '../archive'; +import { + getArchiveFilelist, + getPathParts, + setArchiveFilelist, + unpackArchiveToCache, +} from '../archive'; import { fetchUrl, getResponse, getResponseStream } from './requests'; import { streamToBuffer } from './streams'; import { getRegistryUrl } from './registry_url'; @@ -146,36 +149,6 @@ export async function getRegistryPackage( return { paths, registryPackageInfo }; } -export function pathParts(path: string): AssetParts { - let dataset; - - let [pkgkey, service, type, file] = path.split('/'); - - // if it's a data stream - if (service === 'data_stream') { - // save the dataset name - dataset = type; - // drop the `data_stream/dataset-name` portion & re-parse - [pkgkey, service, type, file] = path.replace(`data_stream/${dataset}/`, '').split('/'); - } - - // This is to cover for the fields.yml files inside the "fields" directory - if (file === undefined) { - file = type; - type = 'fields'; - service = ''; - } - - return { - pkgkey, - service, - type, - file, - dataset, - path, - } as AssetParts; -} - export async function ensureCachedArchiveInfo( name: string, version: string, @@ -204,19 +177,12 @@ async function fetchArchiveBuffer( return { archiveBuffer, archivePath }; } -export function getAsset(key: string) { - const buffer = cacheGet(key); - if (buffer === undefined) throw new Error(`Cannot find asset ${key}`); - - return buffer; -} - export function groupPathsByService(paths: string[]): AssetsGroupedByServiceByType { const kibanaAssetTypes = Object.values(KibanaAssetType); // ASK: best way, if any, to avoid `any`? const assets = paths.reduce((map: any, path) => { - const parts = pathParts(path.replace(/^\/package\//, '')); + const parts = getPathParts(path.replace(/^\/package\//, '')); if (parts.service === 'kibana' && kibanaAssetTypes.includes(parts.type)) { if (!map[parts.service]) map[parts.service] = {}; if (!map[parts.service][parts.type]) map[parts.service][parts.type] = []; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx new file mode 100644 index 0000000000000..dd0060f773b49 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx @@ -0,0 +1,93 @@ +/* + * 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 { EuiTabbedContent } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPanel } from '@elastic/eui'; +import React, { CSSProperties, useMemo } from 'react'; +import { EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; +import { euiStyled } from '../../../../../../../observability/public'; +import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; +import { MetricsTab } from './tabs/metrics'; +import { LogsTab } from './tabs/logs'; +import { ProcessesTab } from './tabs/processes'; +import { PropertiesTab } from './tabs/properties'; + +interface Props { + isOpen: boolean; + onClose(): void; + options: InfraWaffleMapOptions; + currentTime: number; + node: InfraWaffleMapNode; + nodeType: InventoryItemType; +} +export const NodeContextPopover = ({ + isOpen, + node, + nodeType, + currentTime, + options, + onClose, +}: Props) => { + const tabConfigs = [MetricsTab, LogsTab, ProcessesTab, PropertiesTab]; + + const tabs = useMemo(() => { + return tabConfigs.map((m) => { + const TabContent = m.content; + return { + ...m, + content: ( + + ), + }; + }); + }, [tabConfigs, node, nodeType, currentTime, options]); + + if (!isOpen) { + return null; + } + + return ( + + + + + +

    {node.name}

    +
    +
    + + + + + +
    +
    + +
    + ); +}; + +const OverlayHeader = euiStyled.div` + border-color: ${(props) => props.theme.eui.euiBorderColor}; + border-bottom-width: ${(props) => props.theme.eui.euiBorderWidthThick}; + padding: ${(props) => props.theme.eui.euiSizeS}; + padding-bottom: 0; + overflow: hidden; +`; + +const panelStyle: CSSProperties = { + position: 'absolute', + right: 10, + top: -100, + width: '50%', + maxWidth: 600, + zIndex: 2, + height: '50vh', + overflow: 'hidden', +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx new file mode 100644 index 0000000000000..1a8bc374e79a3 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx @@ -0,0 +1,21 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { TabContent, TabProps } from './shared'; + +const TabComponent = (props: TabProps) => { + return Logs Placeholder; +}; + +export const LogsTab = { + id: 'logs', + name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', { + defaultMessage: 'Logs', + }), + content: TabComponent, +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx new file mode 100644 index 0000000000000..e329a5771c41d --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx @@ -0,0 +1,21 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { TabContent, TabProps } from './shared'; + +const TabComponent = (props: TabProps) => { + return Metrics Placeholder; +}; + +export const MetricsTab = { + id: 'metrics', + name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics', { + defaultMessage: 'Metrics', + }), + content: TabComponent, +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx new file mode 100644 index 0000000000000..94ba1150c20dd --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx @@ -0,0 +1,21 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { TabContent, TabProps } from './shared'; + +const TabComponent = (props: TabProps) => { + return Processes Placeholder; +}; + +export const ProcessesTab = { + id: 'processes', + name: i18n.translate('xpack.infra.nodeDetails.tabs.processes', { + defaultMessage: 'Processes', + }), + content: TabComponent, +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx new file mode 100644 index 0000000000000..8157aca9b1410 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx @@ -0,0 +1,21 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { TabContent, TabProps } from './shared'; + +const TabComponent = (props: TabProps) => { + return Properties Placeholder; +}; + +export const PropertiesTab = { + id: 'properties', + name: i18n.translate('xpack.infra.nodeDetails.tabs.properties', { + defaultMessage: 'Properties', + }), + content: TabComponent, +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx new file mode 100644 index 0000000000000..241ad7104836e --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx @@ -0,0 +1,20 @@ +/* + * 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 { InventoryItemType } from '../../../../../../../common/inventory_models/types'; +import { InfraWaffleMapOptions, InfraWaffleMapNode } from '../../../../../../lib/lib'; +import { euiStyled } from '../../../../../../../../observability/public'; + +export interface TabProps { + options: InfraWaffleMapOptions; + currentTime: number; + node: InfraWaffleMapNode; + nodeType: InventoryItemType; +} + +export const TabContent = euiStyled.div` + padding: ${(props) => props.theme.eui.paddingSizes.l}; +`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx index cc177b895ca50..f2d9da960df81 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { first } from 'lodash'; -import { ConditionalToolTip } from './conditional_tooltip'; import { euiStyled } from '../../../../../../../observability/public'; import { InfraWaffleMapBounds, @@ -18,11 +17,14 @@ import { InfraWaffleMapOptions, } from '../../../../../lib/lib'; import { colorFromValue } from '../../lib/color_from_value'; -import { NodeContextMenu } from './node_context_menu'; import { InventoryItemType } from '../../../../../../common/inventory_models/types'; +import { NodeContextPopover } from '../node_details/overlay'; + +import { NodeContextMenu } from './node_context_menu'; const initialState = { isPopoverOpen: false, + isOverlayOpen: false, }; type State = Readonly; @@ -53,22 +55,16 @@ export const Node = class extends React.PureComponent { values: { nodeName: node.name }, }); return ( - - - + + + ); } @@ -101,6 +105,13 @@ export const Node = class extends React.PureComponent { this.setState((prevState) => ({ isPopoverOpen: !prevState.isPopoverOpen })); }; + private toggleNewOverlay = () => { + this.setState((prevState) => ({ + isPopoverOpen: !prevState.isOverlayOpen === true ? false : prevState.isPopoverOpen, + isOverlayOpen: !prevState.isOverlayOpen, + })); + }; + private closePopover = () => { if (this.state.isPopoverOpen) { this.setState({ isPopoverOpen: false }); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx index d913261521383..91c6ad801000a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx @@ -37,6 +37,7 @@ interface Props { isPopoverOpen: boolean; closePopover: () => void; popoverPosition: EuiPopoverProps['anchorPosition']; + openNewOverlay?: () => void; } export const NodeContextMenu: React.FC = withTheme( @@ -50,6 +51,7 @@ export const NodeContextMenu: React.FC = withTheme nodeType, popoverPosition, theme, + openNewOverlay, }) => { const [flyoutVisible, setFlyoutVisible] = useState(false); const inventoryModel = findInventoryModel(nodeType); @@ -159,6 +161,14 @@ export const NodeContextMenu: React.FC = withTheme }, }; + const openNewOverlayMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.openNewOverlay', { + defaultMessage: '**** [NEW] Overlay ***', + }), + style: { color: theme?.eui.euiLinkColor || '#006BB4', fontWeight: 500, padding: 0 }, + onClick: openNewOverlay, + }; + return ( <> = withTheme + diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index 2623a2aff6832..ddc473a5c588d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -4,9 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import { + EuiFormRow, + EuiSelect, + EuiSwitch, + EuiSwitchEvent, + EuiSpacer, + EuiPopover, + EuiButtonEmpty, + EuiText, +} from '@elastic/eui'; import { IndexPatternColumn } from '../../../indexpattern'; import { updateColumnParam } from '../../layer_helpers'; import { DataType } from '../../../../types'; @@ -34,6 +43,8 @@ export interface TermsIndexPatternColumn extends FieldBasedIndexPatternColumn { size: number; orderBy: { type: 'alphabetical' } | { type: 'column'; columnId: string }; orderDirection: 'asc' | 'desc'; + otherBucket?: boolean; + missingBucket?: boolean; // Terms on numeric fields can be formatted format?: { id: string; @@ -67,10 +78,11 @@ export const termsOperation: OperationDefinition column && isSortableByColumn(column)) .map(([id]) => id)[0]; @@ -91,6 +103,8 @@ export const termsOperation: OperationDefinition { + paramEditor: function ParamEditor({ state, setState, currentColumn, layerId }) { + const indexPattern = currentColumn && state.indexPatterns[state.layers[layerId].indexPatternId]; + const hasRestrictions = indexPattern.hasRestrictions; + + const [popoverOpen, setPopoverOpen] = useState(false); + const SEPARATOR = '$$$'; function toValue(orderBy: TermsIndexPatternColumn['params']['orderBy']) { if (orderBy.type === 'alphabetical') { @@ -201,6 +224,73 @@ export const termsOperation: OperationDefinition + {!hasRestrictions && ( + + { + setPopoverOpen(true); + }} + > + {i18n.translate('xpack.lens.indexPattern.terms.advancedSettings', { + defaultMessage: 'Advanced', + })} + + } + isOpen={popoverOpen} + closePopover={() => { + setPopoverOpen(false); + }} + > + + setState( + updateColumnParam({ + state, + layerId, + currentColumn, + paramName: 'otherBucket', + value: e.target.checked, + }) + ) + } + /> + + + setState( + updateColumnParam({ + state, + layerId, + currentColumn, + paramName: 'missingBucket', + value: e.target.checked, + }) + ) + } + /> + + + + )} { beforeEach(() => { state = { indexPatternRefs: [], - indexPatterns: {}, + indexPatterns: { + '1': { + hasRestrictions: false, + } as IndexPattern, + }, existingFields: {}, currentIndexPatternId: '1', isFirstExistenceFetch: false, @@ -69,8 +73,9 @@ describe('terms', () => { describe('toEsAggsConfig', () => { it('should reflect params correctly', () => { + const termsColumn = state.layers.first.columns.col1 as TermsIndexPatternColumn; const esAggsConfig = termsOperation.toEsAggsConfig( - state.layers.first.columns.col1 as TermsIndexPatternColumn, + { ...termsColumn, params: { ...termsColumn.params, otherBucket: true } }, 'col1', {} as IndexPattern ); @@ -80,6 +85,27 @@ describe('terms', () => { orderBy: '_key', field: 'category', size: 3, + otherBucket: true, + }), + }) + ); + }); + + it('should not enable missing bucket if other bucket is not set', () => { + const termsColumn = state.layers.first.columns.col1 as TermsIndexPatternColumn; + const esAggsConfig = termsOperation.toEsAggsConfig( + { + ...termsColumn, + params: { ...termsColumn.params, otherBucket: false, missingBucket: true }, + }, + 'col1', + {} as IndexPattern + ); + expect(esAggsConfig).toEqual( + expect.objectContaining({ + params: expect.objectContaining({ + otherBucket: false, + missingBucket: false, }), }) ); @@ -249,6 +275,36 @@ describe('terms', () => { expect(termsColumn.dataType).toEqual('boolean'); }); + it('should set other bucket to true by default', () => { + const termsColumn = termsOperation.buildColumn({ + indexPattern: createMockedIndexPattern(), + field: { + aggregatable: true, + searchable: true, + type: 'boolean', + name: 'test', + displayName: 'test', + }, + columns: {}, + }); + expect(termsColumn.params.otherBucket).toEqual(true); + }); + + it('should set other bucket to false if index pattern has restrictions', () => { + const termsColumn = termsOperation.buildColumn({ + indexPattern: { ...createMockedIndexPattern(), hasRestrictions: true }, + field: { + aggregatable: true, + searchable: true, + type: 'boolean', + name: 'test', + displayName: 'test', + }, + columns: {}, + }); + expect(termsColumn.params.otherBucket).toEqual(false); + }); + it('should use existing metric column as order column', () => { const termsColumn = termsOperation.buildColumn({ indexPattern: createMockedIndexPattern(), @@ -400,6 +456,132 @@ describe('terms', () => { }); describe('param editor', () => { + it('should render current other bucket value', () => { + const setStateSpy = jest.fn(); + const instance = shallow( + + ); + + const select = instance + .find('[data-test-subj="indexPattern-terms-other-bucket"]') + .find(EuiSwitch); + + expect(select.prop('checked')).toEqual(false); + }); + + it('should hide other bucket setting for rollups', () => { + const setStateSpy = jest.fn(); + const instance = shallow( + + ); + + expect(instance.find('[data-test-subj="indexPattern-terms-other-bucket"]').length).toEqual(0); + }); + + it('should disable missing bucket setting as long as other bucket is not set', () => { + const setStateSpy = jest.fn(); + const instance = shallow( + + ); + + const select = instance + .find('[data-test-subj="indexPattern-terms-missing-bucket"]') + .find(EuiSwitch); + + expect(select.prop('disabled')).toEqual(true); + }); + + it('should enable missing bucket setting as long as other bucket is set', () => { + const setStateSpy = jest.fn(); + const instance = shallow( + + ); + + const select = instance + .find('[data-test-subj="indexPattern-terms-missing-bucket"]') + .find(EuiSwitch); + + expect(select.prop('disabled')).toEqual(false); + }); + + it('should update state when clicking other bucket toggle', () => { + const setStateSpy = jest.fn(); + const instance = shallow( + + ); + + instance + .find('[data-test-subj="indexPattern-terms-other-bucket"]') + .find(EuiSwitch) + .prop('onChange')!({ + target: { + checked: true, + }, + } as EuiSwitchEvent); + + expect(setStateSpy).toHaveBeenCalledWith({ + ...state, + layers: { + first: { + ...state.layers.first, + columns: { + ...state.layers.first.columns, + col1: { + ...state.layers.first.columns.col1, + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + otherBucket: true, + }, + }, + }, + }, + }, + }); + }); + it('should render current order by value and options', () => { const setStateSpy = jest.fn(); const instance = shallow( diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index eec351cfbb27e..39743a355fd78 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -253,7 +253,12 @@ export function PieComponent( onClickValue(desanitizeFilterContext(context)); }} - theme={chartTheme} + theme={{ + ...chartTheme, + background: { + color: undefined, // removes background for embeddables + }, + }} baseTheme={chartBaseTheme} /> , - valuesLabelMode: string = 'hide', - isHorizontal: boolean -) { +function getValueLabelsStyling(isHorizontal: boolean) { const VALUE_LABELS_MAX_FONTSIZE = 15; const VALUE_LABELS_MIN_FONTSIZE = 10; const VALUE_LABELS_VERTICAL_OFFSET = -10; const VALUE_LABELS_HORIZONTAL_OFFSET = 10; - if (valuesLabelMode === 'hide') { - return theme; - } return { - ...theme, - ...{ - barSeriesStyle: { - ...theme.barSeriesStyle, - displayValue: { - fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, - fill: { textInverted: true, textBorder: 2 }, - alignment: isHorizontal - ? { - vertical: VerticalAlignment.Middle, - } - : { horizontal: HorizontalAlignment.Center }, - offsetX: isHorizontal ? VALUE_LABELS_HORIZONTAL_OFFSET : 0, - offsetY: isHorizontal ? 0 : VALUE_LABELS_VERTICAL_OFFSET, - }, - }, + displayValue: { + fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, + fill: { textInverted: true, textBorder: 2 }, + alignment: isHorizontal + ? { + vertical: VerticalAlignment.Middle, + } + : { horizontal: HorizontalAlignment.Center }, + offsetX: isHorizontal ? VALUE_LABELS_HORIZONTAL_OFFSET : 0, + offsetY: isHorizontal ? 0 : VALUE_LABELS_VERTICAL_OFFSET, }, }; } @@ -445,9 +430,8 @@ export function XYChart({ // No histogram charts !isHistogramViz; - const baseThemeWithMaybeValueLabels = !shouldShowValueLabels - ? chartTheme - : mergeThemeWithValueLabelsStyling(chartTheme, valueLabels, shouldRotate); + const valueLabelsStyling = + shouldShowValueLabels && valueLabels !== 'hide' && getValueLabelsStyling(shouldRotate); const colorAssignments = getColorAssignments(args.layers, data, formatFactory); @@ -461,7 +445,16 @@ export function XYChart({ } legendPosition={legend.position} showLegendExtra={false} - theme={baseThemeWithMaybeValueLabels} + theme={{ + ...chartTheme, + barSeriesStyle: { + ...chartTheme.barSeriesStyle, + ...valueLabelsStyling, + }, + background: { + color: undefined, // removes background for embeddables + }, + }} baseTheme={chartBaseTheme} tooltip={{ headerFormatter: (d) => safeXAccessorLabelRenderer(d.value), diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/x-pack/plugins/lens/server/routes/field_stats.ts index a884aeffa6134..29e2416b74618 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/x-pack/plugins/lens/server/routes/field_stats.ts @@ -9,7 +9,7 @@ import DateMath from '@elastic/datemath'; import { schema } from '@kbn/config-schema'; import { CoreSetup } from 'src/core/server'; import { IFieldType } from 'src/plugins/data/common'; -import { ESSearchResponse } from '../../../apm/typings/elasticsearch'; +import { ESSearchResponse } from '../../../../typings/elasticsearch'; import { FieldStatsResponse, BASE_API_URL } from '../../common'; const SHARD_SIZE = 5000; diff --git a/x-pack/plugins/lens/server/usage/task.ts b/x-pack/plugins/lens/server/usage/task.ts index 83cdbd62f3484..014193fb6566e 100644 --- a/x-pack/plugins/lens/server/usage/task.ts +++ b/x-pack/plugins/lens/server/usage/task.ts @@ -15,7 +15,7 @@ import { } from '../../../task_manager/server'; import { getVisualizationCounts } from './visualization_counts'; -import { ESSearchResponse } from '../../../apm/typings/elasticsearch'; +import { ESSearchResponse } from '../../../../typings/elasticsearch'; // This task is responsible for running daily and aggregating all the Lens click event objects // into daily rolled-up documents, which will be used in reporting click stats diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts deleted file mode 100755 index 8cd6b70d47570..0000000000000 --- a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts +++ /dev/null @@ -1,71 +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 { fetchAllFromScroll } from './fetch_all_from_scroll'; - -describe('fetch_all_from_scroll', () => { - let stubCallWithRequest: jest.Mock; - - beforeEach(() => { - stubCallWithRequest = jest.fn(); - stubCallWithRequest - .mockResolvedValueOnce({ - hits: { - hits: ['newhit'], - }, - _scroll_id: 'newScrollId', - }) - .mockResolvedValueOnce({ - hits: { - hits: [], - }, - }); - }); - - describe('#fetchAllFromScroll', () => { - describe('when the passed-in response has no hits', () => { - const mockResponse = { - hits: { - hits: [], - }, - }; - - it('should return an empty array of hits', async () => { - const hits = await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); - expect(hits).toEqual([]); - }); - - it('should not call callWithRequest', async () => { - await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); - expect(stubCallWithRequest).toHaveBeenCalledTimes(0); - }); - }); - - describe('when the passed-in response has some hits', () => { - const mockResponse = { - hits: { - hits: ['foo', 'bar'], - }, - _scroll_id: 'originalScrollId', - }; - - it('should return the hits from the response', async () => { - const hits = await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); - expect(hits).toEqual(['foo', 'bar', 'newhit']); - }); - - it('should call callWithRequest', async () => { - await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); - expect(stubCallWithRequest).toHaveBeenCalledTimes(2); - - const firstCallWithRequestCallArgs = stubCallWithRequest.mock.calls[0]; - expect(firstCallWithRequestCallArgs[1].body.scroll_id).toBe('originalScrollId'); - - const secondCallWithRequestCallArgs = stubCallWithRequest.mock.calls[1]; - expect(secondCallWithRequestCallArgs[1].body.scroll_id).toBe('newScrollId'); - }); - }); - }); -}); diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts deleted file mode 100755 index f7cfc4d4fa12a..0000000000000 --- a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts +++ /dev/null @@ -1,34 +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 { LegacyAPICaller } from 'src/core/server'; -import { SearchResponse } from 'elasticsearch'; - -import { ES_SCROLL_SETTINGS } from '../../../common/constants'; -import { Hits } from '../../types'; - -export async function fetchAllFromScroll( - response: SearchResponse, - callWithRequest: LegacyAPICaller, - hits: Hits = [] -): Promise { - const newHits = response.hits?.hits || []; - const scrollId = response._scroll_id; - - if (newHits.length > 0) { - hits.push(...newHits); - - const innerResponse = await callWithRequest('scroll', { - body: { - scroll: ES_SCROLL_SETTINGS.KEEPALIVE, - scroll_id: scrollId, - }, - }); - - return await fetchAllFromScroll(innerResponse, callWithRequest, hits); - } - - return hits; -} diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/index.ts b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/index.ts deleted file mode 100755 index a6865a5063339..0000000000000 --- a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/index.ts +++ /dev/null @@ -1,7 +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. - */ - -export { fetchAllFromScroll } from './fetch_all_from_scroll'; diff --git a/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts b/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts index 82ce0d72e2052..695531bb69510 100755 --- a/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts +++ b/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts @@ -10,8 +10,7 @@ describe('pipeline', () => { describe('Pipeline', () => { describe('fromUpstreamJSON factory method', () => { const upstreamJSON = { - _id: 'apache', - _source: { + apache: { description: 'this is an apache pipeline', pipeline_metadata: { version: 1, @@ -21,25 +20,23 @@ describe('pipeline', () => { pipeline: 'input {} filter { grok {} }\n output {}', }, }; + const upstreamId = 'apache'; it('returns correct Pipeline instance', () => { const pipeline = Pipeline.fromUpstreamJSON(upstreamJSON); - expect(pipeline.id).toBe(upstreamJSON._id); - expect(pipeline.description).toBe(upstreamJSON._source.description); - expect(pipeline.username).toBe(upstreamJSON._source.username); - expect(pipeline.pipeline).toBe(upstreamJSON._source.pipeline); + expect(pipeline.id).toBe(upstreamId); + expect(pipeline.description).toBe(upstreamJSON.apache.description); + expect(pipeline.username).toBe(upstreamJSON.apache.username); + expect(pipeline.pipeline).toBe(upstreamJSON.apache.pipeline); }); - it('throws if pipeline argument does not contain an id property', () => { - const badJSON = { - // no _id - _source: upstreamJSON._source, - }; + it('throws if pipeline argument does not contain id as a key', () => { + const badJSON = {}; const testFromUpstreamJsonError = () => { return Pipeline.fromUpstreamJSON(badJSON); }; expect(testFromUpstreamJsonError).toThrowError( - /upstreamPipeline argument must contain an id property/i + /upstreamPipeline argument must contain pipeline id as a key/i ); }); }); diff --git a/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts b/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts index 66aac63811050..fd5c22ec72c3b 100755 --- a/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts +++ b/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts @@ -93,21 +93,21 @@ export class Pipeline { // generate Pipeline object from elasticsearch response static fromUpstreamJSON(upstreamPipeline: Record) { - if (!upstreamPipeline._id) { + if (Object.keys(upstreamPipeline).length !== 1) { throw badRequest( i18n.translate( 'xpack.logstash.upstreamPipelineArgumentMustContainAnIdPropertyErrorMessage', { - defaultMessage: 'upstreamPipeline argument must contain an id property', + defaultMessage: 'upstreamPipeline argument must contain pipeline id as a key', } ) ); } - const id = get(upstreamPipeline, '_id') as string; - const description = get(upstreamPipeline, '_source.description') as string; - const username = get(upstreamPipeline, '_source.username') as string; - const pipeline = get(upstreamPipeline, '_source.pipeline') as string; - const settings = get(upstreamPipeline, '_source.pipeline_settings') as Record; + const id = Object.keys(upstreamPipeline).pop() as string; + const description = get(upstreamPipeline, id + '.description') as string; + const username = get(upstreamPipeline, id + '.username') as string; + const pipeline = get(upstreamPipeline, id + '.pipeline') as string; + const settings = get(upstreamPipeline, id + '.pipeline_settings') as Record; const opts: PipelineOptions = { id, description, username, pipeline, settings }; diff --git a/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts index c557e84443b02..7a3654794b590 100755 --- a/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts +++ b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts @@ -9,8 +9,7 @@ import { PipelineListItem } from './pipeline_list_item'; describe('pipeline_list_item', () => { describe('PipelineListItem', () => { const upstreamJSON = { - _id: 'apache', - _source: { + apache: { description: 'this is an apache pipeline', last_modified: '2017-05-14T02:50:51.250Z', pipeline_metadata: { @@ -20,24 +19,22 @@ describe('pipeline_list_item', () => { username: 'elastic', pipeline: 'input {} filter { grok {} }\n output {}', }, - _index: 'index', - _type: 'type', - _score: 100, }; + const upstreamId = 'apache'; describe('fromUpstreamJSON factory method', () => { it('returns correct PipelineListItem instance', () => { - const pipelineListItem = PipelineListItem.fromUpstreamJSON(upstreamJSON); - expect(pipelineListItem.id).toBe(upstreamJSON._id); - expect(pipelineListItem.description).toBe(upstreamJSON._source.description); - expect(pipelineListItem.username).toBe(upstreamJSON._source.username); - expect(pipelineListItem.last_modified).toBe(upstreamJSON._source.last_modified); + const pipelineListItem = PipelineListItem.fromUpstreamJSON(upstreamId, upstreamJSON); + expect(pipelineListItem.id).toBe(upstreamId); + expect(pipelineListItem.description).toBe(upstreamJSON.apache.description); + expect(pipelineListItem.username).toBe(upstreamJSON.apache.username); + expect(pipelineListItem.last_modified).toBe(upstreamJSON.apache.last_modified); }); }); describe('downstreamJSON getter method', () => { it('returns the downstreamJSON JSON', () => { - const pipelineListItem = PipelineListItem.fromUpstreamJSON(upstreamJSON); + const pipelineListItem = PipelineListItem.fromUpstreamJSON(upstreamId, upstreamJSON); const expectedDownstreamJSON = { id: 'apache', description: 'this is an apache pipeline', diff --git a/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts index eeb197a58f51d..07326dc745e18 100755 --- a/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts +++ b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts @@ -5,7 +5,7 @@ */ import { get } from 'lodash'; -import { Hit, PipelineListItemOptions } from '../../types'; +import { PipelineListItemOptions } from '../../types'; export class PipelineListItem { public readonly id: string; @@ -34,12 +34,12 @@ export class PipelineListItem { * Takes the json GET response from ES and constructs a pipeline model to be used * in Kibana downstream */ - static fromUpstreamJSON(pipeline: Hit) { + static fromUpstreamJSON(id: string, pipeline: Record) { const opts = { - id: pipeline._id, - description: get(pipeline, '_source.description') as string, - last_modified: get(pipeline, '_source.last_modified') as string, - username: get(pipeline, '_source.username') as string, + id, + description: get(pipeline, id + '.description') as string, + last_modified: get(pipeline, id + '.last_modified') as string, + username: get(pipeline, id + '.username') as string, }; return new PipelineListItem(opts); diff --git a/x-pack/plugins/logstash/server/plugin.ts b/x-pack/plugins/logstash/server/plugin.ts index 0347a606a8044..4a6d476551db0 100644 --- a/x-pack/plugins/logstash/server/plugin.ts +++ b/x-pack/plugins/logstash/server/plugin.ts @@ -44,10 +44,8 @@ export class LogstashPlugin implements Plugin { }, privileges: [ { - requiredClusterPrivileges: [], - requiredIndexPrivileges: { - ['.logstash']: ['read'], - }, + requiredClusterPrivileges: ['manage_logstash_pipelines'], + requiredIndexPrivileges: {}, ui: [], }, ], diff --git a/x-pack/plugins/logstash/server/routes/pipeline/delete.ts b/x-pack/plugins/logstash/server/routes/pipeline/delete.ts index 4aeae3e0ae2d5..d94b3b94b1df0 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/delete.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/delete.ts @@ -5,7 +5,6 @@ */ import { schema } from '@kbn/config-schema'; import { IRouter } from 'src/core/server'; -import { INDEX_NAMES } from '../../../common/constants'; import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; import { checkLicense } from '../../lib/check_license'; @@ -25,10 +24,9 @@ export function registerPipelineDeleteRoute(router: IRouter) { router.handleLegacyErrors(async (context, request, response) => { const client = context.logstash!.esClient; - await client.callAsCurrentUser('delete', { - index: INDEX_NAMES.PIPELINES, - id: request.params.id, - refresh: 'wait_for', + await client.callAsCurrentUser('transport.request', { + path: '/_logstash/pipeline/' + encodeURIComponent(request.params.id), + method: 'DELETE', }); return response.noContent(); diff --git a/x-pack/plugins/logstash/server/routes/pipeline/load.ts b/x-pack/plugins/logstash/server/routes/pipeline/load.ts index fec9097114d26..69d16fb82d869 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/load.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/load.ts @@ -6,7 +6,6 @@ import { schema } from '@kbn/config-schema'; import { IRouter } from 'src/core/server'; -import { INDEX_NAMES } from '../../../common/constants'; import { Pipeline } from '../../models/pipeline'; import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; import { checkLicense } from '../../lib/check_license'; @@ -26,14 +25,13 @@ export function registerPipelineLoadRoute(router: IRouter) { router.handleLegacyErrors(async (context, request, response) => { const client = context.logstash!.esClient; - const result = await client.callAsCurrentUser('get', { - index: INDEX_NAMES.PIPELINES, - id: request.params.id, - _source: ['description', 'username', 'pipeline', 'pipeline_settings'], + const result = await client.callAsCurrentUser('transport.request', { + path: '/_logstash/pipeline/' + encodeURIComponent(request.params.id), + method: 'GET', ignore: [404], }); - if (!result.found) { + if (result[request.params.id] === undefined) { return response.notFound(); } diff --git a/x-pack/plugins/logstash/server/routes/pipeline/save.ts b/x-pack/plugins/logstash/server/routes/pipeline/save.ts index 755a82e670a2a..e5f28bda1974c 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/save.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/save.ts @@ -7,7 +7,6 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { IRouter } from 'src/core/server'; -import { INDEX_NAMES } from '../../../common/constants'; import { Pipeline } from '../../models/pipeline'; import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; import { SecurityPluginSetup } from '../../../../security/server'; @@ -41,11 +40,10 @@ export function registerPipelineSaveRoute(router: IRouter, security?: SecurityPl const client = context.logstash!.esClient; const pipeline = Pipeline.fromDownstreamJSON(request.body, request.params.id, username); - await client.callAsCurrentUser('index', { - index: INDEX_NAMES.PIPELINES, - id: pipeline.id, + await client.callAsCurrentUser('transport.request', { + path: '/_logstash/pipeline/' + encodeURIComponent(pipeline.id), + method: 'PUT', body: pipeline.upstreamJSON, - refresh: 'wait_for', }); return response.noContent(); diff --git a/x-pack/plugins/logstash/server/routes/pipelines/delete.ts b/x-pack/plugins/logstash/server/routes/pipelines/delete.ts index 4b2471c89fe07..4eb3cae1d0956 100644 --- a/x-pack/plugins/logstash/server/routes/pipelines/delete.ts +++ b/x-pack/plugins/logstash/server/routes/pipelines/delete.ts @@ -7,15 +7,13 @@ import { schema } from '@kbn/config-schema'; import { LegacyAPICaller, IRouter } from 'src/core/server'; import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; -import { INDEX_NAMES } from '../../../common/constants'; import { checkLicense } from '../../lib/check_license'; async function deletePipelines(callWithRequest: LegacyAPICaller, pipelineIds: string[]) { const deletePromises = pipelineIds.map((pipelineId) => { - return callWithRequest('delete', { - index: INDEX_NAMES.PIPELINES, - id: pipelineId, - refresh: 'wait_for', + return callWithRequest('transport.request', { + path: '/_logstash/pipeline/' + encodeURIComponent(pipelineId), + method: 'DELETE', }) .then((success) => ({ success })) .catch((error) => ({ error })); diff --git a/x-pack/plugins/logstash/server/routes/pipelines/list.ts b/x-pack/plugins/logstash/server/routes/pipelines/list.ts index de2266b89e3d0..78690d3091cbd 100644 --- a/x-pack/plugins/logstash/server/routes/pipelines/list.ts +++ b/x-pack/plugins/logstash/server/routes/pipelines/list.ts @@ -4,27 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { SearchResponse } from 'elasticsearch'; import { LegacyAPICaller, IRouter } from 'src/core/server'; import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; -import { INDEX_NAMES, ES_SCROLL_SETTINGS } from '../../../common/constants'; import { PipelineListItem } from '../../models/pipeline_list_item'; -import { fetchAllFromScroll } from '../../lib/fetch_all_from_scroll'; import { checkLicense } from '../../lib/check_license'; async function fetchPipelines(callWithRequest: LegacyAPICaller) { const params = { - index: INDEX_NAMES.PIPELINES, - scroll: ES_SCROLL_SETTINGS.KEEPALIVE, - body: { - size: ES_SCROLL_SETTINGS.PAGE_SIZE, - }, + path: '/_logstash/pipeline', + method: 'GET', ignore: [404], }; - const response = await callWithRequest>('search', params); - return fetchAllFromScroll(response, callWithRequest); + return await callWithRequest('transport.request', params); } export function registerPipelinesListRoute(router: IRouter) { @@ -38,11 +31,16 @@ export function registerPipelinesListRoute(router: IRouter) { router.handleLegacyErrors(async (context, request, response) => { try { const client = context.logstash!.esClient; - const pipelinesHits = await fetchPipelines(client.callAsCurrentUser); + const pipelinesRecord = (await fetchPipelines(client.callAsCurrentUser)) as Record< + string, + any + >; - const pipelines = pipelinesHits.map((pipeline) => { - return PipelineListItem.fromUpstreamJSON(pipeline).downstreamJSON; - }); + const pipelines = Object.keys(pipelinesRecord) + .sort() + .map((key) => { + return PipelineListItem.fromUpstreamJSON(key, pipelinesRecord).downstreamJSON; + }); return response.ok({ body: { pipelines } }); } catch (err) { diff --git a/x-pack/plugins/logstash/server/types.ts b/x-pack/plugins/logstash/server/types.ts index 29198407013ab..d9fd109b20943 100644 --- a/x-pack/plugins/logstash/server/types.ts +++ b/x-pack/plugins/logstash/server/types.ts @@ -3,14 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { SearchResponse } from 'elasticsearch'; import { ILegacyScopedClusterClient } from 'src/core/server'; -type UnwrapArray = T extends Array ? U : never; - -export type Hits = SearchResponse['hits']['hits']; -export type Hit = UnwrapArray; - export interface PipelineListItemOptions { id: string; description: string; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/common/search_bar_filters.tsx similarity index 66% rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx rename to x-pack/plugins/ml/public/application/data_frame_analytics/common/search_bar_filters.tsx index 7a366bb63420c..e045eb68a63f8 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/search_bar_filters.tsx @@ -4,23 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Dispatch, SetStateAction, FC, Fragment, useState } from 'react'; -import { - EuiSearchBar, - EuiSearchBarProps, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { stringMatch } from '../../../../../util/string_utils'; +import { stringMatch } from '../../util/string_utils'; import { TermClause, FieldClause, Value, DataFrameAnalyticsListRow, -} from '../analytics_list/common'; -import { ModelItem } from '../models_management/models_list'; +} from '../pages/analytics_management/components/analytics_list/common'; +import { ModelItem } from '../pages/analytics_management/components/models_management/models_list'; export function filterAnalyticsModels( items: ModelItem[], @@ -151,69 +142,3 @@ export function filterAnalytics( return filtered; } - -function getError(errorMessage: string | null) { - if (errorMessage) { - return i18n.translate('xpack.ml.analyticList.searchBar.invalidSearchErrorMessage', { - defaultMessage: 'Invalid search: {errorMessage}', - values: { errorMessage }, - }); - } - - return ''; -} - -interface Props { - filters: EuiSearchBarProps['filters']; - searchQueryText: string; - setSearchQueryText: Dispatch>; -} - -export const AnalyticsSearchBar: FC = ({ filters, searchQueryText, setSearchQueryText }) => { - const [errorMessage, setErrorMessage] = useState(null); - - const onChange: EuiSearchBarProps['onChange'] = ({ query, error }) => { - if (error) { - setErrorMessage(error.message); - } else if (query !== null && query.text !== undefined) { - setSearchQueryText(query.text); - setErrorMessage(null); - } - }; - - return ( - - - {searchQueryText === undefined && ( - - )} - {searchQueryText !== undefined && ( - - )} - - - - - - ); -}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx index 77d33af24848b..8ed2436843e0e 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx @@ -10,7 +10,7 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiBasicTable, + EuiInMemoryTable, EuiSearchBar, EuiSearchBarProps, EuiSpacer, @@ -35,7 +35,7 @@ import { getGroupQueryText, } from '../../../../../jobs/jobs_list/components/utils'; import { SourceSelection } from '../source_selection'; -import { filterAnalytics, AnalyticsSearchBar } from '../analytics_search_bar'; +import { filterAnalytics } from '../../../../common/search_bar_filters'; import { AnalyticsEmptyPrompt } from './empty_prompt'; import { useTableSettings } from './use_table_settings'; import { RefreshAnalyticsListButton } from '../refresh_analytics_list_button'; @@ -97,6 +97,7 @@ export const DataFrameAnalyticsList: FC = ({ const [isLoading, setIsLoading] = useState(false); const [filteredAnalytics, setFilteredAnalytics] = useState([]); const [searchQueryText, setSearchQueryText] = useState(''); + const [searchError, setSearchError] = useState(); const [analytics, setAnalytics] = useState([]); const [analyticsStats, setAnalyticsStats] = useState( undefined @@ -183,9 +184,21 @@ export const DataFrameAnalyticsList: FC = ({ isMlEnabledInSpace ); - const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings< - DataFrameAnalyticsListRow - >(DataFrameAnalyticsListColumn.id, filteredAnalytics); + const { onTableChange, pagination, sorting } = useTableSettings( + DataFrameAnalyticsListColumn.id, + filteredAnalytics + ); + + const handleSearchOnChange: EuiSearchBarProps['onChange'] = (search) => { + if (search.error !== null) { + setSearchError(search.error.message); + return false; + } + + setSearchError(undefined); + setSearchQueryText(search.queryText); + return true; + }; // Before the analytics have been loaded for the first time, display the loading indicator only. // Otherwise a user would see 'No data frame analytics found' during the initial loading. @@ -240,6 +253,14 @@ export const DataFrameAnalyticsList: FC = ({
    ); + const search: EuiSearchBarProps = { + query: searchQueryText, + onChange: handleSearchOnChange, + box: { + incremental: true, + }, + filters, + }; return (
    @@ -263,25 +284,22 @@ export const DataFrameAnalyticsList: FC = ({
    - - - - className="mlAnalyticsTable" + + allowNeutralSort={false} + className="mlAnalyticsInMemoryTable" columns={columns} + error={searchError} hasActions={false} isExpandable={true} isSelectable={false} - items={pageOfItems} + items={analytics} itemId={DataFrameAnalyticsListColumn.id} itemIdToExpandedRowMap={itemIdToExpandedRowMap} loading={isLoading} - onChange={onTableChange} - pagination={pagination!} + onTableChange={onTableChange} + pagination={pagination} sorting={sorting} + search={search} data-test-subj={isLoading ? 'mlAnalyticsTable loading' : 'mlAnalyticsTable loaded'} rowProps={(item) => ({ 'data-test-subj': `mlAnalyticsTableRow row-${item.id}`, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts index c2018463fdf49..5b7d71dacccf8 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts @@ -5,18 +5,11 @@ */ import { useState } from 'react'; -import { Direction, EuiBasicTableProps, EuiTableSortingType } from '@elastic/eui'; -import { sortBy, get } from 'lodash'; +import { Direction, EuiBasicTableProps, Pagination, PropertySort } from '@elastic/eui'; const PAGE_SIZE = 10; const PAGE_SIZE_OPTIONS = [10, 25, 50]; -const jobPropertyMap = { - ID: 'id', - Status: 'state', - Type: 'job_type', -}; - // Copying from EUI EuiBasicTable types as type is not correctly picked up for table's onChange // Can be removed when https://github.com/elastic/eui/issues/4011 is addressed in EUI export interface Criteria { @@ -47,9 +40,8 @@ interface AnalyticsBasicTableSettings { interface UseTableSettingsReturnValue { onTableChange: EuiBasicTableProps['onChange']; - pageOfItems: T[]; - pagination: EuiBasicTableProps['pagination']; - sorting: EuiTableSortingType; + pagination: Pagination; + sorting: { sort: PropertySort }; } export function useTableSettings( @@ -65,33 +57,6 @@ export function useTableSettings( sortDirection: 'asc', }); - const getPageOfItems = ( - list: TypeOfItem[], - index: number, - size: number, - sortField: keyof TypeOfItem, - sortDirection: Direction - ) => { - list = sortBy(list, (item) => - get(item, jobPropertyMap[sortField as keyof typeof jobPropertyMap] || sortField) - ); - list = sortDirection === 'asc' ? list : list.reverse(); - const listLength = list.length; - - let pageStart = index * size; - if (pageStart >= listLength && listLength !== 0) { - // if the page start is larger than the number of items due to - // filters being applied or items being deleted, calculate a new page start - pageStart = Math.floor((listLength - 1) / size) * size; - - setTableSettings({ ...tableSettings, pageIndex: pageStart / size }); - } - return { - pageOfItems: list.slice(pageStart, pageStart + size), - totalItemCount: listLength, - }; - }; - const onTableChange: EuiBasicTableProps['onChange'] = ({ page = { index: 0, size: PAGE_SIZE }, sort = { field: sortByField, direction: 'asc' }, @@ -110,27 +75,19 @@ export function useTableSettings( const { pageIndex, pageSize, sortField, sortDirection } = tableSettings; - const { pageOfItems, totalItemCount } = getPageOfItems( - items, - pageIndex, - pageSize, - sortField, - sortDirection - ); - const pagination = { pageIndex, pageSize, - totalItemCount, + totalItemCount: items.length, pageSizeOptions: PAGE_SIZE_OPTIONS, }; const sorting = { sort: { - field: sortField, + field: sortField as string, direction: sortDirection, }, }; - return { onTableChange, pageOfItems, pagination, sorting }; + return { onTableChange, pagination, sorting }; } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts deleted file mode 100644 index 2748764d7f46e..0000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts +++ /dev/null @@ -1,7 +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. - */ - -export { AnalyticsSearchBar, filterAnalytics, filterAnalyticsModels } from './analytics_search_bar'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx index 6dd55f1881d72..713cbbc814c32 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx @@ -8,7 +8,7 @@ import React, { FC, useState, useCallback, useEffect, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiBasicTable, + EuiInMemoryTable, EuiFlexGroup, EuiFlexItem, EuiTitle, @@ -18,6 +18,7 @@ import { EuiButtonIcon, EuiBadge, SearchFilterConfig, + EuiSearchBarProps, } from '@elastic/eui'; import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table'; @@ -41,7 +42,7 @@ import { useRefreshAnalyticsList, } from '../../../../common'; import { useTableSettings } from '../analytics_list/use_table_settings'; -import { filterAnalyticsModels, AnalyticsSearchBar } from '../analytics_search_bar'; +import { filterAnalyticsModels } from '../../../../common/search_bar_filters'; import { ML_PAGES } from '../../../../../../../common/constants/ml_url_generator'; import { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; import { timeFormatter } from '../../../../../../../common/util/date_utils'; @@ -401,7 +402,7 @@ export const ModelsList: FC = () => { ] : []; - const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings( + const { onTableChange, pagination, sorting } = useTableSettings( ModelsTableToConfigMapping.id, filteredModels ); @@ -452,6 +453,29 @@ export const ModelsList: FC = () => { } : undefined; + const search: EuiSearchBarProps = { + query: searchQueryText, + onChange: (searchChange) => { + if (searchChange.error !== null) { + return false; + } + setSearchQueryText(searchChange.queryText); + return true; + }, + box: { + incremental: true, + }, + ...(inferenceTypesOptions && inferenceTypesOptions.length > 0 + ? { + filters, + } + : {}), + ...(selectedModels.length > 0 + ? { + toolsLeft, + } + : {}), + }; return ( <> @@ -464,31 +488,21 @@ export const ModelsList: FC = () => {
    - - {selectedModels.length > 0 && toolsLeft} - - - - - - + + allowNeutralSort={false} columns={columns} hasActions={true} isExpandable={true} + itemIdToExpandedRowMap={itemIdToExpandedRowMap} isSelectable={false} - items={pageOfItems} + items={items} itemId={ModelsTableToConfigMapping.id} - itemIdToExpandedRowMap={itemIdToExpandedRowMap} loading={isLoading} - onChange={onTableChange} - selection={selection} - pagination={pagination!} + onTableChange={onTableChange} + pagination={pagination} sorting={sorting} - data-test-subj={isLoading ? 'mlModelsTable loading' : 'mlModelsTable loaded'} + search={search} + selection={selection} rowProps={(item) => ({ 'data-test-subj': `mlModelsTableRow row-${item.model_id}`, })} diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap index c84e78ece03b7..28aa8750beddd 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap @@ -90,7 +90,7 @@ exports[`EnabledFeatures renders as expected 1`] = ` "category": Object { "euiIconType": "logoKibana", "id": "kibana", - "label": "Kibana", + "label": "Analytics", "order": 1000, }, "id": "feature-1", @@ -102,7 +102,7 @@ exports[`EnabledFeatures renders as expected 1`] = ` "category": Object { "euiIconType": "logoKibana", "id": "kibana", - "label": "Kibana", + "label": "Analytics", "order": 1000, }, "id": "feature-2", diff --git a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts index cb6e48530b027..d1c5256c81c63 100644 --- a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts @@ -13,8 +13,7 @@ import { estimateRecurringTaskScheduling, } from './workload_statistics'; import { ConcreteTaskInstance } from '../task'; -import { ESSearchResponse } from '../../../apm/typings/elasticsearch'; -import { AggregationResultOf } from '../../../apm/typings/elasticsearch/aggregations'; +import { AggregationResultOf, ESSearchResponse } from '../../../../typings/elasticsearch'; import { times } from 'lodash'; import { taskStoreMock } from '../task_store.mock'; import { of, Subject } from 'rxjs'; diff --git a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts index 17448ea412ae6..a27b5e2282e32 100644 --- a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts +++ b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts @@ -11,7 +11,7 @@ import { JsonObject } from 'src/plugins/kibana_utils/common'; import { keyBy, mapValues } from 'lodash'; import { AggregatedStatProvider } from './runtime_statistics_aggregator'; import { parseIntervalAsSecond, asInterval, parseIntervalAsMillisecond } from '../lib/intervals'; -import { AggregationResultOf } from '../../../apm/typings/elasticsearch/aggregations'; +import { AggregationResultOf } from '../../../../typings/elasticsearch'; import { HealthStatus } from './monitoring_stats_stream'; import { TaskStore } from '../task_store'; diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 8c0d7764e009f..cb44144d2fefe 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -56,7 +56,7 @@ import { } from './queries/mark_available_tasks_as_claimed'; import { TaskTypeDictionary } from './task_type_dictionary'; -import { ESSearchResponse, ESSearchBody } from '../../apm/typings/elasticsearch'; +import { ESSearchResponse, ESSearchBody } from '../../../typings/elasticsearch'; export interface StoreOpts { esClient: ElasticsearchClient; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index 12836c0a18ce2..4204433feb6b6 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -4,26 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { MouseEventHandler, FC, useContext, useEffect, useState } from 'react'; +import React, { MouseEventHandler, FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { - EuiBasicTable, - EuiBasicTableProps, EuiButtonEmpty, EuiButtonIcon, EuiCallOut, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, - EuiSearchBar, - EuiSpacer, EuiPopover, EuiTitle, + EuiInMemoryTable, + EuiSearchBarProps, } from '@elastic/eui'; -import { TransformId } from '../../../../../../common/types/transform'; +import type { TransformId } from '../../../../../../common/types/transform'; import { useRefreshTransformList, @@ -47,7 +45,7 @@ import { StopActionName } from '../action_stop'; import { ItemIdToExpandedRowMap } from './common'; import { useColumns } from './use_columns'; import { ExpandedRow } from './expanded_row'; -import { TransformSearchBar, filterTransforms } from './transform_search_bar'; +import { transformFilters, filterTransforms } from './transform_search_bar_filters'; import { useTableSettings } from './use_table_settings'; function getItemIdToExpandedRowMap( @@ -81,7 +79,8 @@ export const TransformList: FC = ({ const [isLoading, setIsLoading] = useState(false); const { refresh } = useRefreshTransformList({ isLoading: setIsLoading }); - const [searchQueryText, setSearchQueryText] = useState(''); + const [filterActive, setFilterActive] = useState(false); + const [filteredTransforms, setFilteredTransforms] = useState([]); const [expandedRowItemIds, setExpandedRowItemIds] = useState([]); const [transformSelection, setTransformSelection] = useState([]); @@ -89,6 +88,7 @@ export const TransformList: FC = ({ const bulkStartAction = useStartAction(false); const bulkDeleteAction = useDeleteAction(false); + const [searchError, setSearchError] = useState(undefined); const stopTransforms = useStopTransforms(); const { capabilities } = useContext(AuthorizationContext); @@ -97,42 +97,38 @@ export const TransformList: FC = ({ !capabilities.canPreviewTransform || !capabilities.canStartStopTransform; + const { sorting, pagination, onTableChange } = useTableSettings( + TRANSFORM_LIST_COLUMN.ID, + transforms + ); + const { columns, modals: singleActionModals } = useColumns( expandedRowItemIds, setExpandedRowItemIds, transformSelection ); - const updateFilteredItems = (queryClauses: any) => { - if (queryClauses.length) { - const filtered = filterTransforms(transforms, queryClauses); - setFilteredTransforms(filtered); + const onQueryChange = ({ + query, + error, + }: Parameters>[0]) => { + if (error) { + setSearchError(error.message); } else { - setFilteredTransforms(transforms); - } - }; - - useEffect(() => { - const filterList = () => { - if (searchQueryText !== '') { - const query = EuiSearchBar.Query.parse(searchQueryText); - let clauses: any = []; - if (query && query.ast !== undefined && query.ast.clauses !== undefined) { - clauses = query.ast.clauses; - } - updateFilteredItems(clauses); + let clauses: any = []; + if (query && query.ast !== undefined && query.ast.clauses !== undefined) { + clauses = query.ast.clauses; + } + if (clauses.length > 0) { + setFilterActive(true); + const filtered = filterTransforms(transforms, clauses); + setFilteredTransforms(filtered); } else { - updateFilteredItems([]); + setFilterActive(false); } - }; - filterList(); - // eslint-disable-next-line - }, [searchQueryText, transforms]); // missing dependency updateFilteredItems - - const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings( - TRANSFORM_LIST_COLUMN.ID, - filteredTransforms - ); + setSearchError(undefined); + } + }; // Before the transforms have been loaded for the first time, display the loading indicator only. // Otherwise a user would see 'No transforms found' during the initial loading. @@ -265,6 +261,16 @@ export const TransformList: FC = ({ ); + const search = { + toolsLeft: transformSelection.length > 0 ? renderToolsLeft() : undefined, + toolsRight, + onChange: onQueryChange, + box: { + incremental: true, + }, + filters: transformFilters, + }; + const selection = { onSelectionChange: (selected: TransformListRow[]) => setTransformSelection(selected), }; @@ -277,38 +283,30 @@ export const TransformList: FC = ({ {/* Single Action Modals */} {singleActionModals} - - {transformSelection.length > 0 ? ( - {renderToolsLeft()} - ) : null} - - - - {toolsRight} - - - + + ['onChange']} + onTableChange={onTableChange} + pagination={pagination} + rowProps={(item) => ({ + 'data-test-subj': `transformListRow row-${item.id}`, + })} selection={selection} - pagination={pagination!} sorting={sorting} + search={search} data-test-subj={`transformListTable ${ isLoading || transformsLoading ? 'loading' : 'loaded' }`} - rowProps={(item) => ({ - 'data-test-subj': `transformListRow row-${item.id}`, - })} />
    ); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx similarity index 63% rename from x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx rename to x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx index fdcb9ba5f0aff..915ae67e843e3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar_filters.tsx @@ -4,23 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Dispatch, SetStateAction, FC, Fragment, useState } from 'react'; -import { - EuiBadge, - EuiSearchBar, - EuiSearchBarProps, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - SearchFilterConfig, -} from '@elastic/eui'; +import React from 'react'; +import { EuiBadge, SearchFilterConfig } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TermClause, FieldClause, Value } from './common'; import { TRANSFORM_MODE, TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListRow } from '../../../../common'; import { getTaskStateBadge } from './use_columns'; -const filters: SearchFilterConfig[] = [ +export const transformFilters: SearchFilterConfig[] = [ { type: 'field_value_selection', field: 'state.state', @@ -114,68 +106,3 @@ export const filterTransforms = ( return filtered; }; - -function getError(errorMessage: string | null) { - if (errorMessage) { - return i18n.translate('xpack.transform.transformList.searchBar.invalidSearchErrorMessage', { - defaultMessage: 'Invalid search: {errorMessage}', - values: { errorMessage }, - }); - } - - return ''; -} - -interface Props { - searchQueryText: string; - setSearchQueryText: Dispatch>; -} - -export const TransformSearchBar: FC = ({ searchQueryText, setSearchQueryText }) => { - const [errorMessage, setErrorMessage] = useState(null); - - const onChange: EuiSearchBarProps['onChange'] = ({ query, error }) => { - if (error) { - setErrorMessage(error.message); - } else if (query !== null && query.text !== undefined) { - setSearchQueryText(query.text); - setErrorMessage(null); - } - }; - - return ( - - - {searchQueryText === undefined && ( - - )} - {searchQueryText !== undefined && ( - - )} - - - - - - ); -}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts index 9739fb6be6afb..5b7d71dacccf8 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts @@ -5,17 +5,11 @@ */ import { useState } from 'react'; -import { Direction, EuiBasicTableProps, EuiTableSortingType } from '@elastic/eui'; -import { sortBy } from 'lodash'; -import { get } from 'lodash'; +import { Direction, EuiBasicTableProps, Pagination, PropertySort } from '@elastic/eui'; const PAGE_SIZE = 10; const PAGE_SIZE_OPTIONS = [10, 25, 50]; -const propertyMap = { - Mode: 'mode', -}; - // Copying from EUI EuiBasicTable types as type is not correctly picked up for table's onChange // Can be removed when https://github.com/elastic/eui/issues/4011 is addressed in EUI export interface Criteria { @@ -46,9 +40,8 @@ interface AnalyticsBasicTableSettings { interface UseTableSettingsReturnValue { onTableChange: EuiBasicTableProps['onChange']; - pageOfItems: T[]; - pagination: EuiBasicTableProps['pagination']; - sorting: EuiTableSortingType; + pagination: Pagination; + sorting: { sort: PropertySort }; } export function useTableSettings( @@ -64,33 +57,6 @@ export function useTableSettings( sortDirection: 'asc', }); - const getPageOfItems = ( - list: TypeOfItem[], - index: number, - size: number, - sortField: keyof TypeOfItem, - sortDirection: Direction - ) => { - list = sortBy(list, (item) => - get(item, propertyMap[sortField as keyof typeof propertyMap] || sortField) - ); - list = sortDirection === 'asc' ? list : list.reverse(); - const listLength = list.length; - - let pageStart = index * size; - if (pageStart >= listLength && listLength !== 0) { - // if the page start is larger than the number of items due to - // filters being applied or items being deleted, calculate a new page start - pageStart = Math.floor((listLength - 1) / size) * size; - - setTableSettings({ ...tableSettings, pageIndex: pageStart / size }); - } - return { - pageOfItems: list.slice(pageStart, pageStart + size), - totalItemCount: listLength, - }; - }; - const onTableChange: EuiBasicTableProps['onChange'] = ({ page = { index: 0, size: PAGE_SIZE }, sort = { field: sortByField, direction: 'asc' }, @@ -109,27 +75,19 @@ export function useTableSettings( const { pageIndex, pageSize, sortField, sortDirection } = tableSettings; - const { pageOfItems, totalItemCount } = getPageOfItems( - items, - pageIndex, - pageSize, - sortField, - sortDirection - ); - const pagination = { pageIndex, pageSize, - totalItemCount, + totalItemCount: items.length, pageSizeOptions: PAGE_SIZE_OPTIONS, }; const sorting = { sort: { - field: sortField, + field: sortField as string, direction: sortDirection, }, }; - return { onTableChange, pageOfItems, pagination, sorting }; + return { onTableChange, pagination, sorting }; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8c4a66975d6ef..852c3ffd9bfd6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -540,7 +540,6 @@ "core.ui.errorUrlOverflow.optionsToFixError.enableOptionText.advancedSettingsLinkText": "高度な設定", "core.ui.errorUrlOverflow.optionsToFixError.removeStuffFromDashboardText": "コンテンツまたはフィルターを削除すると、編集しているオブジェクトがシンプルになります。", "core.ui.errorUrlOverflow.optionsToFixErrorDescription": "次を試してください。", - "core.ui.kibanaNavList.label": "Kibana", "core.ui.legacyBrowserMessage": "このElasticインストレーションは、現在ご使用のブラウザが満たしていない厳格なセキュリティ要件が有効になっています。", "core.ui.legacyBrowserTitle": "ブラウザをアップグレードしてください", "core.ui.loadingIndicatorAriaLabel": "コンテンツを読み込んでいます", @@ -1361,6 +1360,12 @@ "data.search.unableToGetSavedQueryToastTitle": "保存したクエリ {savedQueryId} を読み込めません", "data.search.upgradeLicense": "クエリがタイムアウトしました。無料のベーシックティアではクエリがタイムアウトすることはありません。", "data.search.upgradeLicenseActionText": "今すぐアップグレード", + "data.search.functions.kibana_context.filters.help": "Kibana ジェネリックフィルターを指定します", + "data.search.functions.kibana_context.help": "Kibana グローバルコンテキストを更新します", + "data.search.functions.kibana_context.q.help": "自由形式の Kibana テキストクエリを指定します", + "data.search.functions.kibana_context.savedSearchId.help": "クエリとフィルターに使用する保存検索ID を指定します。", + "data.search.functions.kibana_context.timeRange.help": "Kibana 時間範囲フィルターを指定します", + "data.search.functions.kibana.help": "Kibana グローバルコンテキストを取得します", "devTools.badge.readOnly.text": "読み込み専用", "devTools.badge.readOnly.tooltip": "を保存できませんでした", "devTools.devToolsTitle": "開発ツール", @@ -1662,12 +1667,6 @@ "expressions.functions.font.invalidFontWeightErrorMessage": "無効なフォント太さ:'{weight}'", "expressions.functions.font.invalidTextAlignmentErrorMessage": "無効なテキストアラインメント:'{align}'", "expressions.functions.fontHelpText": "フォントスタイルを作成します。", - "data.search.functions.kibana_context.filters.help": "Kibana ジェネリックフィルターを指定します", - "data.search.functions.kibana_context.help": "Kibana グローバルコンテキストを更新します", - "data.search.functions.kibana_context.q.help": "自由形式の Kibana テキストクエリを指定します", - "data.search.functions.kibana_context.savedSearchId.help": "クエリとフィルターに使用する保存検索ID を指定します。", - "data.search.functions.kibana_context.timeRange.help": "Kibana 時間範囲フィルターを指定します", - "data.search.functions.kibana.help": "Kibana グローバルコンテキストを取得します", "expressions.functions.theme.args.defaultHelpText": "テーマ情報がない場合のデフォルト値。", "expressions.functions.theme.args.variableHelpText": "読み取るテーマ変数名。", "expressions.functions.themeHelpText": "テーマ設定を読み取ります。", @@ -11648,7 +11647,6 @@ "xpack.ml.advancedSettings.anomalyDetectionDefaultTimeRangeName": "異常検知結果の時間フィルターデフォルト", "xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeDesc": "シングルメトリックビューアーと異常エクスプローラーでデフォルト時間フィルターを使用します。有効ではない場合、ジョブの全時間範囲の結果が表示されます。", "xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeName": "異常検知結果の時間フィルターデフォルトを有効にする", - "xpack.ml.analyticList.searchBar.invalidSearchErrorMessage": "無効な検索: {errorMessage}", "xpack.ml.annotationFlyout.applyToPartitionTextLabel": "注釈をこの系列に適用", "xpack.ml.annotationsTable.actionsColumnName": "アクション", "xpack.ml.annotationsTable.annotationColumnName": "注釈", @@ -19798,7 +19796,6 @@ "xpack.transform.transformList.refreshButtonLabel": "更新", "xpack.transform.transformList.rowCollapse": "{transformId} の詳細を非表示", "xpack.transform.transformList.rowExpand": "{transformId} の詳細を表示", - "xpack.transform.transformList.searchBar.invalidSearchErrorMessage": "無効な検索: {errorMessage}", "xpack.transform.transformList.showDetailsColumn.screenReaderDescription": "このカラムには変換ごとの詳細を示すクリック可能なコントロールが含まれます", "xpack.transform.transformList.startActionNameText": "開始", "xpack.transform.transformList.startedTransformBulkToolTip": "1 つまたは複数の変換が既に開始済みです。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 60b1a33c8f5c9..461b93e2e081d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -540,7 +540,6 @@ "core.ui.errorUrlOverflow.optionsToFixError.enableOptionText.advancedSettingsLinkText": "高级设置", "core.ui.errorUrlOverflow.optionsToFixError.removeStuffFromDashboardText": "通过删除内容或筛选来简化正在编辑的对象。", "core.ui.errorUrlOverflow.optionsToFixErrorDescription": "试用一下:", - "core.ui.kibanaNavList.label": "Kibana", "core.ui.legacyBrowserMessage": "此 Elastic 安装启用了当前浏览器未满足的严格安全要求。", "core.ui.legacyBrowserTitle": "请升级您的浏览器", "core.ui.loadingIndicatorAriaLabel": "正在加载内容", @@ -1362,6 +1361,12 @@ "data.search.unableToGetSavedQueryToastTitle": "无法加载已保存查询 {savedQueryId}", "data.search.upgradeLicense": "您的查询已超时。使用我们免费的基础级许可,您的查询永不会超时。", "data.search.upgradeLicenseActionText": "立即升级", + "data.search.functions.kibana_context.filters.help": "指定 Kibana 常规筛选", + "data.search.functions.kibana_context.help": "更新 kibana 全局上下文", + "data.search.functions.kibana_context.q.help": "指定 Kibana 自由格式文本查询", + "data.search.functions.kibana_context.savedSearchId.help": "指定要用于查询和筛选的已保存搜索 ID", + "data.search.functions.kibana_context.timeRange.help": "指定 Kibana 时间范围筛选", + "data.search.functions.kibana.help": "获取 kibana 全局上下文", "devTools.badge.readOnly.text": "只读", "devTools.badge.readOnly.tooltip": "无法保存", "devTools.devToolsTitle": "开发工具", @@ -1663,12 +1668,6 @@ "expressions.functions.font.invalidFontWeightErrorMessage": "无效的字体粗细:“{weight}”", "expressions.functions.font.invalidTextAlignmentErrorMessage": "无效的文本对齐方式:“{align}”", "expressions.functions.fontHelpText": "创建字体样式。", - "data.search.functions.kibana_context.filters.help": "指定 Kibana 常规筛选", - "data.search.functions.kibana_context.help": "更新 kibana 全局上下文", - "data.search.functions.kibana_context.q.help": "指定 Kibana 自由格式文本查询", - "data.search.functions.kibana_context.savedSearchId.help": "指定要用于查询和筛选的已保存搜索 ID", - "data.search.functions.kibana_context.timeRange.help": "指定 Kibana 时间范围筛选", - "data.search.functions.kibana.help": "获取 kibana 全局上下文", "expressions.functions.theme.args.defaultHelpText": "主题信息不可用时的默认值。", "expressions.functions.theme.args.variableHelpText": "要读取的主题变量的名称。", "expressions.functions.themeHelpText": "读取主题设置。", @@ -11661,7 +11660,6 @@ "xpack.ml.advancedSettings.anomalyDetectionDefaultTimeRangeName": "异常检测结果的时间筛选默认值", "xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeDesc": "使用 Single Metric Viewer 和 Anomaly Explorer 中的默认时间筛选。如果未启用,则将显示作业的整个时间范围的结果。", "xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeName": "对异常检测结果启用时间筛选默认值", - "xpack.ml.analyticList.searchBar.invalidSearchErrorMessage": "搜索无效:{errorMessage}", "xpack.ml.annotationFlyout.applyToPartitionTextLabel": "将标注应用到此系列", "xpack.ml.annotationsTable.actionsColumnName": "操作", "xpack.ml.annotationsTable.annotationColumnName": "注释", @@ -19817,7 +19815,6 @@ "xpack.transform.transformList.refreshButtonLabel": "刷新", "xpack.transform.transformList.rowCollapse": "隐藏 {transformId} 的详情", "xpack.transform.transformList.rowExpand": "显示 {transformId} 的详情", - "xpack.transform.transformList.searchBar.invalidSearchErrorMessage": "搜索无效:{errorMessage}", "xpack.transform.transformList.showDetailsColumn.screenReaderDescription": "此列包含可单击控件,用于显示每个转换的更多详情", "xpack.transform.transformList.startActionNameText": "启动", "xpack.transform.transformList.startedTransformBulkToolTip": "一个或多个选定数据帧转换已启动。", diff --git a/x-pack/test/api_integration/apis/logstash/pipelines/fixtures/list.json b/x-pack/test/api_integration/apis/logstash/pipelines/fixtures/list.json index bee5c0aa2dee2..b4c973f22ca28 100644 --- a/x-pack/test/api_integration/apis/logstash/pipelines/fixtures/list.json +++ b/x-pack/test/api_integration/apis/logstash/pipelines/fixtures/list.json @@ -1,11 +1,5 @@ { "pipelines": [ - { - "id": "tweets_and_beats", - "description": "ingest tweets and beats", - "last_modified": "2017-08-02T18:59:07.724Z", - "username": "elastic" - }, { "id": "empty_pipeline_1", "description": "an empty pipeline", @@ -13,124 +7,130 @@ "username": "elastic" }, { - "id": "empty_pipeline_2", + "id": "empty_pipeline_10", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_3", + "id": "empty_pipeline_11", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_4", + "id": "empty_pipeline_12", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_5", + "id": "empty_pipeline_13", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_6", + "id": "empty_pipeline_14", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_7", + "id": "empty_pipeline_15", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_8", + "id": "empty_pipeline_16", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_9", + "id": "empty_pipeline_17", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_10", + "id": "empty_pipeline_18", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_11", + "id": "empty_pipeline_19", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_12", + "id": "empty_pipeline_2", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_13", + "id": "empty_pipeline_20", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_14", + "id": "empty_pipeline_21", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_15", + "id": "empty_pipeline_3", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_16", + "id": "empty_pipeline_4", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_17", + "id": "empty_pipeline_5", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_18", + "id": "empty_pipeline_6", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_19", + "id": "empty_pipeline_7", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_20", + "id": "empty_pipeline_8", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" }, { - "id": "empty_pipeline_21", + "id": "empty_pipeline_9", "description": "an empty pipeline", "last_modified": "2017-08-02T18:57:32.907Z", "username": "elastic" + }, + { + "id": "tweets_and_beats", + "description": "ingest tweets and beats", + "last_modified": "2017-08-02T18:59:07.724Z", + "username": "elastic" } ] } diff --git a/x-pack/test/apm_api_integration/basic/tests/correlations/ranges.ts b/x-pack/test/apm_api_integration/basic/tests/correlations/ranges.ts index f013520fa163b..0a730217e53f5 100644 --- a/x-pack/test/apm_api_integration/basic/tests/correlations/ranges.ts +++ b/x-pack/test/apm_api_integration/basic/tests/correlations/ranges.ts @@ -6,10 +6,10 @@ import expect from '@kbn/expect'; import { format } from 'url'; -import { expectSnapshot } from '../../../common/match_snapshot'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import archives_metadata from '../../../common/archives_metadata'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { expectSnapshot } from '../../../common/match_snapshot'; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test/apm_api_integration/basic/tests/correlations/slow_durations.ts b/x-pack/test/apm_api_integration/basic/tests/correlations/slow_durations.ts index 085a81c5f1bf4..0cfdf3ec474d5 100644 --- a/x-pack/test/apm_api_integration/basic/tests/correlations/slow_durations.ts +++ b/x-pack/test/apm_api_integration/basic/tests/correlations/slow_durations.ts @@ -6,10 +6,10 @@ import expect from '@kbn/expect'; import { format } from 'url'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; +import archives_metadata from '../../../common/archives_metadata'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { expectSnapshot } from '../../../common/match_snapshot'; -import archives_metadata from '../../../common/archives_metadata'; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test/apm_api_integration/basic/tests/services/top_services.ts b/x-pack/test/apm_api_integration/basic/tests/services/top_services.ts index b4bbec1e0f861..cd2bdb7fde19e 100644 --- a/x-pack/test/apm_api_integration/basic/tests/services/top_services.ts +++ b/x-pack/test/apm_api_integration/basic/tests/services/top_services.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { isEmpty, pick } from 'lodash'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import { expectSnapshot } from '../../../common/match_snapshot'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import archives_metadata from '../../../common/archives_metadata'; diff --git a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts index d7d6d613281ef..c3b969d765664 100644 --- a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts +++ b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; import archives_metadata from '../../../common/archives_metadata'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import { expectSnapshot } from '../../../common/match_snapshot'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; diff --git a/x-pack/test/apm_api_integration/common/authentication.ts b/x-pack/test/apm_api_integration/common/authentication.ts index 46401224f0d8c..3d1e03aa032f0 100644 --- a/x-pack/test/apm_api_integration/common/authentication.ts +++ b/x-pack/test/apm_api_integration/common/authentication.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PromiseReturnType } from '../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../plugins/observability/typings/common'; import { SecurityServiceProvider } from '../../../../test/common/services/security'; type SecurityService = PromiseReturnType; diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index db073cb967423..f94bd6bd3be6f 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -9,7 +9,7 @@ import supertestAsPromised from 'supertest-as-promised'; import { format, UrlObject } from 'url'; import path from 'path'; import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context'; -import { PromiseReturnType } from '../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../plugins/observability/typings/common'; import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication'; interface Settings { diff --git a/x-pack/test/apm_api_integration/trial/tests/service_maps/service_maps.ts b/x-pack/test/apm_api_integration/trial/tests/service_maps/service_maps.ts index 0cd91eb46a5e2..25c3f753341d1 100644 --- a/x-pack/test/apm_api_integration/trial/tests/service_maps/service_maps.ts +++ b/x-pack/test/apm_api_integration/trial/tests/service_maps/service_maps.ts @@ -8,7 +8,7 @@ import querystring from 'querystring'; import expect from '@kbn/expect'; import { isEmpty, uniq } from 'lodash'; import archives_metadata from '../../../common/archives_metadata'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import { expectSnapshot } from '../../../common/match_snapshot'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; diff --git a/x-pack/test/apm_api_integration/trial/tests/services/top_services.ts b/x-pack/test/apm_api_integration/trial/tests/services/top_services.ts index 9a6c6f94dbb60..bb611013351d7 100644 --- a/x-pack/test/apm_api_integration/trial/tests/services/top_services.ts +++ b/x-pack/test/apm_api_integration/trial/tests/services/top_services.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { expectSnapshot } from '../../../common/match_snapshot'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import archives_metadata from '../../../common/archives_metadata'; diff --git a/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts b/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts index c35dfcc3817a4..47e465596e0d7 100644 --- a/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts +++ b/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { expectSnapshot } from '../../../common/match_snapshot'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../../../../plugins/observability/typings/common'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import archives_metadata from '../../../common/archives_metadata'; diff --git a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts index 4cafe049fcbc9..aabbb5d860b92 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts @@ -15,7 +15,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); const globalNav = getService('globalNav'); - const retry = getService('retry'); describe('infrastructure security', () => { describe('global infrastructure all privileges', () => { @@ -97,24 +96,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await testSubjects.existOrFail('~waffleMap'); }); - describe('context menu', () => { - before(async () => { - await testSubjects.click('~nodeContainer'); - }); - - it(`does not show link to view logs`, async () => { - await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu')); - const link = await testSubjects.find('~viewLogsContextMenuItem'); - expect(await link.isEnabled()).to.be(false); - }); - - it(`does not show link to view apm traces`, async () => { - await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu')); - const link = await testSubjects.find('~viewApmTracesContextMenuItem'); - expect(await link.isEnabled()).to.be(false); - }); - }); - it(`doesn't show read-only badge`, async () => { await globalNav.badgeMissingOrFail(); }); @@ -213,24 +194,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await testSubjects.existOrFail('~waffleMap'); }); - describe('context menu', () => { - before(async () => { - await testSubjects.click('~nodeContainer'); - }); - - it(`does not show link to view logs`, async () => { - await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu')); - const link = await testSubjects.find('~viewLogsContextMenuItem'); - expect(await link.isEnabled()).to.be(false); - }); - - it(`does not show link to view apm traces`, async () => { - await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu')); - const link = await testSubjects.find('~viewApmTracesContextMenuItem'); - expect(await link.isEnabled()).to.be(false); - }); - }); - it(`shows read-only badge`, async () => { await globalNav.badgeExistsOrFail('Read only'); }); @@ -300,19 +263,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('infra/metrics_and_logs'); }); - - it(`context menu allows user to view logs`, async () => { - await PageObjects.common.navigateToUrlWithBrowserHistory('infraOps', '', undefined, { - ensureCurrentUrl: true, - shouldLoginIfPrompted: false, - }); - await PageObjects.infraHome.goToTime(DATE_WITH_DATA); - await testSubjects.existOrFail('~waffleMap'); - await testSubjects.click('~nodeContainer'); - await retry.waitFor('context menu', () => testSubjects.exists('nodeContextMenu')); - await testSubjects.click('~viewLogsContextMenuItem'); - await testSubjects.existOrFail('~infraLogsPage'); - }); }); }); @@ -366,19 +316,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('infra/metrics_and_logs'); }); - - it(`context menu allows user to view APM traces`, async () => { - await PageObjects.common.navigateToUrlWithBrowserHistory('infraOps', '', undefined, { - ensureCurrentUrl: true, - shouldLoginIfPrompted: false, - }); - await PageObjects.infraHome.goToTime(DATE_WITH_DATA); - await testSubjects.existOrFail('~waffleMap'); - await testSubjects.click('~nodeContainer'); - await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu')); - await testSubjects.click('~viewApmTracesContextMenuItem'); - await testSubjects.existOrFail('~apmMainContainer'); - }); }); }); diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index ed0a98a45cb9c..2375a8acb6442 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -60,7 +60,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // .echLegendItem__title is the only viable way of getting the xy chart's // legend item(s), so we're using a class selector here. - expect(await find.allByCssSelector('.echLegendItem')).to.have.length(3); + // 4th item is the other bucket + expect(await find.allByCssSelector('.echLegendItem')).to.have.length(4); }); it('should create an xy visualization with filters aggregation', async () => { diff --git a/x-pack/test/functional/apps/logstash/pipeline_create.js b/x-pack/test/functional/apps/logstash/pipeline_create.js index 1fd09ce393785..c3cf102c908a0 100644 --- a/x-pack/test/functional/apps/logstash/pipeline_create.js +++ b/x-pack/test/functional/apps/logstash/pipeline_create.js @@ -15,7 +15,8 @@ export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects(['logstash']); const retry = getService('retry'); - describe('pipeline create new', () => { + // FLAKY: https://github.com/elastic/kibana/issues/83231 + describe.skip('pipeline create new', () => { let originalWindowSize; before(async () => { diff --git a/x-pack/test/functional/apps/logstash/pipeline_list.js b/x-pack/test/functional/apps/logstash/pipeline_list.js index dd6313f7b9b38..8ea3a9c49af79 100644 --- a/x-pack/test/functional/apps/logstash/pipeline_list.js +++ b/x-pack/test/functional/apps/logstash/pipeline_list.js @@ -42,16 +42,8 @@ export default function ({ getService, getPageObjects }) { expect(time).to.be.a('string').match(/ ago$/); } - const expectedRows = [ - { - selected: false, - id: 'tweets_and_beats', - description: 'ingest tweets and beats', - username: 'elastic', - }, - ]; - - for (let emptyPipelineId = 1; emptyPipelineId <= 19; ++emptyPipelineId) { + let expectedRows = []; + for (let emptyPipelineId = 1; emptyPipelineId <= 21; ++emptyPipelineId) { expectedRows.push({ selected: false, id: `empty_pipeline_${emptyPipelineId}`, @@ -59,6 +51,10 @@ export default function ({ getService, getPageObjects }) { username: 'elastic', }); } + expectedRows = expectedRows.sort((a, b) => { + return a.id.localeCompare(b.id); + }); + expectedRows.pop(); expect(rowsWithoutTime).to.eql(expectedRows); }); @@ -145,14 +141,14 @@ export default function ({ getService, getPageObjects }) { expect(rowsWithoutTime).to.eql([ { selected: false, - id: 'empty_pipeline_20', + id: 'empty_pipeline_9', description: 'an empty pipeline', username: 'elastic', }, { selected: false, - id: 'empty_pipeline_21', - description: 'an empty pipeline', + id: 'tweets_and_beats', + description: 'ingest tweets and beats', username: 'elastic', }, ]); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 11e4111696ccf..70e92e88e60be 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -473,12 +473,7 @@ export default async function ({ readConfigFile }) { logstash_read_user: { elasticsearch: { - indices: [ - { - names: ['.logstash*'], - privileges: ['read'], - }, - ], + cluster: ['manage_logstash_pipelines'], }, }, diff --git a/x-pack/test/observability_api_integration/trial/tests/annotations.ts b/x-pack/test/observability_api_integration/trial/tests/annotations.ts index f47a0f75cbfde..32e41c2c463e1 100644 --- a/x-pack/test/observability_api_integration/trial/tests/annotations.ts +++ b/x-pack/test/observability_api_integration/trial/tests/annotations.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { JsonObject } from 'src/plugins/kibana_utils/common'; import { Annotation } from '../../../../plugins/observability/common/annotations'; -import { ESSearchHit } from '../../../../plugins/apm/typings/elasticsearch'; +import { ESSearchHit } from '../../../../typings/elasticsearch'; import { FtrProviderContext } from '../../common/ftr_provider_context'; const DEFAULT_INDEX_NAME = 'observability-annotations'; diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/typings/elasticsearch/aggregations.d.ts similarity index 91% rename from x-pack/plugins/apm/typings/elasticsearch/aggregations.ts rename to x-pack/typings/elasticsearch/aggregations.d.ts index a869c1e1186fa..29c78e9383175 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/typings/elasticsearch/aggregations.d.ts @@ -202,10 +202,7 @@ type SubAggregationResponseOf< ? AggregationResponseMap : {}; -interface AggregationResponsePart< - TAggregationOptionsMap extends AggregationOptionsMap, - TDocument -> { +interface AggregationResponsePart { terms: { buckets: Array< { @@ -224,8 +221,7 @@ interface AggregationResponsePart< }; date_histogram: { buckets: Array< - DateHistogramBucket & - SubAggregationResponseOf + DateHistogramBucket & SubAggregationResponseOf >; }; avg: MetricsAggregationResponsePart; @@ -277,10 +273,7 @@ interface AggregationResponsePart< } & SubAggregationResponseOf; filters: TAggregationOptionsMap extends { filters: { filters: any[] } } ? Array< - { doc_count: number } & AggregationResponseMap< - TAggregationOptionsMap['aggs'], - TDocument - > + { doc_count: number } & AggregationResponseMap > : TAggregationOptionsMap extends { filters: { @@ -291,10 +284,7 @@ interface AggregationResponsePart< buckets: { [key in keyof TAggregationOptionsMap['filters']['filters']]: { doc_count: number; - } & SubAggregationResponseOf< - TAggregationOptionsMap['aggs'], - TDocument - >; + } & SubAggregationResponseOf; }; } : never; @@ -337,18 +327,15 @@ interface AggregationResponsePart< buckets: TAggregationOptionsMap extends { range: { keyed: true } } ? Record< string, - DateRangeBucket & - SubAggregationResponseOf + DateRangeBucket & SubAggregationResponseOf > : Array< - DateRangeBucket & - SubAggregationResponseOf + DateRangeBucket & SubAggregationResponseOf >; }; auto_date_histogram: { buckets: Array< - DateHistogramBucket & - AggregationResponseMap + DateHistogramBucket & AggregationResponseMap >; interval: string; }; @@ -389,9 +376,11 @@ interface AggregationResponsePart< // Union keys are not included in keyof. The type will fall back to keyof T if // UnionToIntersection fails, which happens when there are conflicts between the union // types, e.g. { foo: string; bar?: undefined } | { foo?: undefined; bar: string }; -export type ValidAggregationKeysOf< - T extends Record -> = keyof (UnionToIntersection extends never ? T : UnionToIntersection); +export type ValidAggregationKeysOf> = keyof (UnionToIntersection< + T +> extends never + ? T + : UnionToIntersection); export type AggregationResultOf< TAggregationOptionsMap extends AggregationOptionsMap, diff --git a/x-pack/plugins/apm/typings/elasticsearch/index.ts b/x-pack/typings/elasticsearch/index.d.ts similarity index 76% rename from x-pack/plugins/apm/typings/elasticsearch/index.ts rename to x-pack/typings/elasticsearch/index.d.ts index 9a05fe631e888..f5d595edcd71e 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/index.ts +++ b/x-pack/typings/elasticsearch/index.d.ts @@ -6,6 +6,17 @@ import { SearchParams, SearchResponse } from 'elasticsearch'; import { AggregationResponseMap, AggregationInputMap } from './aggregations'; +export { + AggregationInputMap, + AggregationOptionsByType, + AggregationResponseMap, + AggregationResultOf, + SortOptions, + ValidAggregationKeysOf, +} from './aggregations'; + +// Typings for Elasticsearch queries and aggregations. These are intended to be +// moved to the Elasticsearch JS client at some point (see #77720.) interface CollapseQuery { field: string; @@ -42,10 +53,7 @@ export type ESSearchResponse< > = Omit, 'aggregations' | 'hits'> & (TSearchRequest extends { body: { aggs: AggregationInputMap } } ? { - aggregations?: AggregationResponseMap< - TSearchRequest['body']['aggs'], - TDocument - >; + aggregations?: AggregationResponseMap; } : {}) & { hits: Omit['hits'], 'total'> & @@ -63,12 +71,6 @@ export type ESSearchResponse< export interface ESFilter { [key: string]: { - [key: string]: - | string - | string[] - | number - | boolean - | Record - | ESFilter[]; + [key: string]: string | string[] | number | boolean | Record | ESFilter[]; }; }