diff --git a/.bazelrc b/.bazelrc index 91c4870ebd126..9278352e686ef 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,12 +3,12 @@ import %workspace%/.bazelrc.common # Remote cache settings for local env -build --remote_cache=grpcs://cloud.buildbuddy.io -build --incompatible_remote_results_ignore_disk=true -build --noremote_upload_local_results -build --remote_timeout=30 -build --remote_header=x-buildbuddy-api-key=3EYk49W2NefOx2n3yMze -build --remote_accept_cached=true +# build --remote_cache=grpcs://cloud.buildbuddy.io +# build --incompatible_remote_results_ignore_disk=true +# build --noremote_upload_local_results +# build --remote_timeout=30 +# build --remote_header=x-buildbuddy-api-key=3EYk49W2NefOx2n3yMze +# build --remote_accept_cached=true # Enable this in case you want to share your build info # build --build_metadata=VISIBILITY=PUBLIC diff --git a/.buildkite/pipelines/flaky_tests/pipeline.js b/.buildkite/pipelines/flaky_tests/pipeline.js index 5f3633860dfe3..208924aefe80e 100644 --- a/.buildkite/pipelines/flaky_tests/pipeline.js +++ b/.buildkite/pipelines/flaky_tests/pipeline.js @@ -27,6 +27,8 @@ for (let i = 1; i <= XPACK_CI_GROUPS; i++) { inputs.push(stepInput(`xpack/cigroup/${i}`, `Default CI Group ${i}`)); } +inputs.push(stepInput(`xpack/cigroup/Docker`, 'Default CI Group Docker')); + const pipeline = { steps: [ { diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.js b/.buildkite/scripts/pipelines/pull_request/pipeline.js index 7b5c944d31c1c..02d6fc270ddb0 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.js +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.js @@ -66,12 +66,12 @@ const uploadPipeline = (pipelineContent) => { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/security_solution.yml')); } - // if ( - // (await doAnyChangesMatch([/^x-pack\/plugins\/apm/])) || - // process.env.GITHUB_PR_LABELS.includes('ci:all-cypress-suites') - // ) { - // pipeline.push(getPipeline('.buildkite/pipelines/pull_request/apm_cypress.yml')); - // } + if ( + (await doAnyChangesMatch([/^x-pack\/plugins\/apm/])) || + process.env.GITHUB_PR_LABELS.includes('ci:all-cypress-suites') + ) { + pipeline.push(getPipeline('.buildkite/pipelines/pull_request/apm_cypress.yml')); + } if (await doAnyChangesMatch([/^x-pack\/plugins\/uptime/])) { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/uptime.yml')); diff --git a/.buildkite/scripts/steps/functional/apm_cypress.sh b/.buildkite/scripts/steps/functional/apm_cypress.sh index 800f22c78d14c..77b26fafee920 100755 --- a/.buildkite/scripts/steps/functional/apm_cypress.sh +++ b/.buildkite/scripts/steps/functional/apm_cypress.sh @@ -2,7 +2,10 @@ set -euo pipefail -source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/common/util.sh + +.buildkite/scripts/bootstrap.sh +.buildkite/scripts/download_build_artifacts.sh export JOB=kibana-apm-cypress @@ -11,4 +14,5 @@ echo "--- APM Cypress Tests" cd "$XPACK_DIR" checks-reporter-with-killswitch "APM Cypress Tests" \ - node plugins/apm/scripts/test/e2e.js + node plugins/apm/scripts/test/e2e.js \ + --kibana-install-dir "$KIBANA_BUILD_LOCATION" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ec03acc752d55..227041522ac78 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -95,15 +95,15 @@ # Observability Shared /x-pack/plugins/observability/ @elastic/observability-ui -# Logs and Metrics (Infra) -/x-pack/plugins/infra/ @elastic/logs-metrics-ui -/x-pack/plugins/infra/server/routes/log* @elastic/logs-metrics-ui @elastic/logs-ui -/x-pack/plugins/infra/public/pages/logs/ @elastic/logs-metrics-ui @elastic/logs-ui -/x-pack/plugins/infra/server/routes/metrics* @elastic/logs-metrics-ui @elastic/metrics-ui -/x-pack/plugins/infra/public/pages/metrics/ @elastic/logs-metrics-ui @elastic/metrics-ui +# Infra Monitoring +/x-pack/plugins/infra/ @elastic/infra-monitoring-ui +/x-pack/test/functional/apps/infra @elastic/infra-monitoring-ui +/x-pack/test/api_integration/apis/infra @elastic/infra-monitoring-ui -# Stack Monitoring -/x-pack/plugins/monitoring/ @elastic/stack-monitoring-ui @elastic/logs-metrics-ui @elastic/metrics-ui +# Elastic Stack Monitoring +/x-pack/plugins/monitoring/ @elastic/infra-monitoring-ui +/x-pack/test/functional/apps/monitoring @elastic/infra-monitoring-ui +/x-pack/test/api_integration/apis/monitoring @elastic/infra-monitoring-ui # Fleet /x-pack/plugins/fleet/ @elastic/fleet @@ -289,6 +289,7 @@ /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-core /src/plugins/interactive_setup/ @elastic/kibana-security /test/interactive_setup_api_integration/ @elastic/kibana-security +/test/interactive_setup_functional/ @elastic/kibana-security /x-pack/plugins/spaces/ @elastic/kibana-security /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security diff --git a/.github/workflows/add-to-apm-project.yml b/.github/workflows/add-to-apm-project.yml new file mode 100644 index 0000000000000..26ff71fbdca8c --- /dev/null +++ b/.github/workflows/add-to-apm-project.yml @@ -0,0 +1,28 @@ +name: Add to APM Project +on: + issues: + types: + - labeled +jobs: + add_to_project: + runs-on: ubuntu-latest + steps: + - uses: octokit/graphql-action@v2.x + id: add_to_project + if: | + github.event.label.name == 'Team:apm' + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + mutation add_to_project($projectid:String!,$contentid:String!) { + addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { + projectNextItem { + id + } + } + } + projectid: ${{ env.PROJECT_ID }} + contentid: ${{ github.event.issue.node_id }} + env: + PROJECT_ID: "PN_kwDOAGc3Zs0VSg" + GITHUB_TOKEN: ${{ secrets.APM_TECH_KIBANA_USER_TOKEN }} diff --git a/api_docs/cases.json b/api_docs/cases.json index c35220cda3c66..aedf69d28559f 100644 --- a/api_docs/cases.json +++ b/api_docs/cases.json @@ -7610,10 +7610,10 @@ }, { "parentPluginId": "cases", - "id": "def-common.ConnectorResillientTypeFields", + "id": "def-common.ConnectorResilientTypeFields", "type": "Type", "tags": [], - "label": "ConnectorResillientTypeFields", + "label": "ConnectorResilientTypeFields", "description": [], "signature": [ "{ type: ", diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 341a6b6b6bb33..fda6834f9b4e9 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -16,9 +16,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | securitySolution | - | | | dataViews, visTypeTimeseries, reporting, discover, observability, maps, dataVisualizer, apm, lens, osquery, securitySolution, transform, savedObjects, indexPatternFieldEditor, visualizations, dashboard, graph, stackAlerts, uptime, indexPatternEditor, indexPatternManagement, inputControlVis, savedObjectsManagement, visualize, visDefaultEditor, visTypeVega, data | - | | | dataViews, discover, maps, dataVisualizer, lens, indexPatternFieldEditor, securitySolution, indexPatternEditor, indexPatternManagement, inputControlVis, visDefaultEditor, visTypeTimeseries, data | - | -| | dataViews, timelines, monitoring, securitySolution, indexPatternManagement, stackAlerts, transform | - | -| | home, savedObjects, security, fleet, indexPatternFieldEditor, discover, visualizations, dashboard, lens, observability, maps, fileUpload, dataVisualizer, ml, infra, apm, graph, monitoring, osquery, securitySolution, stackAlerts, transform, upgradeAssistant, uptime, indexPatternEditor, indexPatternManagement, inputControlVis, kibanaOverview, savedObjectsManagement, visualize, visTypeTimelion, visTypeTimeseries, visTypeVega | - | -| | dataViews, timelines, monitoring, securitySolution, indexPatternManagement, stackAlerts, transform, data | - | +| | dataViews, timelines, monitoring, securitySolution, indexPatternManagement, presentationUtil, stackAlerts, transform | - | +| | home, savedObjects, security, fleet, indexPatternFieldEditor, discover, dashboard, lens, observability, maps, fileUpload, dataVisualizer, ml, infra, graph, monitoring, osquery, securitySolution, stackAlerts, transform, upgradeAssistant, uptime, indexPatternEditor, indexPatternManagement, inputControlVis, kibanaOverview, savedObjectsManagement, visualize, visTypeTimelion, visTypeTimeseries, visTypeVega | - | +| | dataViews, timelines, monitoring, securitySolution, indexPatternManagement, presentationUtil, stackAlerts, transform, data | - | | | dataViews, discover, maps, dataVisualizer, lens, indexPatternFieldEditor, securitySolution, indexPatternEditor, indexPatternManagement, inputControlVis, visDefaultEditor, visTypeTimeseries, data | - | | | dataViews, visTypeTimeseries, reporting, discover, observability, maps, dataVisualizer, apm, lens, osquery, securitySolution, transform, savedObjects, indexPatternFieldEditor, visualizations, dashboard, graph, stackAlerts, uptime, indexPatternEditor, indexPatternManagement, inputControlVis, savedObjectsManagement, visualize, visDefaultEditor, visTypeVega, data | - | | | dataViews, discover, maps, dataVisualizer, lens, indexPatternFieldEditor, securitySolution, indexPatternEditor, indexPatternManagement, inputControlVis, visDefaultEditor, visTypeTimeseries | - | @@ -29,27 +29,30 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | dashboard, lens, maps, ml, securitySolution, security, visualize | - | | | securitySolution | - | | | dataViews, visTypeTimeseries, maps, lens, discover, data | - | -| | dataViews, discover, observability, savedObjects, security, visualizations, dashboard, lens, maps, graph, stackAlerts, transform, indexPatternManagement, inputControlVis, savedObjectsManagement, visTypeTimelion, data | - | +| | dataViews, discover, observability, savedObjects, security, dashboard, lens, maps, graph, stackAlerts, transform, indexPatternManagement, inputControlVis, savedObjectsManagement, visTypeTimelion, data | - | | | dataViews, discover, transform, canvas | - | -| | dataViews, observability, indexPatternEditor, apm | - | +| | dataViews, observability, indexPatternEditor | - | | | dataViews | - | | | dataViews, indexPatternManagement | - | | | dataViews, discover, transform, canvas, data | - | | | dataViews, data | - | | | dataViews, data | - | | | dataViews | - | -| | dataViews, observability, indexPatternEditor, apm, data | - | +| | dataViews, observability, indexPatternEditor, data | - | | | dataViews, visualizations, dashboard, data | - | | | dataViews, data | - | | | dataViews, visTypeTimeseries, maps, lens, discover, data | - | -| | dataViews, discover, observability, savedObjects, security, visualizations, dashboard, lens, maps, graph, stackAlerts, transform, indexPatternManagement, inputControlVis, savedObjectsManagement, visTypeTimelion, data | - | +| | dataViews, discover, observability, savedObjects, security, dashboard, lens, maps, graph, stackAlerts, transform, indexPatternManagement, inputControlVis, savedObjectsManagement, visTypeTimelion, data | - | | | dataViews, discover, dashboard, lens, visualize | - | | | dataViews, indexPatternManagement, data | - | +| | dataViews, maps | - | | | dataViews, discover, transform, canvas | - | | | dataViews, visTypeTimeseries, maps, lens, discover | - | +| | dataViews, maps | - | | | fleet, indexPatternFieldEditor, discover, dashboard, lens, ml, stackAlerts, indexPatternManagement, visTypePie, visTypeTable, visTypeTimeseries, visTypeXy, visTypeVislib | - | | | reporting, visTypeTimeseries | - | | | data, lens, visTypeTimeseries, infra, maps, visTypeTimelion | - | +| | maps | - | | | dashboard, maps, graph, visualize | - | | | spaces, security, reporting, actions, alerting, ml, fleet, remoteClusters, graph, indexLifecycleManagement, maps, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | - | | | discover, dashboard, lens, visualize | - | @@ -57,9 +60,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | discover | - | | | discover | - | | | embeddable, presentationUtil, discover, dashboard, graph | - | -| | discover, visualizations, dashboard | - | -| | savedObjectsTaggingOss, discover, visualizations, dashboard | - | -| | discover, visualizations, dashboard | - | | | data, discover, embeddable | - | | | advancedSettings, discover | - | | | advancedSettings, discover | - | @@ -68,7 +68,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | security | - | | | security, licenseManagement, ml, fleet, apm, reporting, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | - | | | management, fleet, security, kibanaOverview | - | -| | visualizations | - | +| | dashboard | - | +| | savedObjectsTaggingOss, dashboard | - | +| | dashboard | - | | | spaces, savedObjectsManagement | - | | | spaces, savedObjectsManagement | - | | | reporting | - | @@ -103,14 +105,14 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | discover, visualizations, dashboard, lens, observability, timelines, maps, infra, dashboardEnhanced, discoverEnhanced, securitySolution, urlDrilldown, inputControlVis, visualize, visTypeTimelion, visTypeVega, ml, visTypeTimeseries | 8.1 | | | discover, visualizations, dashboard, lens, observability, timelines, maps, infra, dashboardEnhanced, discoverEnhanced, securitySolution, urlDrilldown, inputControlVis, visualize, visTypeTimelion, visTypeVega, ml, visTypeTimeseries | 8.1 | | | discover, visualizations, dashboard, lens, observability, timelines, maps, infra, dashboardEnhanced, discoverEnhanced, securitySolution, urlDrilldown, inputControlVis, visualize, visTypeTimelion, visTypeVega, ml, visTypeTimeseries | 8.1 | -| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement | 8.1 | -| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement, data | 8.1 | +| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement, presentationUtil | 8.1 | +| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement, presentationUtil, data | 8.1 | | | dataViews | 8.1 | | | dataViews | 8.1 | | | indexPatternManagement, dataViews | 8.1 | | | visTypeTimeseries, graph, indexPatternManagement, dataViews | 8.1 | | | dataViews, indexPatternManagement | 8.1 | -| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement | 8.1 | +| | dataViews, fleet, infra, monitoring, stackAlerts, indexPatternManagement, presentationUtil | 8.1 | | | dataViews | 8.1 | | | dataViews | 8.1 | | | indexPatternManagement, dataViews | 8.1 | @@ -125,8 +127,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | lens, infra, apm, graph, monitoring, stackAlerts, transform | 8.1 | | | observability | 8.1 | | | observability | 8.1 | -| | visualizations, visDefaultEditor | 8.1 | -| | visualizations, visDefaultEditor | 8.1 | | | indexPatternManagement | 8.1 | | | indexPatternManagement | 8.1 | | | indexPatternManagement | 8.1 | @@ -136,6 +136,8 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | indexPatternFieldEditor | 8.1 | | | indexPatternFieldEditor | 8.1 | | | indexPatternFieldEditor | 8.1 | +| | visualizations, visDefaultEditor | 8.1 | +| | visualizations, visDefaultEditor | 8.1 | | | visualize | 8.1 | | | timelines | 8.1 | | | timelines | 8.1 | @@ -214,8 +216,6 @@ Safe to remove. | | | | | | -| | -| | | | | | | | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 7ef3a75269963..d405da72f959c 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -48,19 +48,16 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern)+ 4 more | - | -| | [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec) | - | -| | [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=indexPatterns) | - | +| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=esKuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=esKuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=esKuery) | 8.1 | -| | [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPatternSpec) | - | -| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern)+ 4 more | - | -| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [use_index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/use_index_pattern.ts#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/shared/kuery_bar/index.tsx#:~:text=IndexPattern) | - | +| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern) | - | +| | [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [SelectedFilters.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/SelectedFilters.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern), [selected_wildcards.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/components/app/RumDashboard/LocalUIFilters/selected_wildcards.tsx#:~:text=IndexPattern) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/plugin.ts#:~:text=environment) | - | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | - | | | [license_context.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/public/context/license/license_context.tsx#:~:text=license%24) | - | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | - | -| | [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/server/routes/index_pattern.ts#:~:text=spacesService) | 7.16 | -| | [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/server/routes/index_pattern.ts#:~:text=getSpaceId) | 7.16 | +| | [data_view.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/server/routes/data_view.ts#:~:text=spacesService) | 7.16 | +| | [data_view.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/apm/server/routes/data_view.ts#:~:text=getSpaceId) | 7.16 | @@ -228,6 +225,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern) | - | | | [data_views.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_views.ts#:~:text=IndexPatternListItem), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternListItem) | - | | | [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [update_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/update_index_pattern.ts#:~:text=intervalName), [update_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/update_index_pattern.ts#:~:text=intervalName) | 8.1 | +| | [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=flattenHit) | - | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=addScriptedField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=addScriptedField) | 8.1 | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=removeScriptedField) | 8.1 | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getNonScriptedFields) | 8.1 | @@ -238,6 +236,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternsService) | - | | | [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=intervalName), [update_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/update_index_pattern.ts#:~:text=intervalName), [update_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/update_index_pattern.ts#:~:text=intervalName) | 8.1 | +| | [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=flattenHit) | - | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=addScriptedField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=addScriptedField) | 8.1 | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=removeScriptedField) | 8.1 | | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getNonScriptedFields) | 8.1 | @@ -250,11 +249,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern)+ 60 more | - | -| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 16 more | - | +| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 20 more | - | | | [file_data_visualizer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/file_data_visualizer.tsx#:~:text=indexPatterns), [index_data_visualizer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx#:~:text=indexPatterns) | - | -| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 16 more | - | +| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 20 more | - | | | [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern)+ 60 more | - | -| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 3 more | - | +| | [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_data_row.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/types/field_data_row.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [field_types_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/util/field_types_utils.ts#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [search_panel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/search_panel/search_panel.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField), [index_data_visualizer_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx#:~:text=IndexPatternField)+ 5 more | - | | | [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [lens_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/lens_utils.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [geo_point_content_with_map.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/geo_point_content_with_map/geo_point_content_with_map.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern), [index_based_expanded_row.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/data_visualizer/public/application/common/components/expanded_row/index_based_expanded_row.tsx#:~:text=IndexPattern)+ 25 more | - | @@ -264,38 +263,35 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService)+ 6 more | - | -| | [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract)+ 34 more | - | -| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 378 more | - | -| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField)+ 192 more | - | +| | [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract)+ 26 more | - | +| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 382 more | - | +| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField)+ 198 more | - | | | [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes)+ 3 more | - | | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=create), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=create) | - | | | [anchor.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/services/anchor.ts#:~:text=fetch), [fetch_hits_in_interval.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/services/utils/fetch_hits_in_interval.ts#:~:text=fetch) | 8.1 | -| | [build_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/build_services.ts#:~:text=indexPatterns), [source_viewer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/source_viewer/source_viewer.tsx#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [plugin.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/plugin.tsx#:~:text=indexPatterns) | - | +| | [build_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/build_services.ts#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=indexPatterns), [plugin.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/plugin.tsx#:~:text=indexPatterns) | - | | | [histogram.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/chart/histogram.tsx#:~:text=fieldFormats) | - | | | [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=esFilters), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=esFilters), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=esFilters), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=esFilters), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=esFilters), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=esFilters), [get_context_url.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/get_context_url.tsx#:~:text=esFilters), [get_context_url.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/get_context_url.tsx#:~:text=esFilters), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=esFilters), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=esFilters)+ 17 more | 8.1 | | | [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter)+ 22 more | 8.1 | | | [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes)+ 16 more | - | -| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField)+ 192 more | - | +| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField)+ 198 more | - | | | [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService)+ 6 more | - | -| | [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract)+ 34 more | - | +| | [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_data_grid_columns.ts#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [use_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/use_index_pattern.tsx#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/utils/resolve_index_pattern.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [use_data_grid_columns.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/helpers/use_data_grid_columns.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract), [resolve_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/utils/resolve_index_pattern.d.ts#:~:text=IndexPatternsContract)+ 26 more | - | | | [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=ensureDefaultDataView), [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=ensureDefaultDataView) | - | -| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 378 more | - | +| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 382 more | - | | | [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter)+ 22 more | 8.1 | | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=create), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=create) | - | | | [anchor.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/services/anchor.ts#:~:text=fetch), [fetch_hits_in_interval.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/services/utils/fetch_hits_in_interval.ts#:~:text=fetch) | 8.1 | -| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField), [discover_field_visualize.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field_visualize.tsx#:~:text=IndexPatternField)+ 91 more | - | +| | [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [discover_grid_cell_actions.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [doc_table_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/doc_table_wrapper.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [data_visualizer_grid.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/data_visualizer_grid/data_visualizer_grid.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=IndexPatternField), [context_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/context/context_app.tsx#:~:text=IndexPatternField)+ 94 more | - | | | [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_index_pattern.tsx#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_index_pattern.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/apps/main/components/sidebar/discover_index_pattern.d.ts#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [discover_sidebar_responsive.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/layout/types.ts#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes), [discover_main_app.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_app.tsx#:~:text=IndexPatternAttributes)+ 3 more | - | -| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 184 more | - | +| | [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_flyout.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [discover_grid_context.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [get_render_cell_value.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern), [discover_grid_columns.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx#:~:text=IndexPattern)+ 186 more | - | | | [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [popularize_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/helpers/popularize_field.test.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService), [index_patterns.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/__mocks__/index_patterns.ts#:~:text=IndexPatternsService)+ 6 more | - | | | [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [url_generator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/url_generator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [locator.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/locator.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/types.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter), [discover_state.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/services/discover_state.ts#:~:text=Filter)+ 22 more | 8.1 | | | [discover_main_route.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/discover_main_route.tsx#:~:text=ensureDefaultDataView) | - | | | [on_save_search.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal), [on_save_search.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/apps/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal) | - | -| | [saved_searches.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/saved_searches/legacy/saved_searches.ts#:~:text=SavedObjectLoader), [saved_searches.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/saved_searches/legacy/saved_searches.ts#:~:text=SavedObjectLoader), [plugin.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/plugin.tsx#:~:text=SavedObjectLoader), [plugin.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/plugin.tsx#:~:text=SavedObjectLoader) | - | -| | [_saved_search.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/saved_searches/legacy/_saved_search.ts#:~:text=SavedObject), [_saved_search.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/saved_searches/legacy/_saved_search.ts#:~:text=SavedObject) | - | -| | [_saved_search.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/saved_searches/legacy/_saved_search.ts#:~:text=SavedObjectClass) | - | | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx#:~:text=executeTriggerActions), [search_embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts#:~:text=executeTriggerActions), [plugin.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/discover/public/plugin.tsx#:~:text=executeTriggerActions), [search_embeddable_factory.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/target/types/public/application/embeddable/search_embeddable_factory.d.ts#:~:text=executeTriggerActions) | - | -| | [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric) | - | -| | [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric) | - | +| | [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric) | - | +| | [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/master/src/plugins/discover/server/ui_settings.ts#:~:text=metric) | - | @@ -443,7 +439,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType) | 8.1 | | | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IndexPatternListItem), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IndexPatternListItem), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IndexPatternListItem), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IndexPatternListItem), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IndexPatternListItem), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IndexPatternListItem), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IndexPatternListItem), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IndexPatternListItem) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/constants/index.ts#:~:text=getKbnTypeNames), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/constants/index.ts#:~:text=getKbnTypeNames) | 8.1 | -| | [edit_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx#:~:text=indexPatterns), [edit_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx#:~:text=indexPatterns), [edit_index_pattern_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern_container.tsx#:~:text=indexPatterns), [edit_index_pattern_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern_container.tsx#:~:text=indexPatterns), [create_edit_field.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx#:~:text=indexPatterns), [create_edit_field_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field_container.tsx#:~:text=indexPatterns), [create_edit_field_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field_container.tsx#:~:text=indexPatterns) | - | +| | [scripted_fields_table.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx#:~:text=indexPatterns), [tabs.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx#:~:text=indexPatterns), [edit_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx#:~:text=indexPatterns), [edit_index_pattern.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx#:~:text=indexPatterns), [edit_index_pattern_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern_container.tsx#:~:text=indexPatterns), [edit_index_pattern_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern_container.tsx#:~:text=indexPatterns), [create_edit_field.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx#:~:text=indexPatterns), [create_edit_field_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field_container.tsx#:~:text=indexPatterns), [create_edit_field_container.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field_container.tsx#:~:text=indexPatterns) | - | | | [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats), [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats), [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats), [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats), [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats), [field_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx#:~:text=fieldFormats) | - | | | [test_script.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.tsx#:~:text=esQuery), [test_script.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.tsx#:~:text=esQuery), [test_script.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.tsx#:~:text=esQuery) | 8.1 | | | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/public/components/utils.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType), [utils.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/index_pattern_management/target/types/public/components/utils.d.ts#:~:text=IFieldType) | 8.1 | @@ -541,18 +537,18 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService) | - | -| | [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract)+ 20 more | - | +| | [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract)+ 22 more | - | | | [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPattern), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/existing_fields.d.ts#:~:text=IndexPattern), [existing_fields.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/existing_fields.d.ts#:~:text=IndexPattern), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPattern), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPattern)+ 36 more | - | | | [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField)+ 8 more | - | | | [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=indexPatterns), [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=indexPatterns), [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=indexPatterns), [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=indexPatterns), [indexpattern.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx#:~:text=indexPatterns), [lens_top_nav.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx#:~:text=indexPatterns), [lens_top_nav.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx#:~:text=indexPatterns), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/plugin.ts#:~:text=indexPatterns), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/plugin.ts#:~:text=indexPatterns) | - | | | [ranges.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx#:~:text=fieldFormats), [droppable.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts#:~:text=fieldFormats) | - | -| | [save_modal_container.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx#:~:text=esFilters), [save_modal_container.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx#:~:text=esFilters), [mocks.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/mocks.tsx#:~:text=esFilters), [mocks.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/mocks.tsx#:~:text=esFilters) | 8.1 | +| | [save_modal_container.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx#:~:text=esFilters), [save_modal_container.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx#:~:text=esFilters), [data_plugin_mock.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts#:~:text=esFilters), [data_plugin_mock.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts#:~:text=esFilters) | 8.1 | | | [validation.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts#:~:text=esKuery), [validation.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts#:~:text=esKuery), [validation.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts#:~:text=esKuery) | 8.1 | | | [validation.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts#:~:text=esQuery), [validation.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx#:~:text=esQuery), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=esQuery), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=esQuery), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=esQuery), [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=esQuery), [datapanel.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx#:~:text=esQuery)+ 1 more | 8.1 | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/state_management/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/state_management/types.ts#:~:text=Filter), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=Filter), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=Filter)+ 16 more | 8.1 | | | [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts#:~:text=IndexPatternField), [field_stats.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/field_stats.ts#:~:text=IndexPatternField)+ 8 more | - | | | [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPatternsService) | - | -| | [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract)+ 20 more | - | +| | [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/utils.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [embeddable_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract), [loader.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts#:~:text=IndexPatternsContract)+ 22 more | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/plugin.ts#:~:text=ensureDefaultDataView), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/plugin.ts#:~:text=ensureDefaultDataView) | - | | | [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPattern), [existing_fields.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/server/routes/existing_fields.test.ts#:~:text=IndexPattern), [existing_fields.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/existing_fields.d.ts#:~:text=IndexPattern), [existing_fields.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/target/types/server/routes/existing_fields.d.ts#:~:text=IndexPattern), [loader.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts#:~:text=IndexPattern), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=IndexPattern)+ 36 more | - | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/types.ts#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [embeddable.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/embeddable/embeddable.tsx#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/state_management/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/state_management/types.ts#:~:text=Filter), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=Filter), [field_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx#:~:text=Filter)+ 16 more | 8.1 | @@ -608,12 +604,15 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/lazy_load_bundle/index.ts#:~:text=IndexPatternsContract), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/lazy_load_bundle/index.ts#:~:text=IndexPatternsContract), [index.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/public/lazy_load_bundle/index.d.ts#:~:text=IndexPatternsContract), [index.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/public/lazy_load_bundle/index.d.ts#:~:text=IndexPatternsContract), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/lazy_load_bundle/index.ts#:~:text=IndexPatternsContract), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/lazy_load_bundle/index.ts#:~:text=IndexPatternsContract), [index.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/public/lazy_load_bundle/index.d.ts#:~:text=IndexPatternsContract), [index.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/public/lazy_load_bundle/index.d.ts#:~:text=IndexPatternsContract) | - | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#:~:text=IndexPattern), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPattern), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPattern), [agg_field_types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts#:~:text=IndexPattern), [agg_field_types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts#:~:text=IndexPattern), [percentile_agg_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts#:~:text=IndexPattern), [percentile_agg_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts#:~:text=IndexPattern), [es_geo_grid_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx#:~:text=IndexPattern), [es_geo_grid_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx#:~:text=IndexPattern)+ 206 more | - | +| | [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit) | - | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/reducers/map/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/reducers/map/types.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [vector_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx#:~:text=Filter), [vector_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx#:~:text=Filter), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=Filter), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=Filter)+ 115 more | 8.1 | | | [es_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#:~:text=fetch), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=fetch), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=fetch) | 8.1 | | | [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPatternField), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPatternField), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPatternField), [es_agg_utils.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/common/elasticsearch_util/es_agg_utils.d.ts#:~:text=IndexPatternField), [es_agg_utils.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/common/elasticsearch_util/es_agg_utils.d.ts#:~:text=IndexPatternField), [es_agg_utils.d.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/target/types/common/elasticsearch_util/es_agg_utils.d.ts#:~:text=IndexPatternField), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=IndexPatternField), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=IndexPatternField), [es_doc_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#:~:text=IndexPatternField), [es_doc_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#:~:text=IndexPatternField)+ 129 more | - | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#:~:text=IndexPattern), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPattern), [es_agg_utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts#:~:text=IndexPattern), [agg_field_types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts#:~:text=IndexPattern), [agg_field_types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts#:~:text=IndexPattern), [percentile_agg_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts#:~:text=IndexPattern), [percentile_agg_field.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts#:~:text=IndexPattern), [es_geo_grid_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx#:~:text=IndexPattern), [es_geo_grid_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx#:~:text=IndexPattern)+ 98 more | - | | | [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService), [create_doc_source.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/create_doc_source.ts#:~:text=IndexPatternsService) | - | +| | [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit) | - | | | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/reducers/map/types.ts#:~:text=Filter), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/reducers/map/types.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts#:~:text=Filter), [vector_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx#:~:text=Filter), [vector_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx#:~:text=Filter), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=Filter), [es_tooltip_property.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/tooltips/es_tooltip_property.ts#:~:text=Filter)+ 115 more | 8.1 | +| | [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit), [es_search_source.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx#:~:text=flattenHit) | - | | | [kibana_server_services.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/kibana_server_services.ts#:~:text=indexPatternsServiceFactory), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/plugin.ts#:~:text=indexPatternsServiceFactory), [indexing_routes.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/data_indexing/indexing_routes.ts#:~:text=indexPatternsServiceFactory) | - | | | [maps_list_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx#:~:text=settings), [maps_list_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx#:~:text=settings), [maps_list_view.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx#:~:text=settings) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/server/plugin.ts#:~:text=license%24) | - | @@ -683,11 +682,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern)+ 2 more | - | -| | [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=indexPatterns), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=indexPatterns) | - | -| | [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern)+ 2 more | - | -| | [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_errors.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [use_scheduled_query_group_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/use_scheduled_query_group_query_last_results.ts#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern), [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=IndexPattern) | - | -| | [scheduled_query_group_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/scheduled_query_groups/scheduled_query_group_queries_status_table.tsx#:~:text=urlGenerator), [use_discover_link.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/common/hooks/use_discover_link.tsx#:~:text=urlGenerator) | - | +| | [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern)+ 2 more | - | +| | [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=indexPatterns), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=indexPatterns) | - | +| | [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern)+ 2 more | - | +| | [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_errors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_errors.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [use_pack_query_last_results.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/use_pack_query_last_results.ts#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern), [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=IndexPattern) | - | +| | [pack_queries_status_table.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx#:~:text=urlGenerator), [use_discover_link.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/osquery/public/common/hooks/use_discover_link.tsx#:~:text=urlGenerator) | - | @@ -704,7 +703,12 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| +| | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern) | - | +| | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType) | 8.1 | | | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=esFilters), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=esFilters) | 8.1 | +| | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType)+ 10 more | 8.1 | +| | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IIndexPattern)+ 10 more | - | +| | [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_embeddable.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType), [options_list_editor.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_editor.tsx#:~:text=IFieldType) | 8.1 | | | [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal) | - | @@ -826,23 +830,23 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_risky_hosts_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts#:~:text=dashboardUrlGenerator), [use_risky_hosts_dashboard_links.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx#:~:text=dashboardUrlGenerator), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=dashboardUrlGenerator) | - | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern)+ 30 more | - | | | [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField) | - | -| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 74 more | - | +| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 74 more | - | | | [middleware.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=indexPatterns), [plugin.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=indexPatterns), [dependencies_start_mock.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/mock/endpoint/dependencies_start_mock.ts#:~:text=indexPatterns) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters)+ 14 more | 8.1 | | | [expandable_network.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx#:~:text=esQuery), [expandable_network.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx#:~:text=esQuery), [events_viewer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx#:~:text=esQuery), [events_viewer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx#:~:text=esQuery)+ 30 more | 8.1 | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter)+ 163 more | 8.1 | -| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 158 more | - | +| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter)+ 165 more | 8.1 | +| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 158 more | - | | | [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField) | - | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern)+ 30 more | - | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter)+ 163 more | 8.1 | +| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter)+ 165 more | 8.1 | | | [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField) | - | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern)+ 10 more | - | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter)+ 163 more | 8.1 | +| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx#:~:text=Filter)+ 165 more | 8.1 | | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [isolation.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts#:~:text=mode), [isolation.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts#:~:text=mode)+ 4 more | - | | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [isolation.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts#:~:text=mode), [isolation.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts#:~:text=mode)+ 4 more | - | -| | [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=spacesService), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=spacesService) | 7.16 | -| | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=getSpaceId), [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=getSpaceId) | 7.16 | +| | [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [preview_rules_route.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts#:~:text=authc), [request_context_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=spacesService), [request_context_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=spacesService), [request_context_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=spacesService) | 7.16 | +| | [plugin.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/plugin.ts#:~:text=getSpaceId), [request_context_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=getSpaceId), [request_context_factory.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=getSpaceId) | 7.16 | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/index.tsx#:~:text=onAppLeave) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/template_wrapper/bottom_bar/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/template_wrapper/bottom_bar/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/home/index.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler)+ 3 more | - | @@ -894,11 +898,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=IIndexPattern), [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=IIndexPattern) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType) | 8.1 | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=esQuery) | 8.1 | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter)+ 5 more | 8.1 | +| | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter)+ 5 more | 8.1 | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=IIndexPattern), [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=IIndexPattern), [index_pattern.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx#:~:text=IIndexPattern)+ 8 more | - | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter)+ 5 more | 8.1 | +| | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter)+ 5 more | 8.1 | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType) | 8.1 | -| | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx#:~:text=Filter)+ 5 more | 8.1 | +| | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/cells/index.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/store/t_grid/model.ts#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx#:~:text=Filter)+ 5 more | 8.1 | | | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx#:~:text=IFieldSubType) | 8.1 | @@ -1073,23 +1077,16 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract) | - | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern)+ 10 more | - | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=toJSON) | 8.1 | -| | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/plugin.ts#:~:text=indexPatterns) | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=esFilters), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=esFilters) | 8.1 | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | | | [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE)+ 8 more | - | -| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract) | - | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern)+ 10 more | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=toJSON) | 8.1 | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern) | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | -| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=__LEGACY), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=__LEGACY) | - | -| | [find_list_items.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/find_list_items.ts#:~:text=SavedObjectLoader), [find_list_items.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/find_list_items.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader) | - | -| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject) | - | -| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObjectClass) | - | diff --git a/api_docs/elastic_apm_generator.json b/api_docs/elastic_apm_generator.json deleted file mode 100644 index 24f11791d92b6..0000000000000 --- a/api_docs/elastic_apm_generator.json +++ /dev/null @@ -1,288 +0,0 @@ -{ - "id": "@elastic/apm-generator", - "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getBreakdownMetrics", - "type": "Function", - "tags": [], - "label": "getBreakdownMetrics", - "description": [], - "signature": [ - "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]) => Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_breakdown_metrics.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getBreakdownMetrics.$1", - "type": "Array", - "tags": [], - "label": "events", - "description": [], - "signature": [ - "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_breakdown_metrics.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getObserverDefaults", - "type": "Function", - "tags": [], - "label": "getObserverDefaults", - "description": [], - "signature": [ - "() => Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>" - ], - "path": "packages/elastic-apm-generator/src/lib/defaults/get_observer_defaults.ts", - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getSpanDestinationMetrics", - "type": "Function", - "tags": [], - "label": "getSpanDestinationMetrics", - "description": [], - "signature": [ - "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]) => { \"metricset.name\": string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; '@timestamp'?: number | undefined; 'agent.name'?: string | undefined; 'agent.version'?: string | undefined; 'container.id'?: string | undefined; 'ecs.version'?: string | undefined; 'event.outcome'?: string | undefined; 'event.ingested'?: number | undefined; 'host.name'?: string | undefined; 'observer.version'?: string | undefined; 'observer.version_major'?: number | undefined; 'parent.id'?: string | undefined; 'processor.event'?: string | undefined; 'processor.name'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; 'transaction.id'?: string | undefined; 'transaction.duration.us'?: number | undefined; 'transaction.duration.histogram'?: { values: number[]; counts: number[]; } | undefined; 'transaction.sampled'?: true | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'service.node.name'?: string | undefined; 'span.id'?: string | undefined; 'span.name'?: string | undefined; 'span.type'?: string | undefined; 'span.subtype'?: string | undefined; 'span.duration.us'?: number | undefined; 'span.destination.service.name'?: string | undefined; 'span.destination.service.resource'?: string | undefined; 'span.destination.service.type'?: string | undefined; 'span.self_time.count'?: number | undefined; 'span.self_time.sum.us'?: number | undefined; }[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getSpanDestinationMetrics.$1", - "type": "Array", - "tags": [], - "label": "events", - "description": [], - "signature": [ - "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getTransactionMetrics", - "type": "Function", - "tags": [], - "label": "getTransactionMetrics", - "description": [], - "signature": [ - "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]) => { 'transaction.duration.histogram': { values: number[]; counts: number[]; }; _doc_count: number; '@timestamp'?: number | undefined; 'agent.name'?: string | undefined; 'agent.version'?: string | undefined; 'container.id'?: string | undefined; 'ecs.version'?: string | undefined; 'event.outcome'?: string | undefined; 'event.ingested'?: number | undefined; 'host.name'?: string | undefined; 'metricset.name'?: string | undefined; 'observer.version'?: string | undefined; 'observer.version_major'?: number | undefined; 'parent.id'?: string | undefined; 'processor.event'?: string | undefined; 'processor.name'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; 'transaction.id'?: string | undefined; 'transaction.duration.us'?: number | undefined; 'transaction.sampled'?: true | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'service.node.name'?: string | undefined; 'span.id'?: string | undefined; 'span.name'?: string | undefined; 'span.type'?: string | undefined; 'span.subtype'?: string | undefined; 'span.duration.us'?: number | undefined; 'span.destination.service.name'?: string | undefined; 'span.destination.service.resource'?: string | undefined; 'span.destination.service.type'?: string | undefined; 'span.destination.service.response_time.sum.us'?: number | undefined; 'span.destination.service.response_time.count'?: number | undefined; 'span.self_time.count'?: number | undefined; 'span.self_time.sum.us'?: number | undefined; }[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.getTransactionMetrics.$1", - "type": "Array", - "tags": [], - "label": "events", - "description": [], - "signature": [ - "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]" - ], - "path": "packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.service", - "type": "Function", - "tags": [], - "label": "service", - "description": [], - "signature": [ - "(name: string, environment: string, agentName: string) => ", - "Service" - ], - "path": "packages/elastic-apm-generator/src/lib/service.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.service.$1", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "signature": [ - "string" - ], - "path": "packages/elastic-apm-generator/src/lib/service.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.service.$2", - "type": "string", - "tags": [], - "label": "environment", - "description": [], - "signature": [ - "string" - ], - "path": "packages/elastic-apm-generator/src/lib/service.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.service.$3", - "type": "string", - "tags": [], - "label": "agentName", - "description": [], - "signature": [ - "string" - ], - "path": "packages/elastic-apm-generator/src/lib/service.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.timerange", - "type": "Function", - "tags": [], - "label": "timerange", - "description": [], - "signature": [ - "(from: number, to: number) => ", - "Timerange" - ], - "path": "packages/elastic-apm-generator/src/lib/timerange.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.timerange.$1", - "type": "number", - "tags": [], - "label": "from", - "description": [], - "signature": [ - "number" - ], - "path": "packages/elastic-apm-generator/src/lib/timerange.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.timerange.$2", - "type": "number", - "tags": [], - "label": "to", - "description": [], - "signature": [ - "number" - ], - "path": "packages/elastic-apm-generator/src/lib/timerange.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.toElasticsearchOutput", - "type": "Function", - "tags": [], - "label": "toElasticsearchOutput", - "description": [], - "signature": [ - "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[], versionOverride: string | undefined) => { _index: string; _source: {}; }[]" - ], - "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.toElasticsearchOutput.$1", - "type": "Array", - "tags": [], - "label": "events", - "description": [], - "signature": [ - "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'container.id': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'host.name': string; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; 'span.self_time.count': number; 'span.self_time.sum.us': number; }>[]" - ], - "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "@elastic/apm-generator", - "id": "def-server.toElasticsearchOutput.$2", - "type": "string", - "tags": [], - "label": "versionOverride", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - } - ], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - } -} \ No newline at end of file diff --git a/api_docs/elastic_apm_synthtrace.json b/api_docs/elastic_apm_synthtrace.json new file mode 100644 index 0000000000000..13d950c53a8df --- /dev/null +++ b/api_docs/elastic_apm_synthtrace.json @@ -0,0 +1,321 @@ +{ + "id": "@elastic/apm-synthtrace", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getBreakdownMetrics", + "type": "Function", + "tags": [], + "label": "getBreakdownMetrics", + "description": [], + "signature": [ + "(events: ", + "Fields", + "[]) => ", + "Fields", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_breakdown_metrics.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getBreakdownMetrics.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Fields", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_breakdown_metrics.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getObserverDefaults", + "type": "Function", + "tags": [], + "label": "getObserverDefaults", + "description": [], + "signature": [ + "() => ", + "Fields" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/defaults/get_observer_defaults.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getSpanDestinationMetrics", + "type": "Function", + "tags": [], + "label": "getSpanDestinationMetrics", + "description": [], + "signature": [ + "(events: ", + "Fields", + "[]) => { \"metricset.name\": string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; '@timestamp'?: number | undefined; 'agent.name'?: string | undefined; 'agent.version'?: string | undefined; 'container.id'?: string | undefined; 'ecs.version'?: string | undefined; 'event.outcome'?: string | undefined; 'event.ingested'?: number | undefined; 'error.id'?: string | undefined; 'error.exception'?: ", + "Exception", + "[] | undefined; 'error.grouping_name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'host.name'?: string | undefined; 'observer.version'?: string | undefined; 'observer.version_major'?: number | undefined; 'parent.id'?: string | undefined; 'processor.event'?: string | undefined; 'processor.name'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; 'transaction.id'?: string | undefined; 'transaction.duration.us'?: number | undefined; 'transaction.duration.histogram'?: { values: number[]; counts: number[]; } | undefined; 'transaction.sampled'?: true | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'service.node.name'?: string | undefined; 'span.id'?: string | undefined; 'span.name'?: string | undefined; 'span.type'?: string | undefined; 'span.subtype'?: string | undefined; 'span.duration.us'?: number | undefined; 'span.destination.service.name'?: string | undefined; 'span.destination.service.resource'?: string | undefined; 'span.destination.service.type'?: string | undefined; 'span.self_time.count'?: number | undefined; 'span.self_time.sum.us'?: number | undefined; 'system.process.memory.size'?: number | undefined; 'system.memory.actual.free'?: number | undefined; 'system.memory.total'?: number | undefined; 'system.cpu.total.norm.pct'?: number | undefined; 'system.process.memory.rss.bytes'?: number | undefined; 'system.process.cpu.total.norm.pct'?: number | undefined; }[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_span_destination_metrics.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getSpanDestinationMetrics.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Fields", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_span_destination_metrics.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getTransactionMetrics", + "type": "Function", + "tags": [], + "label": "getTransactionMetrics", + "description": [], + "signature": [ + "(events: ", + "Fields", + "[]) => { 'transaction.duration.histogram': { values: number[]; counts: number[]; }; _doc_count: number; '@timestamp'?: number | undefined; 'agent.name'?: string | undefined; 'agent.version'?: string | undefined; 'container.id'?: string | undefined; 'ecs.version'?: string | undefined; 'event.outcome'?: string | undefined; 'event.ingested'?: number | undefined; 'error.id'?: string | undefined; 'error.exception'?: ", + "Exception", + "[] | undefined; 'error.grouping_name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'host.name'?: string | undefined; 'metricset.name'?: string | undefined; 'observer.version'?: string | undefined; 'observer.version_major'?: number | undefined; 'parent.id'?: string | undefined; 'processor.event'?: string | undefined; 'processor.name'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; 'transaction.id'?: string | undefined; 'transaction.duration.us'?: number | undefined; 'transaction.sampled'?: true | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'service.node.name'?: string | undefined; 'span.id'?: string | undefined; 'span.name'?: string | undefined; 'span.type'?: string | undefined; 'span.subtype'?: string | undefined; 'span.duration.us'?: number | undefined; 'span.destination.service.name'?: string | undefined; 'span.destination.service.resource'?: string | undefined; 'span.destination.service.type'?: string | undefined; 'span.destination.service.response_time.sum.us'?: number | undefined; 'span.destination.service.response_time.count'?: number | undefined; 'span.self_time.count'?: number | undefined; 'span.self_time.sum.us'?: number | undefined; 'system.process.memory.size'?: number | undefined; 'system.memory.actual.free'?: number | undefined; 'system.memory.total'?: number | undefined; 'system.cpu.total.norm.pct'?: number | undefined; 'system.process.memory.rss.bytes'?: number | undefined; 'system.process.cpu.total.norm.pct'?: number | undefined; }[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_transaction_metrics.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.getTransactionMetrics.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Fields", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/utils/get_transaction_metrics.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.service", + "type": "Function", + "tags": [], + "label": "service", + "description": [], + "signature": [ + "(name: string, environment: string, agentName: string) => ", + "Service" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.service.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/service.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.service.$2", + "type": "string", + "tags": [], + "label": "environment", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/service.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.service.$3", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.timerange", + "type": "Function", + "tags": [], + "label": "timerange", + "description": [], + "signature": [ + "(from: number, to: number) => ", + "Timerange" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/timerange.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.timerange.$1", + "type": "number", + "tags": [], + "label": "from", + "description": [], + "signature": [ + "number" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/timerange.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.timerange.$2", + "type": "number", + "tags": [], + "label": "to", + "description": [], + "signature": [ + "number" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/timerange.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.toElasticsearchOutput", + "type": "Function", + "tags": [], + "label": "toElasticsearchOutput", + "description": [], + "signature": [ + "({\n events,\n writeTargets,\n}: { events: ", + "Fields", + "[]; writeTargets: ", + "ElasticsearchOutputWriteTargets", + "; }) => ", + "ElasticsearchOutput", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.toElasticsearchOutput.$1", + "type": "Object", + "tags": [], + "label": "{\n events,\n writeTargets,\n}", + "description": [], + "path": "packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.toElasticsearchOutput.$1.events", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Fields", + "[]" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false + }, + { + "parentPluginId": "@elastic/apm-synthtrace", + "id": "def-server.toElasticsearchOutput.$1.writeTargets", + "type": "Object", + "tags": [], + "label": "writeTargets", + "description": [], + "signature": [ + "ElasticsearchOutputWriteTargets" + ], + "path": "packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/elastic_apm_generator.mdx b/api_docs/elastic_apm_synthtrace.mdx similarity index 63% rename from api_docs/elastic_apm_generator.mdx rename to api_docs/elastic_apm_synthtrace.mdx index 4c95050b09c28..b41afe6c7357c 100644 --- a/api_docs/elastic_apm_generator.mdx +++ b/api_docs/elastic_apm_synthtrace.mdx @@ -1,14 +1,14 @@ --- -id: kibElasticApmGeneratorPluginApi -slug: /kibana-dev-docs/api/elastic-apm-generator -title: "@elastic/apm-generator" +id: kibElasticApmSynthtracePluginApi +slug: /kibana-dev-docs/api/elastic-apm-synthtrace +title: "@elastic/apm-synthtrace" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @elastic/apm-generator plugin +summary: API docs for the @elastic/apm-synthtrace plugin date: 2020-11-16 -tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-generator'] +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-synthtrace'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- -import elasticApmGeneratorObj from './elastic_apm_generator.json'; +import elasticApmSynthtraceObj from './elastic_apm_synthtrace.json'; Elastic APM trace data generator @@ -18,10 +18,10 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 17 | 0 | 17 | 2 | +| 18 | 0 | 18 | 6 | ## Server ### Functions - + diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 19e3bc08a5361..d23a52b07a1e3 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -18,7 +18,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 24459 | 276 | 19826 | 1583 | +| 24503 | 264 | 19863 | 1594 | ## Plugin Directory @@ -26,7 +26,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 125 | 0 | 125 | 8 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 23 | 0 | 22 | 1 | -| | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 257 | 0 | 249 | 17 | +| | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 258 | 0 | 250 | 17 | | | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 39 | 0 | 39 | 37 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 76 | 1 | 67 | 2 | @@ -34,18 +34,18 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Security Solution Threat Hunting](https://github.com/orgs/elastic/teams/security-threat-hunting) | The Case management system in Kibana | 476 | 0 | 432 | 14 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 285 | 4 | 253 | 3 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 22 | 0 | -| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 9 | 0 | 9 | 1 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2298 | 27 | 1018 | 29 | +| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 13 | 0 | 13 | 1 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2304 | 27 | 1023 | 29 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 91 | 1 | 75 | 1 | -| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 145 | 1 | 132 | 10 | +| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 100 | 1 | 84 | 1 | +| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 147 | 1 | 134 | 10 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 51 | 0 | 50 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3193 | 43 | 2807 | 48 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3238 | 40 | 2848 | 48 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Enhanced data plugin. (See src/plugins/data.) Enhances the main data plugin with a search session management UI. Includes a reusable search session indicator component to use in other applications. Exposes routes for managing search sessions. Includes a service that monitors, updates, and cleans up search session saved objects. | 16 | 0 | 16 | 2 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 683 | 6 | 541 | 5 | -| | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 80 | 5 | 80 | 0 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 668 | 5 | 526 | 5 | +| | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 84 | 5 | 84 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 10 | 0 | 8 | 2 | -| | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 103 | 0 | 77 | 7 | +| | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 84 | 0 | 58 | 7 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds embeddables service to Kibana | 469 | 5 | 393 | 3 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Extends embeddable plugin with more functionality | 14 | 0 | 14 | 0 | @@ -61,17 +61,17 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'revealImage' function and renderer to expressions | 12 | 0 | 12 | 3 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 143 | 0 | 143 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 5 | 0 | 5 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds expression runtime to Kibana | 2086 | 27 | 1640 | 4 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds expression runtime to Kibana | 2092 | 27 | 1646 | 3 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 216 | 0 | 98 | 2 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 288 | 7 | 250 | 3 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 284 | 7 | 246 | 3 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 129 | 4 | 129 | 1 | -| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1210 | 15 | 1110 | 10 | +| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1225 | 15 | 1122 | 10 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | globalSearchProviders | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | graph | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 0 | 0 | 0 | 0 | | grokdebugger | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 99 | 3 | 77 | 5 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 96 | 2 | 74 | 5 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 4 | 0 | 4 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 169 | 9 | 164 | 3 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create index patterns via a modal flyout from any kibana app | 13 | 1 | 8 | 0 | @@ -82,16 +82,16 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | inputControlVis | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 123 | 6 | 96 | 4 | | | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 26 | 0 | 16 | 0 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 48 | 1 | 45 | 0 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 12 | 0 | 9 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 297 | 8 | 260 | 5 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 282 | 2 | 245 | 5 | | kibanaUsageCollection | [Kibana Telemtry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 0 | 0 | 0 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 606 | 3 | 413 | 8 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 607 | 3 | 414 | 8 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 253 | 0 | 235 | 24 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 8 | 0 | 8 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 3 | 0 | 3 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 8 | -| | [Security detections response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 150 | 0 | 143 | 38 | +| | [Security detections response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 155 | 0 | 148 | 39 | | logstash | [Logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 40 | 0 | 40 | 5 | | | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 202 | 0 | 201 | 29 | @@ -101,14 +101,14 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Stack Monitoring](https://github.com/orgs/elastic/teams/stack-monitoring-ui) | - | 10 | 0 | 10 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 31 | 0 | 31 | 2 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | -| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 258 | 1 | 257 | 12 | -| | [Security asset management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 11 | 0 | 11 | 0 | +| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 268 | 1 | 267 | 15 | +| | [Security asset management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 10 | 0 | 10 | 0 | | painlessLab | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 178 | 3 | 151 | 6 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 4 | 0 | 4 | 0 | -| | [Kibana Reporting Services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 135 | 0 | 134 | 12 | -| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 20 | 0 | 20 | 0 | -| | [RAC](https://github.com/orgs/elastic/teams/rac) | - | 136 | 0 | 113 | 7 | +| | [Kibana Reporting Services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 137 | 0 | 136 | 12 | +| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 21 | 0 | 21 | 0 | +| | [RAC](https://github.com/orgs/elastic/teams/rac) | - | 151 | 0 | 128 | 7 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 24 | 0 | 19 | 2 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 221 | 3 | 207 | 4 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 103 | 0 | 90 | 0 | @@ -116,18 +116,18 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 90 | 3 | 51 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 22 | 0 | 17 | 1 | | searchprofiler | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 113 | 0 | 51 | 7 | -| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 1361 | 8 | 1307 | 30 | +| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 116 | 0 | 54 | 8 | +| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 1372 | 8 | 1318 | 33 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 143 | 1 | 90 | 10 | -| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 23 | 1 | 22 | 1 | +| | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 23 | 1 | 23 | 1 | | | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 208 | 0 | 21 | 1 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 4 | 0 | 4 | 0 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 70 | 0 | 32 | 7 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 41 | 0 | 0 | 0 | -| | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 36 | 0 | 36 | 4 | +| | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 32 | 0 | 32 | 5 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 1 | 0 | 1 | 0 | -| | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 14 | 0 | 13 | 0 | -| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 968 | 6 | 847 | 25 | +| | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 11 | 0 | 10 | 0 | +| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 969 | 6 | 848 | 25 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [Kibana Localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 238 | 1 | 229 | 18 | @@ -142,14 +142,14 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | visTypeMarkdown | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds a markdown visualization type | 0 | 0 | 0 | 0 | | visTypeMetric | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the Metric aggregation-based visualization. | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the pie chart implementation using the elastic-charts library. The goal is to eventually deprecate the old implementation and keep only this. Until then, the library used is defined by the Legacy charts library advanced setting. | 12 | 0 | 12 | 2 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the datatable aggregation-based visualization. | 11 | 0 | 11 | 0 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the datatable aggregation-based visualization. | 12 | 0 | 12 | 0 | | visTypeTagcloud | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the tagcloud visualization. It is based on elastic-charts wordcloud. | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the timelion visualization. Also contains the backend for both timelion app and timelion visualization. | 2 | 0 | 2 | 2 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the TSVB visualization. TSVB has its one editor, works with index patterns and index strings and contains 6 types of charts: timeseries, topN, table. markdown, metric and gauge. | 10 | 1 | 10 | 3 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the vislib visualizations. These are the classical area/line/bar, pie, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 26 | 0 | 25 | 1 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 57 | 0 | 51 | 5 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 304 | 13 | 286 | 16 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 303 | 13 | 285 | 15 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the visualize application which includes the listing page and the app frame, which will load the visualization's editor. | 24 | 0 | 23 | 1 | | watcher | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | @@ -157,7 +157,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| -| | [Owner missing] | Elastic APM trace data generator | 17 | 0 | 17 | 2 | +| | [Owner missing] | Elastic APM trace data generator | 18 | 0 | 18 | 6 | | | [Owner missing] | elasticsearch datemath parser, used in kibana | 44 | 0 | 43 | 0 | | | [Owner missing] | - | 11 | 5 | 11 | 0 | | | [Owner missing] | Alerts components and hooks | 9 | 1 | 9 | 0 | @@ -187,13 +187,13 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | security solution elastic search utilities to use across plugins such lists, security_solution, cases, etc... | 54 | 0 | 51 | 0 | | | [Owner missing] | Security Solution utilities for React hooks | 8 | 0 | 1 | 1 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 147 | 1 | 128 | 0 | -| | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 418 | 1 | 409 | 0 | +| | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 419 | 1 | 410 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 45 | 0 | 23 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 28 | 0 | 22 | 0 | | | [Owner missing] | security solution list REST API | 42 | 0 | 41 | 5 | | | [Owner missing] | security solution list constants to use across plugins such lists, security_solution, cases, etc... | 23 | 0 | 9 | 0 | | | [Owner missing] | Security solution list ReactJS hooks | 56 | 0 | 44 | 0 | -| | [Owner missing] | security solution list utilities | 222 | 0 | 177 | 0 | +| | [Owner missing] | security solution list utilities | 223 | 0 | 178 | 0 | | | [Owner missing] | security solution t-grid packages will allow sharing components between timelines and security_solution plugin until we transfer all functionality to timelines plugin | 120 | 0 | 116 | 0 | | | [Owner missing] | security solution utilities to use across plugins such lists, security_solution, cases, etc... | 6 | 0 | 4 | 0 | | | [Owner missing] | - | 53 | 0 | 50 | 1 | diff --git a/config/kibana.yml b/config/kibana.yml index 8338a148ef176..eeb7c84df4318 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -31,10 +31,6 @@ # The URLs of the Elasticsearch instances to use for all your queries. #elasticsearch.hosts: ["http://localhost:9200"] -# Kibana uses an index in Elasticsearch to store saved searches, visualizations and -# dashboards. Kibana creates a new index if the index doesn't already exist. -#kibana.index: ".kibana" - # If your Elasticsearch is protected with basic authentication, these settings provide # the username and password that the Kibana server uses to perform maintenance on the Kibana # index at startup. Your Kibana users still need to authenticate with Elasticsearch, which diff --git a/dev_docs/tutorials/data/search.mdx b/dev_docs/tutorials/data/search.mdx index 1585adbdd37be..425736ddb03bb 100644 --- a/dev_docs/tutorials/data/search.mdx +++ b/dev_docs/tutorials/data/search.mdx @@ -13,7 +13,7 @@ tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'search', 'sessions', 'search Searching data stored in Elasticsearch can be done in various ways, for example using the Elasticsearch REST API or using an `Elasticsearch Client` for low level access. -However, the recommended and easist way to search Elasticsearch is by using the low level search service. The service is exposed from the `data` plugin, and by using it, you not only gain access to the data you stored, but also to capabilities, such as Custom Search Strategies, Asynchronous Search, Partial Results, Search Sessions, and more. +However, the recommended and easiest way to search Elasticsearch is by using the low level search service. The service is exposed from the `data` plugin, and by using it, you not only gain access to the data you stored, but also to capabilities, such as Custom Search Strategies, Asynchronous Search, Partial Results, Search Sessions, and more. Here is a basic example for using the `data.search` service from a custom plugin: @@ -418,11 +418,11 @@ export class MyPlugin implements Plugin { // return the name you want to give the saved Search Session return `MyApp_${Math.random()}`; }, - getUrlGeneratorData: async () => { + getLocatorData: async () => { return { - urlGeneratorId: MY_URL_GENERATOR, - initialState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: false }), - restoreState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: true }), + id: MY_LOCATOR, + initialState: getLocatorParams({ ...deps, shouldRestoreSearchSession: false }), + restoreState: getLocatorParams({ ...deps, shouldRestoreSearchSession: true }), }; }, }); diff --git a/docs/api/saved-objects/bulk_create.asciidoc b/docs/api/saved-objects/bulk_create.asciidoc index a935907ef3f11..471e297316578 100644 --- a/docs/api/saved-objects/bulk_create.asciidoc +++ b/docs/api/saved-objects/bulk_create.asciidoc @@ -66,7 +66,8 @@ Saved objects that are unable to persist are replaced with an error object. ==== Response code `200`:: - Indicates a successful call. + Indicates a successful call. Note, this HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual + objects will be returned in the response body. See the example below for details. [[saved-objects-api-bulk-create-example]] ==== Example @@ -122,3 +123,19 @@ The API returns the following: -------------------------------------------------- There is already a saved object with the `my-dashboard` ID, so only the index pattern is created. + +[[saved-objects-api-bulk-create-conflict-errors]] +==== Conflict errors + +Starting in {kib} 8.0, saved objects can exist in multiple spaces. As a result, you may encounter different types of conflict errors when +attempting to create an object: + +* *Regular conflict*: This is a 409 error without any metadata. It means an object of that type/ID already exists. This can be + overridden by using the `overwrite: true` option. +* *Unresolvable conflict*: This is a 409 error with `isNotOverwritable: true` in its metadata. It means an object of that type/ID already + exists in a different space, and it cannot be overridden with the given parameters. To successfully overwrite this object, you must do so + in at least one space where it exists. You can specify that using the `space_id` path parameter _or_ the `initialNamespaces` parameter. +* *Alias conflict*: This is a 409 error with a `spacesWithConflictingAliases` string array in its metadata. It means a conflicting + <> for this type/ID exists in the space(s) where you attempted to create this object. A conflicting + legacy URL alias is one that points to a different type/ID. To successfully create this object, you need to first use the + <> API to disable the problematic legacy URL alias(es). diff --git a/docs/api/saved-objects/bulk_get.asciidoc b/docs/api/saved-objects/bulk_get.asciidoc index 1bcdf7ba33cf4..65cd93fe212f8 100644 --- a/docs/api/saved-objects/bulk_get.asciidoc +++ b/docs/api/saved-objects/bulk_get.asciidoc @@ -53,7 +53,8 @@ Saved objects that are unable to persist are replaced with an error object. ==== Response code `200`:: - Indicates a successful call. + Indicates a successful call. Note, this HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual + objects will be returned in the response body. See the example below for details. [[saved-objects-api-bulk-get-body-example]] ==== Example diff --git a/docs/api/saved-objects/bulk_resolve.asciidoc b/docs/api/saved-objects/bulk_resolve.asciidoc index 98077ff11aa8c..e8b947638abeb 100644 --- a/docs/api/saved-objects/bulk_resolve.asciidoc +++ b/docs/api/saved-objects/bulk_resolve.asciidoc @@ -46,7 +46,8 @@ that "exactMatch" is the default outcome, and the outcome only changes if an ali ==== Response code `200`:: - Indicates a successful call. + Indicates a successful call. Note, this HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual + objects will be returned in the response body. See the example below for details. [[saved-objects-api-bulk-resolve-body-example]] ==== Example diff --git a/docs/api/saved-objects/create.asciidoc b/docs/api/saved-objects/create.asciidoc index 437bdb497da26..d250b0602adb7 100644 --- a/docs/api/saved-objects/create.asciidoc +++ b/docs/api/saved-objects/create.asciidoc @@ -64,6 +64,9 @@ used to specify a single space, and the "All spaces" identifier (`'*'`) is not a `200`:: Indicates a successful call. +`409`:: + Indicates a <>. + [[saved-objects-api-create-example]] ==== Example @@ -93,3 +96,11 @@ The API returns the following: -------------------------------------------------- <1> When `my-pattern` is unspecified in the path, a unique ID is automatically generated. + +[[saved-objects-api-create-conflict-errors]] +==== Conflict errors + +Starting in {kib} 8.0, saved objects can exist in multiple spaces. As a result, you may encounter different types of conflict errors when +attempting to create an object. If you encounter a 409 error that cannot be overridden by using the `overwrite: true` option, you are likely +hitting a different type of conflict error. The Create API response is limited and does not include additional metadata. You can get more +details about this error by using the <> instead. diff --git a/docs/api/saved-objects/update.asciidoc b/docs/api/saved-objects/update.asciidoc index 2bd95df1adf30..fccc6112948a1 100644 --- a/docs/api/saved-objects/update.asciidoc +++ b/docs/api/saved-objects/update.asciidoc @@ -45,6 +45,12 @@ WARNING: When you update, attributes are not validated, which allows you to pass `200`:: Indicates a successful call. +`404`:: + Indicates the object was not found. + +`409`:: + Indicates a <>. + [[saved-objects-api-update-example]] ==== Example @@ -74,3 +80,10 @@ The API returns the following: } } -------------------------------------------------- + +[[saved-objects-api-update-conflict-errors]] +==== Conflict errors + +Starting in {kib} 8.0, saved objects can exist in multiple spaces. As a result, you may encounter a 409 *alias conflict* error when using +the `upsert` option. The Update API response is limited and does not include additional metadata. You can get more details about this error +by using the <> instead. diff --git a/docs/developer/advanced/running-elasticsearch.asciidoc b/docs/developer/advanced/running-elasticsearch.asciidoc index 324d2af2ed3af..36f9ee420d41d 100644 --- a/docs/developer/advanced/running-elasticsearch.asciidoc +++ b/docs/developer/advanced/running-elasticsearch.asciidoc @@ -76,7 +76,6 @@ If many other users will be interacting with your remote cluster, you'll want to [source,bash] ---- kibana.index: '.{YourGitHubHandle}-kibana' -xpack.task_manager.index: '.{YourGitHubHandle}-task-manager-kibana' ---- ==== Running remote clusters diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index 7754463339771..9d257c8d848d4 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -91,6 +91,7 @@ yarn kbn watch - @kbn/securitysolution-list-constants - @kbn/securitysolution-list-hooks - @kbn/securitysolution-list-utils +- @kbn/securitysolution-rules - @kbn/securitysolution-utils - @kbn/server-http-tools - @kbn/server-route-repository diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index 01e7beae61ce8..ed6763db69ffe 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -229,6 +229,7 @@ readonly links: { readonly snapshotRestore: Record; readonly ingest: Record; readonly fleet: Readonly<{ + datastreamsILM: string; guide: string; fleetServer: string; fleetServerAddFleetServer: string; diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index fdf469f443f28..96c2c0df9d782 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly settings: string;
readonly elasticStackGetStarted: string;
readonly apm: {
readonly kibanaSettings: string;
readonly supportedServiceMaps: string;
readonly customLinks: string;
readonly droppedTransactionSpans: string;
readonly upgrading: string;
readonly metaData: string;
};
readonly canvas: {
readonly guide: string;
};
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly discover: Record<string, string>;
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly elasticsearchModule: string;
readonly startup: string;
readonly exportedFields: string;
readonly suricataModule: string;
readonly zeekModule: string;
};
readonly auditbeat: {
readonly base: string;
readonly auditdModule: string;
readonly systemModule: string;
};
readonly metricbeat: {
readonly base: string;
readonly configure: string;
readonly httpEndpoint: string;
readonly install: string;
readonly start: string;
};
readonly enterpriseSearch: {
readonly base: string;
readonly appSearchBase: string;
readonly workplaceSearchBase: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly libbeat: {
readonly getStarted: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly composite: string;
readonly composite_missing_bucket: string;
readonly date_histogram: string;
readonly date_range: string;
readonly date_format_pattern: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly runtimeFields: {
readonly overview: string;
readonly mapping: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessLangSpec: string;
readonly painlessSyntax: string;
readonly painlessWalkthrough: string;
readonly luceneExpressions: string;
};
readonly search: {
readonly sessions: string;
readonly sessionLimits: string;
};
readonly indexPatterns: {
readonly introduction: string;
readonly fieldFormattersNumber: string;
readonly fieldFormattersString: string;
readonly runtimeFields: string;
};
readonly addData: string;
readonly kibana: string;
readonly upgradeAssistant: string;
readonly rollupJobs: string;
readonly elasticsearch: Record<string, string>;
readonly siem: {
readonly privileges: string;
readonly guide: string;
readonly gettingStarted: string;
readonly ml: string;
readonly ruleChangeLog: string;
readonly detectionsReq: string;
readonly networkMap: string;
readonly troubleshootGaps: string;
};
readonly securitySolution: {
readonly trustedApps: string;
};
readonly query: {
readonly eql: string;
readonly kueryQuerySyntax: string;
readonly luceneQuerySyntax: string;
readonly percolate: string;
readonly queryDsl: string;
readonly autocompleteChanges: string;
};
readonly date: {
readonly dateMath: string;
readonly dateMathIndexNames: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
readonly apis: Readonly<{
bulkIndexAlias: string;
byteSizeUnits: string;
createAutoFollowPattern: string;
createFollower: string;
createIndex: string;
createSnapshotLifecyclePolicy: string;
createRoleMapping: string;
createRoleMappingTemplates: string;
createRollupJobsRequest: string;
createApiKey: string;
createPipeline: string;
createTransformRequest: string;
cronExpressions: string;
executeWatchActionModes: string;
indexExists: string;
openIndex: string;
putComponentTemplate: string;
painlessExecute: string;
painlessExecuteAPIContexts: string;
putComponentTemplateMetadata: string;
putSnapshotLifecyclePolicy: string;
putIndexTemplateV1: string;
putWatch: string;
simulatePipeline: string;
timeUnits: string;
updateTransform: string;
}>;
readonly observability: Readonly<{
guide: string;
infrastructureThreshold: string;
logsThreshold: string;
metricsThreshold: string;
monitorStatus: string;
monitorUptime: string;
tlsCertificate: string;
uptimeDurationAnomaly: string;
}>;
readonly alerting: Record<string, string>;
readonly maps: Record<string, string>;
readonly monitoring: Record<string, string>;
readonly security: Readonly<{
apiKeyServiceSettings: string;
clusterPrivileges: string;
elasticsearchSettings: string;
elasticsearchEnableSecurity: string;
indicesPrivileges: string;
kibanaTLS: string;
kibanaPrivileges: string;
mappingRoles: string;
mappingRolesFieldRules: string;
runAsPrivilege: string;
}>;
readonly spaces: Readonly<{
kibanaLegacyUrlAliases: string;
kibanaDisableLegacyUrlAliasesApi: string;
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
guide: string;
fleetServer: string;
fleetServerAddFleetServer: string;
settings: string;
settingsFleetServerHostSettings: string;
troubleshooting: string;
elasticAgent: string;
datastreams: string;
datastreamsNamingScheme: string;
installElasticAgent: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
learnMoreBlog: string;
apiKeysLearnMore: string;
}>;
readonly ecs: {
readonly guide: string;
};
readonly clients: {
readonly guide: string;
readonly goOverview: string;
readonly javaIndex: string;
readonly jsIntro: string;
readonly netGuide: string;
readonly perlGuide: string;
readonly phpGuide: string;
readonly pythonGuide: string;
readonly rubyOverview: string;
readonly rustGuide: string;
};
} | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly settings: string;
readonly elasticStackGetStarted: string;
readonly apm: {
readonly kibanaSettings: string;
readonly supportedServiceMaps: string;
readonly customLinks: string;
readonly droppedTransactionSpans: string;
readonly upgrading: string;
readonly metaData: string;
};
readonly canvas: {
readonly guide: string;
};
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly discover: Record<string, string>;
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly elasticsearchModule: string;
readonly startup: string;
readonly exportedFields: string;
readonly suricataModule: string;
readonly zeekModule: string;
};
readonly auditbeat: {
readonly base: string;
readonly auditdModule: string;
readonly systemModule: string;
};
readonly metricbeat: {
readonly base: string;
readonly configure: string;
readonly httpEndpoint: string;
readonly install: string;
readonly start: string;
};
readonly enterpriseSearch: {
readonly base: string;
readonly appSearchBase: string;
readonly workplaceSearchBase: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly libbeat: {
readonly getStarted: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly composite: string;
readonly composite_missing_bucket: string;
readonly date_histogram: string;
readonly date_range: string;
readonly date_format_pattern: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly runtimeFields: {
readonly overview: string;
readonly mapping: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessLangSpec: string;
readonly painlessSyntax: string;
readonly painlessWalkthrough: string;
readonly luceneExpressions: string;
};
readonly search: {
readonly sessions: string;
readonly sessionLimits: string;
};
readonly indexPatterns: {
readonly introduction: string;
readonly fieldFormattersNumber: string;
readonly fieldFormattersString: string;
readonly runtimeFields: string;
};
readonly addData: string;
readonly kibana: string;
readonly upgradeAssistant: string;
readonly rollupJobs: string;
readonly elasticsearch: Record<string, string>;
readonly siem: {
readonly privileges: string;
readonly guide: string;
readonly gettingStarted: string;
readonly ml: string;
readonly ruleChangeLog: string;
readonly detectionsReq: string;
readonly networkMap: string;
readonly troubleshootGaps: string;
};
readonly securitySolution: {
readonly trustedApps: string;
};
readonly query: {
readonly eql: string;
readonly kueryQuerySyntax: string;
readonly luceneQuerySyntax: string;
readonly percolate: string;
readonly queryDsl: string;
readonly autocompleteChanges: string;
};
readonly date: {
readonly dateMath: string;
readonly dateMathIndexNames: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
readonly apis: Readonly<{
bulkIndexAlias: string;
byteSizeUnits: string;
createAutoFollowPattern: string;
createFollower: string;
createIndex: string;
createSnapshotLifecyclePolicy: string;
createRoleMapping: string;
createRoleMappingTemplates: string;
createRollupJobsRequest: string;
createApiKey: string;
createPipeline: string;
createTransformRequest: string;
cronExpressions: string;
executeWatchActionModes: string;
indexExists: string;
openIndex: string;
putComponentTemplate: string;
painlessExecute: string;
painlessExecuteAPIContexts: string;
putComponentTemplateMetadata: string;
putSnapshotLifecyclePolicy: string;
putIndexTemplateV1: string;
putWatch: string;
simulatePipeline: string;
timeUnits: string;
updateTransform: string;
}>;
readonly observability: Readonly<{
guide: string;
infrastructureThreshold: string;
logsThreshold: string;
metricsThreshold: string;
monitorStatus: string;
monitorUptime: string;
tlsCertificate: string;
uptimeDurationAnomaly: string;
}>;
readonly alerting: Record<string, string>;
readonly maps: Record<string, string>;
readonly monitoring: Record<string, string>;
readonly security: Readonly<{
apiKeyServiceSettings: string;
clusterPrivileges: string;
elasticsearchSettings: string;
elasticsearchEnableSecurity: string;
elasticsearchEnableApiKeys: string;
indicesPrivileges: string;
kibanaTLS: string;
kibanaPrivileges: string;
mappingRoles: string;
mappingRolesFieldRules: string;
runAsPrivilege: string;
}>;
readonly spaces: Readonly<{
kibanaLegacyUrlAliases: string;
kibanaDisableLegacyUrlAliasesApi: string;
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
datastreamsILM: string;
guide: string;
fleetServer: string;
fleetServerAddFleetServer: string;
settings: string;
settingsFleetServerHostSettings: string;
troubleshooting: string;
elasticAgent: string;
datastreams: string;
datastreamsNamingScheme: string;
installElasticAgent: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
learnMoreBlog: string;
apiKeysLearnMore: string;
}>;
readonly ecs: {
readonly guide: string;
};
readonly clients: {
readonly guide: string;
readonly goOverview: string;
readonly javaIndex: string;
readonly jsIntro: string;
readonly netGuide: string;
readonly perlGuide: string;
readonly phpGuide: string;
readonly pythonGuide: string;
readonly rubyOverview: string;
readonly rustGuide: string;
};
} | | diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md index 279262aa6a5ec..f6190fb3bc055 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md @@ -9,9 +9,9 @@ Client used to query the elasticsearch cluster. Signature: ```typescript -export declare type ElasticsearchClient = Omit & { +export declare type ElasticsearchClient = Omit & { transport: { - request(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise; + request(params: TransportRequestParams, options?: TransportRequestOptions): Promise>; }; }; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.error.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.error.md new file mode 100644 index 0000000000000..7191caea54929 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.error.md @@ -0,0 +1,14 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md) > [error](./kibana-plugin-core-server.elasticsearcherrordetails.error.md) + +## ElasticsearchErrorDetails.error property + +Signature: + +```typescript +error?: { + type: string; + reason?: string; + }; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.md new file mode 100644 index 0000000000000..7dbf9e89f9b7c --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearcherrordetails.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md) + +## ElasticsearchErrorDetails interface + + +Signature: + +```typescript +export interface ElasticsearchErrorDetails +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [error](./kibana-plugin-core-server.elasticsearcherrordetails.error.md) | {
type: string;
reason?: string;
} | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 3970cf005abe4..f22a0fb8283d7 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -71,6 +71,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [DeprecationsServiceSetup](./kibana-plugin-core-server.deprecationsservicesetup.md) | The deprecations service provides a way for the Kibana platform to communicate deprecated features and configs with its users. These deprecations are only communicated if the deployment is using these features. Allowing for a user tailored experience for upgrading the stack version.The Deprecation service is consumed by the upgrade assistant to assist with the upgrade experience.If a deprecated feature can be resolved without manual user intervention. Using correctiveActions.api allows the Upgrade Assistant to use this api to correct the deprecation upon a user trigger. | | [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) | Small container object used to expose information about discovered plugins that may or may not have been started. | | [ElasticsearchConfigPreboot](./kibana-plugin-core-server.elasticsearchconfigpreboot.md) | A limited set of Elasticsearch configuration entries exposed to the preboot plugins at setup. | +| [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md) | | | [ElasticsearchServicePreboot](./kibana-plugin-core-server.elasticsearchservicepreboot.md) | | | [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) | | | [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md deleted file mode 100644 index e17877a537d00..0000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) > [createGenericNotFoundEsUnavailableError](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md) - -## SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError() method - -Signature: - -```typescript -static createGenericNotFoundEsUnavailableError(type?: string | null, id?: string | null): DecoratedError; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| type | string | null | | -| id | string | null | | - -Returns: - -`DecoratedError` - diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md index 67056c8a3cb50..2dc78f2df3a83 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectserrorhelpers.md @@ -18,7 +18,6 @@ export declare class SavedObjectsErrorHelpers | [createBadRequestError(reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.createbadrequesterror.md) | static | | | [createConflictError(type, id, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md) | static | | | [createGenericNotFoundError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfounderror.md) | static | | -| [createGenericNotFoundEsUnavailableError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md) | static | | | [createIndexAliasNotFoundError(alias)](./kibana-plugin-core-server.savedobjectserrorhelpers.createindexaliasnotfounderror.md) | static | | | [createInvalidVersionError(versionInput)](./kibana-plugin-core-server.savedobjectserrorhelpers.createinvalidversionerror.md) | static | | | [createTooManyRequestsError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md) | static | | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.getkibanaindex.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.getkibanaindex.md new file mode 100644 index 0000000000000..9319ae987ad44 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.getkibanaindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) > [getKibanaIndex](./kibana-plugin-core-server.savedobjectsservicesetup.getkibanaindex.md) + +## SavedObjectsServiceSetup.getKibanaIndex property + +Returns the default index used for saved objects. + +Signature: + +```typescript +getKibanaIndex: () => string; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md index a1bc99ce8d13d..336d9f63f0ced 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md @@ -52,6 +52,7 @@ export class Plugin() { | Property | Type | Description | | --- | --- | --- | | [addClientWrapper](./kibana-plugin-core-server.savedobjectsservicesetup.addclientwrapper.md) | (priority: number, id: string, factory: SavedObjectsClientWrapperFactory) => void | Add a [client wrapper factory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) with the given priority. | +| [getKibanaIndex](./kibana-plugin-core-server.savedobjectsservicesetup.getkibanaindex.md) | () => string | Returns the default index used for saved objects. | | [registerType](./kibana-plugin-core-server.savedobjectsservicesetup.registertype.md) | <Attributes = any>(type: SavedObjectsType<Attributes>) => void | Register a [savedObjects type](./kibana-plugin-core-server.savedobjectstype.md) definition.See the [mappings format](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) and [migration format](./kibana-plugin-core-server.savedobjectmigrationmap.md) for more details about these. | | [setClientFactoryProvider](./kibana-plugin-core-server.savedobjectsservicesetup.setclientfactoryprovider.md) | (clientFactoryProvider: SavedObjectsClientFactoryProvider) => void | Set the default [factory provider](./kibana-plugin-core-server.savedobjectsclientfactoryprovider.md) for creating Saved Objects clients. Only one provider can be set, subsequent calls to this method will fail. | diff --git a/docs/development/core/server/kibana-plugin-core-server.sharedglobalconfig.md b/docs/development/core/server/kibana-plugin-core-server.sharedglobalconfig.md index ec2e1b227a2d7..477cd5a651a56 100644 --- a/docs/development/core/server/kibana-plugin-core-server.sharedglobalconfig.md +++ b/docs/development/core/server/kibana-plugin-core-server.sharedglobalconfig.md @@ -9,7 +9,6 @@ ```typescript export declare type SharedGlobalConfig = RecursiveReadonly<{ - kibana: Pick; elasticsearch: Pick; path: Pick; savedObjects: Pick; diff --git a/docs/maps/vector-layer.asciidoc b/docs/maps/vector-layer.asciidoc index 7191197c27dbe..f70e4d59796cc 100644 --- a/docs/maps/vector-layer.asciidoc +++ b/docs/maps/vector-layer.asciidoc @@ -27,9 +27,9 @@ Results exceeding `index.max_result_window` are not displayed. * *Show clusters when results exceed 10,000* When results exceed `index.max_result_window`, the layer uses {ref}/search-aggregations-bucket-geotilegrid-aggregation.html[GeoTile grid aggregation] to group your documents into clusters and displays metrics for each cluster. When results are less then `index.max_result_window`, the layer displays features from individual documents. -* *Use vector tiles.* Vector tiles partition your map into 6 to 8 tiles. +* *Use vector tiles.* Vector tiles partition your map into tiles. Each tile request is limited to the `index.max_result_window` index setting. -Tiles exceeding `index.max_result_window` have a visual indicator when there are too many features to display. +When a tile exceeds `index.max_result_window`, results exceeding `index.max_result_window` are not contained in the tile and a dashed rectangle outlining the bounding box containing all geo values within the tile is displayed. *EMS Boundaries*:: Administrative boundaries from https://www.elastic.co/elastic-maps-service[Elastic Maps Service]. diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index c291b65c3c35b..7737745c7cfa8 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -12,20 +12,6 @@ You do not need to configure any additional settings to use the [[general-security-settings]] ==== General security settings -[cols="2*<"] -|=== -| `xpack.security.enabled` - | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] - By default, {kib} automatically detects whether to enable the - {security-features} based on the license and whether {es} {security-features} - are enabled. + - + - Do not set this to `false`; it disables the login form, user and role management - screens, and authorization using <>. To disable - {security-features} entirely, see - {ref}/security-settings.html[{es} security settings]. -|=== - [float] [[authentication-security-settings]] ==== Authentication security settings diff --git a/docs/settings/task-manager-settings.asciidoc b/docs/settings/task-manager-settings.asciidoc index ef45c262f897b..c61ef83953347 100644 --- a/docs/settings/task-manager-settings.asciidoc +++ b/docs/settings/task-manager-settings.asciidoc @@ -22,9 +22,6 @@ Task Manager runs background tasks by polling for work on an interval. You can | `xpack.task_manager.request_capacity` | How many requests can Task Manager buffer before it rejects new requests. Defaults to 1000. -| `xpack.task_manager.index` - | The name of the index used to store task information. Defaults to `.kibana_task_manager`. - | `xpack.task_manager.max_workers` | The maximum number of tasks that this Kibana instance will run simultaneously. Defaults to 10. Starting in 8.0, it will not be possible to set the value greater than 100. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 7235c2a673376..9ccfeb6894713 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -285,18 +285,6 @@ is an alternative to `elasticsearch.username` and `elasticsearch.password`. | `interpreter.enableInVisualize` | Enables use of interpreter in Visualize. *Default: `true`* -|[[kibana-index]] `kibana.index:` - | deprecated:[7.11.0,This setting will be removed in 8.0.] Multitenancy by - changing `kibana.index` will not be supported starting in 8.0. See - https://ela.st/kbn-remove-legacy-multitenancy[8.0 Breaking Changes] for more - details. - + - {kib} uses an index in {es} to store saved searches, visualizations, and - dashboards. {kib} creates a new index if the index doesn’t already exist. If - you configure a custom index, the name must be lowercase, and conform to the - {es} {ref}/indices-create-index.html[index name limitations]. - *Default: `".kibana"`* - | `data.autocomplete.valueSuggestions.timeout:` {ess-icon} | Time in milliseconds to wait for autocomplete suggestions from {es}. This value must be a whole number greater than zero. *Default: `"1000"`* @@ -362,11 +350,6 @@ When `includeElasticMapsService` is turned off, only tile layer configured by << | `map.emsUrl:` | Specifies the URL of a self hosted <> -| `map.proxyElasticMapsServiceInMaps:` - | deprecated:[7.14.0,"In 8.0 and later, this setting will no longer be supported."] - Set to `true` to proxy all <> Elastic Maps Service -requests through the {kib} server. *Default: `false`* - | [[tilemap-settings]] `map.tilemap.options.attribution:` {ess-icon} | The map attribution string. *Default: `"© [Elastic Maps Service](https://www.elastic.co/elastic-maps-service)"`* diff --git a/docs/setup/upgrade.asciidoc b/docs/setup/upgrade.asciidoc index bd93517a7a82f..f5ed03f85cc1a 100644 --- a/docs/setup/upgrade.asciidoc +++ b/docs/setup/upgrade.asciidoc @@ -1,55 +1,45 @@ [[upgrade]] == Upgrade {kib} -Depending on the {kib} version you're upgrading from, the upgrade process to {version} -varies. The following upgrades are supported: +You can always upgrade to the latest patch release or from one minor version +to another within the same major version series. -* Between minor versions -* From 5.6 to 6.8 -* From 6.8 to {prev-major-version} -* From {prev-major-version} to {version} -ifeval::[ "{version}" != "{minor-version}.0" ] -* From any version since {minor-version}.0 to {version} -endif::[] +For major version upgrades: -The following table shows the recommended upgrade paths to {version}. +. Upgrade to the last minor version released before the new major version. +. Use the Upgrade Assistant to determine what changes you need to make before the major version upgrade. +. When you've addressed all the critical issues, upgrade {es} and then upgrade {kib}. + +IMPORTANT: You can upgrade to pre-release versions of 8.0 for testing, +but upgrading from a pre-release to the final GA version is not supported. +Pre-releases should only be used for testing in a temporary environment. + +[discrete] +[[upgrade-paths]] +=== Recommended upgrade paths to 8.0 [cols="<1,3",options="header",] |==== -|Upgrade from -|Recommended upgrade path to {version} - -ifeval::[ "{version}" != "{minor-version}.0" ] -|A previous {minor-version} version (e.g., {minor-version}.0) -|Upgrade to {version} -endif::[] +|Upgrading from +|Upgrade path -|{prev-major-version} -|Upgrade to {version} +|7.16 +|Upgrade to 8.0 -|7.0–7.7 +|6.8–7.15 a| -. Upgrade to {prev-major-version} -. Upgrade to {version} -|6.8 -a| -. Upgrade to {prev-major-version} -. Upgrade to {version} +. Upgrade to 7.16 +. Upgrade to 8.0 |6.0–6.7 a| . Upgrade to 6.8 -. Upgrade to {prev-major-version} -. Upgrade to {version} +. Upgrade to 7.16 +. Upgrade to 8.0 |==== -[WARNING] -==== -The upgrade path from 6.8 to 7.0 is *not* supported. -==== - [float] [[upgrade-before-you-begin]] === Before you begin diff --git a/docs/setup/upgrade/upgrade-migrations.asciidoc b/docs/setup/upgrade/upgrade-migrations.asciidoc index 947043b21ef50..adf86d2b2b542 100644 --- a/docs/setup/upgrade/upgrade-migrations.asciidoc +++ b/docs/setup/upgrade/upgrade-migrations.asciidoc @@ -16,8 +16,8 @@ WARNING: The following instructions assumes {kib} is using the default index nam Saved objects are stored in two indices: -* `.kibana_{kibana_version}_001`, or if the `kibana.index` configuration setting is set `.{kibana.index}_{kibana_version}_001`. E.g. for Kibana v7.12.0 `.kibana_7.12.0_001`. -* `.kibana_task_manager_{kibana_version}_001`, or if the `xpack.tasks.index` configuration setting is set `.{xpack.tasks.index}_{kibana_version}_001` E.g. for Kibana v7.12.0 `.kibana_task_manager_7.12.0_001`. +* `.kibana_{kibana_version}_001`, e.g. for Kibana v7.12.0 `.kibana_7.12.0_001`. +* `.kibana_task_manager_{kibana_version}_001`, e.g. for Kibana v7.12.0 `.kibana_task_manager_7.12.0_001`. The index aliases `.kibana` and `.kibana_task_manager` will always point to the most up-to-date saved object indices. diff --git a/docs/user/production-considerations/task-manager-production-considerations.asciidoc b/docs/user/production-considerations/task-manager-production-considerations.asciidoc index 0de32bf00948b..672c310f138e9 100644 --- a/docs/user/production-considerations/task-manager-production-considerations.asciidoc +++ b/docs/user/production-considerations/task-manager-production-considerations.asciidoc @@ -12,7 +12,7 @@ This has three major benefits: [IMPORTANT] ============================================== -Task definitions for alerts and actions are stored in the index specified by <>. The default is `.kibana_task_manager`. +Task definitions for alerts and actions are stored in the index called `.kibana_task_manager`. You must have at least one replica of this index for production deployments. diff --git a/examples/search_examples/public/plugin.ts b/examples/search_examples/public/plugin.ts index b00362aef1f5e..95ea688f49cc2 100644 --- a/examples/search_examples/public/plugin.ts +++ b/examples/search_examples/public/plugin.ts @@ -8,18 +8,18 @@ import { AppMountParameters, + AppNavLinkStatus, CoreSetup, CoreStart, Plugin, - AppNavLinkStatus, } from '../../../src/core/public'; import { - SearchExamplesPluginSetup, - SearchExamplesPluginStart, AppPluginSetupDependencies, AppPluginStartDependencies, + SearchExamplesPluginSetup, + SearchExamplesPluginStart, } from './types'; -import { createSearchSessionsExampleUrlGenerator } from './search_sessions/url_generator'; +import { SearchSessionsExamplesAppLocatorDefinition } from './search_sessions/app_locator'; import { PLUGIN_NAME } from '../common'; import img from './search_examples.png'; @@ -67,14 +67,10 @@ export class SearchExamplesPlugin ], }); - // we need an URL generator for search session examples for restoring a search session - share.urlGenerators.registerUrlGenerator( - createSearchSessionsExampleUrlGenerator(() => { - return core - .getStartServices() - .then(([coreStart]) => ({ appBasePath: coreStart.http.basePath.get() })); - }) - ); + // we need an locator for search session examples for restoring a search session + const getAppBasePath = () => + core.getStartServices().then(([coreStart]) => coreStart.http.basePath.get()); + share.url.locators.create(new SearchSessionsExamplesAppLocatorDefinition(getAppBasePath)); return {}; } diff --git a/examples/search_examples/public/search_sessions/app.tsx b/examples/search_examples/public/search_sessions/app.tsx index 63ab706c945d5..c953da0895ccd 100644 --- a/examples/search_examples/public/search_sessions/app.tsx +++ b/examples/search_examples/public/search_sessions/app.tsx @@ -55,11 +55,7 @@ import { createStateContainer, useContainerState, } from '../../../../src/plugins/kibana_utils/public'; -import { - getInitialStateFromUrl, - SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, - SearchSessionExamplesUrlGeneratorState, -} from './url_generator'; +import { getInitialStateFromUrl, SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR } from './app_locator'; interface SearchSessionsExampleAppDeps { notifications: CoreStart['notifications']; @@ -140,14 +136,14 @@ export const SearchSessionsExampleApp = ({ const enableSessionStorage = useCallback(() => { data.search.session.enableStorage({ getName: async () => 'Search sessions example', - getUrlGeneratorData: async () => ({ + getLocatorData: async () => ({ initialState: { time: data.query.timefilter.timefilter.getTime(), filters: data.query.filterManager.getFilters(), query: data.query.queryString.getQuery(), indexPatternId: indexPattern?.id, numericFieldName, - } as SearchSessionExamplesUrlGeneratorState, + }, restoreState: { time: data.query.timefilter.timefilter.getAbsoluteTime(), filters: data.query.filterManager.getFilters(), @@ -155,8 +151,8 @@ export const SearchSessionsExampleApp = ({ indexPatternId: indexPattern?.id, numericFieldName, searchSessionId: data.search.session.getSessionId(), - } as SearchSessionExamplesUrlGeneratorState, - urlGeneratorId: SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, + }, + id: SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR, }), }); }, [ diff --git a/examples/search_examples/public/search_sessions/url_generator.ts b/examples/search_examples/public/search_sessions/app_locator.ts similarity index 52% rename from examples/search_examples/public/search_sessions/url_generator.ts rename to examples/search_examples/public/search_sessions/app_locator.ts index 69355f9046c46..1cbd27887c1c3 100644 --- a/examples/search_examples/public/search_sessions/url_generator.ts +++ b/examples/search_examples/public/search_sessions/app_locator.ts @@ -6,17 +6,17 @@ * Side Public License, v 1. */ -import { TimeRange, Filter, Query, esFilters } from '../../../../src/plugins/data/public'; +import { SerializableRecord } from '@kbn/utility-types'; +import { esFilters, Filter, Query, TimeRange } from '../../../../src/plugins/data/public'; import { getStatesFromKbnUrl, setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public'; -import { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public'; +import { LocatorDefinition } from '../../../../src/plugins/share/common'; export const STATE_STORAGE_KEY = '_a'; export const GLOBAL_STATE_STORAGE_KEY = '_g'; -export const SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR = - 'SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR'; +export const SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR = 'SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR'; -export interface AppUrlState { +export interface AppUrlState extends SerializableRecord { filters?: Filter[]; query?: Query; indexPatternId?: string; @@ -24,32 +24,32 @@ export interface AppUrlState { searchSessionId?: string; } -export interface GlobalUrlState { +export interface GlobalUrlState extends SerializableRecord { filters?: Filter[]; time?: TimeRange; } -export type SearchSessionExamplesUrlGeneratorState = AppUrlState & GlobalUrlState; +export type SearchSessionsExamplesAppLocatorParams = AppUrlState & GlobalUrlState; -export const createSearchSessionsExampleUrlGenerator = ( - getStartServices: () => Promise<{ - appBasePath: string; - }> -): UrlGeneratorsDefinition => ({ - id: SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, - createUrl: async (state: SearchSessionExamplesUrlGeneratorState) => { - const startServices = await getStartServices(); - const appBasePath = startServices.appBasePath; - const path = `${appBasePath}/app/searchExamples/search-sessions`; +export class SearchSessionsExamplesAppLocatorDefinition + implements LocatorDefinition +{ + public readonly id = SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR; + + constructor(protected readonly getAppBasePath: () => Promise) {} + + public readonly getLocation = async (params: SearchSessionsExamplesAppLocatorParams) => { + const appBasePath = await this.getAppBasePath(); + const path = `${appBasePath}/search-sessions`; let url = setStateToKbnUrl( STATE_STORAGE_KEY, { - query: state.query, - filters: state.filters?.filter((f) => !esFilters.isFilterPinned(f)), - indexPatternId: state.indexPatternId, - numericFieldName: state.numericFieldName, - searchSessionId: state.searchSessionId, + query: params.query, + filters: params.filters?.filter((f) => !esFilters.isFilterPinned(f)), + indexPatternId: params.indexPatternId, + numericFieldName: params.numericFieldName, + searchSessionId: params.searchSessionId, } as AppUrlState, { useHash: false, storeInHashQuery: false }, path @@ -58,18 +58,22 @@ export const createSearchSessionsExampleUrlGenerator = ( url = setStateToKbnUrl( GLOBAL_STATE_STORAGE_KEY, { - time: state.time, - filters: state.filters?.filter((f) => esFilters.isFilterPinned(f)), + time: params.time, + filters: params.filters?.filter((f) => esFilters.isFilterPinned(f)), } as GlobalUrlState, { useHash: false, storeInHashQuery: false }, url ); - return url; - }, -}); + return { + app: 'searchExamples', + path: url, + state: {}, + }; + }; +} -export function getInitialStateFromUrl(): SearchSessionExamplesUrlGeneratorState { +export function getInitialStateFromUrl(): SearchSessionsExamplesAppLocatorParams { const { _a: { numericFieldName, indexPatternId, searchSessionId, filters: aFilters, query } = {}, _g: { filters: gFilters, time } = {}, diff --git a/package.json b/package.json index e6b17783197bc..b2065ddc1d608 100644 --- a/package.json +++ b/package.json @@ -95,14 +95,14 @@ "@dnd-kit/core": "^3.1.1", "@dnd-kit/sortable": "^4.0.0", "@dnd-kit/utilities": "^2.0.0", - "@elastic/apm-generator": "link:bazel-bin/packages/elastic-apm-generator", + "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", "@elastic/apm-rum": "^5.9.1", "@elastic/apm-rum-react": "^1.3.1", "@elastic/charts": "38.0.1", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", - "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.21", - "@elastic/ems-client": "7.16.0", - "@elastic/eui": "39.1.1", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.35", + "@elastic/ems-client": "8.0.0", + "@elastic/eui": "40.0.0", "@elastic/filesaver": "1.1.2", "@elastic/maki": "6.3.0", "@elastic/node-crypto": "1.2.1", @@ -148,6 +148,7 @@ "@kbn/securitysolution-list-constants": "link:bazel-bin/packages/kbn-securitysolution-list-constants", "@kbn/securitysolution-list-hooks": "link:bazel-bin/packages/kbn-securitysolution-list-hooks", "@kbn/securitysolution-list-utils": "link:bazel-bin/packages/kbn-securitysolution-list-utils", + "@kbn/securitysolution-rules": "link:bazel-bin/packages/kbn-securitysolution-rules", "@kbn/securitysolution-t-grid": "link:bazel-bin/packages/kbn-securitysolution-t-grid", "@kbn/securitysolution-utils": "link:bazel-bin/packages/kbn-securitysolution-utils", "@kbn/server-http-tools": "link:bazel-bin/packages/kbn-server-http-tools", @@ -166,7 +167,6 @@ "@mapbox/geojson-rewind": "^0.5.0", "@mapbox/mapbox-gl-draw": "1.3.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", - "@mapbox/vector-tile": "1.3.1", "@reduxjs/toolkit": "^1.6.1", "@slack/webhook": "^5.0.4", "@turf/along": "6.0.1", @@ -218,7 +218,7 @@ "deep-freeze-strict": "^1.1.1", "deepmerge": "^4.2.2", "del": "^5.1.0", - "elastic-apm-node": "^3.21.1", + "elastic-apm-node": "^3.23.0", "execa": "^4.0.2", "exit-hook": "^2.2.0", "expiry-js": "0.1.7", @@ -331,7 +331,7 @@ "react-moment-proptypes": "^1.7.0", "react-monaco-editor": "^0.41.2", "react-popper-tooltip": "^2.10.1", - "react-query": "^3.27.0", + "react-query": "^3.28.0", "react-redux": "^7.2.0", "react-resizable": "^1.7.5", "react-resize-detector": "^4.2.0", @@ -460,6 +460,7 @@ "@kbn/test": "link:bazel-bin/packages/kbn-test", "@kbn/test-subj-selector": "link:bazel-bin/packages/kbn-test-subj-selector", "@loaders.gl/polyfills": "^2.3.5", + "@mapbox/vector-tile": "1.3.1", "@microsoft/api-documenter": "7.7.2", "@microsoft/api-extractor": "7.7.0", "@octokit/rest": "^16.35.0", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index ace4f982b8515..bda4f1b79df55 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -3,7 +3,7 @@ filegroup( name = "build", srcs = [ - "//packages/elastic-apm-generator:build", + "//packages/elastic-apm-synthtrace:build", "//packages/elastic-datemath:build", "//packages/elastic-eslint-config-kibana:build", "//packages/elastic-safer-lodash-set:build", @@ -46,6 +46,7 @@ filegroup( "//packages/kbn-securitysolution-list-api:build", "//packages/kbn-securitysolution-list-hooks:build", "//packages/kbn-securitysolution-list-utils:build", + "//packages/kbn-securitysolution-rules:build", "//packages/kbn-securitysolution-utils:build", "//packages/kbn-securitysolution-es-utils:build", "//packages/kbn-securitysolution-t-grid:build", diff --git a/packages/elastic-apm-generator/README.md b/packages/elastic-apm-generator/README.md deleted file mode 100644 index b442c0ec23ee0..0000000000000 --- a/packages/elastic-apm-generator/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# @elastic/apm-generator - -`@elastic/apm-generator` is an experimental tool to generate synthetic APM data. It is intended to be used for development and testing of the Elastic APM app in Kibana. - -At a high-level, the module works by modeling APM events/metricsets with [a fluent API](https://en.wikipedia.org/wiki/Fluent_interface). The models can then be serialized and converted to Elasticsearch documents. In the future we might support APM Server as an output as well. - -## Usage - -This section assumes that you've installed Kibana's dependencies by running `yarn kbn bootstrap` in the repository's root folder. - -This library can currently be used in two ways: - -- Imported as a Node.js module, for instance to be used in Kibana's functional test suite. -- With a command line interface, to index data based on a specified scenario. - -### Using the Node.js module - -#### Concepts - -- `Service`: a logical grouping for a monitored service. A `Service` object contains fields like `service.name`, `service.environment` and `agent.name`. -- `Instance`: a single instance of a monitored service. E.g., the workload for a monitored service might be spread across multiple containers. An `Instance` object contains fields like `service.node.name` and `container.id`. -- `Timerange`: an object that will return an array of timestamps based on an interval and a rate. These timestamps can be used to generate events/metricsets. -- `Transaction`, `Span`, `APMError` and `Metricset`: events/metricsets that occur on an instance. For more background, see the [explanation of the APM data model](https://www.elastic.co/guide/en/apm/get-started/7.15/apm-data-model.html) - - -#### Example - -```ts -import { service, timerange, toElasticsearchOutput } from '@elastic/apm-generator'; - -const instance = service('synth-go', 'production', 'go') - .instance('instance-a'); - -const from = new Date('2021-01-01T12:00:00.000Z').getTime(); -const to = new Date('2021-01-01T12:00:00.000Z').getTime(); - -const traceEvents = timerange(from, to) - .interval('1m') - .rate(10) - .flatMap(timestamp => instance.transaction('GET /api/product/list') - .timestamp(timestamp) - .duration(1000) - .success() - .children( - instance.span('GET apm-*/_search', 'db', 'elasticsearch') - .timestamp(timestamp + 50) - .duration(900) - .destination('elasticsearch') - .success() - ).serialize() - ); - -const metricsets = timerange(from, to) - .interval('30s') - .rate(1) - .flatMap(timestamp => instance.appMetrics({ - 'system.memory.actual.free': 800, - 'system.memory.total': 1000, - 'system.cpu.total.norm.pct': 0.6, - 'system.process.cpu.total.norm.pct': 0.7, - }).timestamp(timestamp) - .serialize() - ); - -const esEvents = toElasticsearchOutput(traceEvents.concat(metricsets)); -``` - -#### Generating metricsets - -`@elastic/apm-generator` can also automatically generate transaction metrics, span destination metrics and transaction breakdown metrics based on the generated trace events. If we expand on the previous example: - -```ts -import { getTransactionMetrics, getSpanDestinationMetrics, getBreakdownMetrics } from '@elastic/apm-generator'; - -const esEvents = toElasticsearchOutput([ - ...traceEvents, - ...getTransactionMetrics(traceEvents), - ...getSpanDestinationMetrics(traceEvents), - ...getBreakdownMetrics(traceEvents) -]); -``` - -### CLI - -Via the CLI, you can upload scenarios, either using a fixed time range or continuously generating data. Some examples are available in in `src/scripts/examples`. Here's an example for live data: - -`$ node packages/elastic-apm-generator/src/scripts/run packages/elastic-apm-generator/src/examples/01_simple_trace.ts --target=http://admin:changeme@localhost:9200 --live` - -For a fixed time window: -`$ node packages/elastic-apm-generator/src/scripts/run packages/elastic-apm-generator/src/examples/01_simple_trace.ts --target=http://admin:changeme@localhost:9200 --from=now-24h --to=now` - -The script will try to automatically find bootstrapped APM indices. __If these indices do not exist, the script will exit with an error. It will not bootstrap the indices itself.__ - -The following options are supported: -| Option | Description | Default | -| -------------- | ------------------------------------------------------- | ------------ | -| `--from` | The start of the time window. | `now - 15m` | -| `--to` | The end of the time window. | `now` | -| `--live` | Continously ingest data | `false` | -| `--bucketSize` | Size of bucket for which to generate data. | `15m` | -| `--clean` | Clean APM indices before indexing new data. | `false` | -| `--interval` | The interval at which to index data. | `10s` | -| `--logLevel` | Log level. | `info` | -| `--lookback` | The lookback window for which data should be generated. | `15m` | -| `--target` | Elasticsearch target, including username/password. | **Required** | -| `--workers` | Amount of simultaneously connected ES clients. | `1` | - diff --git a/packages/elastic-apm-generator/src/scripts/utils/common_options.ts b/packages/elastic-apm-generator/src/scripts/utils/common_options.ts deleted file mode 100644 index eba547114d533..0000000000000 --- a/packages/elastic-apm-generator/src/scripts/utils/common_options.ts +++ /dev/null @@ -1,53 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -const fileOption = { - describe: 'File that contains the trace scenario', - demandOption: true, -}; - -const intervalOption = { - describe: 'The interval at which to index data', - default: '10s', -}; - -const targetOption = { - describe: 'Elasticsearch target, including username/password', - demandOption: true, -}; - -const bucketSizeOption = { - describe: 'Size of bucket for which to generate data', - default: '15m', -}; - -const workerOption = { - describe: 'Amount of simultaneously connected ES clients', - default: 1, -}; - -const cleanOption = { - describe: 'Clean APM indices before indexing new data', - default: false, - boolean: true as const, -}; - -const logLevelOption = { - describe: 'Log level', - default: 'info', -}; - -export { - fileOption, - intervalOption, - targetOption, - bucketSizeOption, - workerOption, - cleanOption, - logLevelOption, -}; diff --git a/packages/elastic-apm-generator/src/scripts/utils/logger.ts b/packages/elastic-apm-generator/src/scripts/utils/logger.ts deleted file mode 100644 index c9017cb08e663..0000000000000 --- a/packages/elastic-apm-generator/src/scripts/utils/logger.ts +++ /dev/null @@ -1,32 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export enum LogLevel { - debug = 0, - info = 1, - quiet = 2, -} - -export function createLogger(logLevel: LogLevel) { - return { - debug: (...args: any[]) => { - if (logLevel <= LogLevel.debug) { - // eslint-disable-next-line no-console - console.debug(...args); - } - }, - info: (...args: any[]) => { - if (logLevel <= LogLevel.info) { - // eslint-disable-next-line no-console - console.log(...args); - } - }, - }; -} - -export type Logger = ReturnType; diff --git a/packages/elastic-apm-generator/src/scripts/utils/start_historical_data_upload.ts b/packages/elastic-apm-generator/src/scripts/utils/start_historical_data_upload.ts deleted file mode 100644 index db14090dd1d8f..0000000000000 --- a/packages/elastic-apm-generator/src/scripts/utils/start_historical_data_upload.ts +++ /dev/null @@ -1,64 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Client } from '@elastic/elasticsearch'; -import { ElasticsearchOutputWriteTargets } from '../../lib/output/to_elasticsearch_output'; -import { Scenario } from './get_scenario'; -import { Logger } from './logger'; -import { uploadEvents } from './upload_events'; - -export async function startHistoricalDataUpload({ - from, - to, - scenario, - intervalInMs, - bucketSizeInMs, - client, - workers, - writeTargets, - logger, -}: { - from: number; - to: number; - scenario: Scenario; - intervalInMs: number; - bucketSizeInMs: number; - client: Client; - workers: number; - writeTargets: ElasticsearchOutputWriteTargets; - logger: Logger; -}) { - let requestedUntil: number = from; - function uploadNextBatch() { - const bucketFrom = requestedUntil; - const bucketTo = Math.min(to, bucketFrom + bucketSizeInMs); - - const events = scenario({ from: bucketFrom, to: bucketTo }); - - logger.info( - `Uploading: ${new Date(bucketFrom).toISOString()} to ${new Date(bucketTo).toISOString()}` - ); - - uploadEvents({ - events, - client, - workers, - writeTargets, - logger, - }).then(() => { - if (bucketTo >= to) { - return; - } - uploadNextBatch(); - }); - - requestedUntil = bucketTo; - } - - return uploadNextBatch(); -} diff --git a/packages/elastic-apm-generator/BUILD.bazel b/packages/elastic-apm-synthtrace/BUILD.bazel similarity index 95% rename from packages/elastic-apm-generator/BUILD.bazel rename to packages/elastic-apm-synthtrace/BUILD.bazel index 396c27b3a4c89..5d9510c6a81d5 100644 --- a/packages/elastic-apm-generator/BUILD.bazel +++ b/packages/elastic-apm-synthtrace/BUILD.bazel @@ -2,8 +2,8 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") load("//src/dev/bazel:index.bzl", "jsts_transpiler") -PKG_BASE_NAME = "elastic-apm-generator" -PKG_REQUIRE_NAME = "@elastic/apm-generator" +PKG_BASE_NAME = "elastic-apm-synthtrace" +PKG_REQUIRE_NAME = "@elastic/apm-synthtrace" SOURCE_FILES = glob( [ diff --git a/packages/elastic-apm-synthtrace/README.md b/packages/elastic-apm-synthtrace/README.md new file mode 100644 index 0000000000000..3d65120b4b6c2 --- /dev/null +++ b/packages/elastic-apm-synthtrace/README.md @@ -0,0 +1,116 @@ +# @elastic/apm-synthtrace + +`@elastic/apm-synthtrace` is an experimental tool to generate synthetic APM data. It is intended to be used for development and testing of the Elastic APM app in Kibana. + +At a high-level, the module works by modeling APM events/metricsets with [a fluent API](https://en.wikipedia.org/wiki/Fluent_interface). The models can then be serialized and converted to Elasticsearch documents. In the future we might support APM Server as an output as well. + +## Usage + +This section assumes that you've installed Kibana's dependencies by running `yarn kbn bootstrap` in the repository's root folder. + +This library can currently be used in two ways: + +- Imported as a Node.js module, for instance to be used in Kibana's functional test suite. +- With a command line interface, to index data based on a specified scenario. + +### Using the Node.js module + +#### Concepts + +- `Service`: a logical grouping for a monitored service. A `Service` object contains fields like `service.name`, `service.environment` and `agent.name`. +- `Instance`: a single instance of a monitored service. E.g., the workload for a monitored service might be spread across multiple containers. An `Instance` object contains fields like `service.node.name` and `container.id`. +- `Timerange`: an object that will return an array of timestamps based on an interval and a rate. These timestamps can be used to generate events/metricsets. +- `Transaction`, `Span`, `APMError` and `Metricset`: events/metricsets that occur on an instance. For more background, see the [explanation of the APM data model](https://www.elastic.co/guide/en/apm/get-started/7.15/apm-data-model.html) + +#### Example + +```ts +import { service, timerange, toElasticsearchOutput } from '@elastic/apm-synthtrace'; + +const instance = service('synth-go', 'production', 'go').instance('instance-a'); + +const from = new Date('2021-01-01T12:00:00.000Z').getTime(); +const to = new Date('2021-01-01T12:00:00.000Z').getTime(); + +const traceEvents = timerange(from, to) + .interval('1m') + .rate(10) + .flatMap((timestamp) => + instance + .transaction('GET /api/product/list') + .timestamp(timestamp) + .duration(1000) + .success() + .children( + instance + .span('GET apm-*/_search', 'db', 'elasticsearch') + .timestamp(timestamp + 50) + .duration(900) + .destination('elasticsearch') + .success() + ) + .serialize() + ); + +const metricsets = timerange(from, to) + .interval('30s') + .rate(1) + .flatMap((timestamp) => + instance + .appMetrics({ + 'system.memory.actual.free': 800, + 'system.memory.total': 1000, + 'system.cpu.total.norm.pct': 0.6, + 'system.process.cpu.total.norm.pct': 0.7, + }) + .timestamp(timestamp) + .serialize() + ); + +const esEvents = toElasticsearchOutput(traceEvents.concat(metricsets)); +``` + +#### Generating metricsets + +`@elastic/apm-synthtrace` can also automatically generate transaction metrics, span destination metrics and transaction breakdown metrics based on the generated trace events. If we expand on the previous example: + +```ts +import { + getTransactionMetrics, + getSpanDestinationMetrics, + getBreakdownMetrics, +} from '@elastic/apm-synthtrace'; + +const esEvents = toElasticsearchOutput([ + ...traceEvents, + ...getTransactionMetrics(traceEvents), + ...getSpanDestinationMetrics(traceEvents), + ...getBreakdownMetrics(traceEvents), +]); +``` + +### CLI + +Via the CLI, you can upload scenarios, either using a fixed time range or continuously generating data. Some examples are available in in `src/scripts/examples`. Here's an example for live data: + +`$ node packages/elastic-apm-synthtrace/src/scripts/run packages/elastic-apm-generator/src/examples/01_simple_trace.ts --target=http://admin:changeme@localhost:9200 --live` + +For a fixed time window: +`$ node packages/elastic-apm-synthtrace/src/scripts/run packages/elastic-apm-generator/src/examples/01_simple_trace.ts --target=http://admin:changeme@localhost:9200 --from=now-24h --to=now` + +The script will try to automatically find bootstrapped APM indices. __If these indices do not exist, the script will exit with an error. It will not bootstrap the indices itself.__ + +The following options are supported: +| Option | Description | Default | +| ------------------| ------------------------------------------------------- | ------------ | +| `--target` | Elasticsearch target, including username/password. | **Required** | +| `--from` | The start of the time window. | `now - 15m` | +| `--to` | The end of the time window. | `now` | +| `--live` | Continously ingest data | `false` | +| `--clean` | Clean APM indices before indexing new data. | `false` | +| `--workers` | Amount of Node.js worker threads | `5` | +| `--bucketSize` | Size of bucket for which to generate data. | `15m` | +| `--interval` | The interval at which to index data. | `10s` | +| `--clientWorkers` | Number of simultaneously connected ES clients | `5` | +| `--batchSize` | Number of documents per bulk index request | `1000` | +| `--logLevel` | Log level. | `info` | diff --git a/packages/elastic-apm-generator/jest.config.js b/packages/elastic-apm-synthtrace/jest.config.js similarity index 89% rename from packages/elastic-apm-generator/jest.config.js rename to packages/elastic-apm-synthtrace/jest.config.js index 64aaa43741cc3..13d8643c5213c 100644 --- a/packages/elastic-apm-generator/jest.config.js +++ b/packages/elastic-apm-synthtrace/jest.config.js @@ -9,7 +9,7 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/elastic-apm-generator'], + roots: ['/packages/elastic-apm-synthtrace'], setupFiles: [], setupFilesAfterEnv: [], }; diff --git a/packages/elastic-apm-generator/package.json b/packages/elastic-apm-synthtrace/package.json similarity index 85% rename from packages/elastic-apm-generator/package.json rename to packages/elastic-apm-synthtrace/package.json index 57dafd5d6431d..43699e4795586 100644 --- a/packages/elastic-apm-generator/package.json +++ b/packages/elastic-apm-synthtrace/package.json @@ -1,5 +1,5 @@ { - "name": "@elastic/apm-generator", + "name": "@elastic/apm-synthtrace", "version": "0.1.0", "description": "Elastic APM trace data generator", "license": "SSPL-1.0 OR Elastic License 2.0", diff --git a/packages/elastic-apm-generator/src/.eslintrc.js b/packages/elastic-apm-synthtrace/src/.eslintrc.js similarity index 100% rename from packages/elastic-apm-generator/src/.eslintrc.js rename to packages/elastic-apm-synthtrace/src/.eslintrc.js diff --git a/packages/elastic-apm-generator/src/index.ts b/packages/elastic-apm-synthtrace/src/index.ts similarity index 100% rename from packages/elastic-apm-generator/src/index.ts rename to packages/elastic-apm-synthtrace/src/index.ts diff --git a/packages/elastic-apm-generator/src/lib/apm_error.ts b/packages/elastic-apm-synthtrace/src/lib/apm_error.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/apm_error.ts rename to packages/elastic-apm-synthtrace/src/lib/apm_error.ts diff --git a/packages/elastic-apm-generator/src/lib/base_span.ts b/packages/elastic-apm-synthtrace/src/lib/base_span.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/base_span.ts rename to packages/elastic-apm-synthtrace/src/lib/base_span.ts diff --git a/packages/elastic-apm-generator/src/lib/defaults/get_observer_defaults.ts b/packages/elastic-apm-synthtrace/src/lib/defaults/get_observer_defaults.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/defaults/get_observer_defaults.ts rename to packages/elastic-apm-synthtrace/src/lib/defaults/get_observer_defaults.ts diff --git a/packages/elastic-apm-generator/src/lib/entity.ts b/packages/elastic-apm-synthtrace/src/lib/entity.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/entity.ts rename to packages/elastic-apm-synthtrace/src/lib/entity.ts diff --git a/packages/elastic-apm-generator/src/lib/instance.ts b/packages/elastic-apm-synthtrace/src/lib/instance.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/instance.ts rename to packages/elastic-apm-synthtrace/src/lib/instance.ts diff --git a/packages/elastic-apm-generator/src/lib/interval.ts b/packages/elastic-apm-synthtrace/src/lib/interval.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/interval.ts rename to packages/elastic-apm-synthtrace/src/lib/interval.ts diff --git a/packages/elastic-apm-generator/src/lib/metricset.ts b/packages/elastic-apm-synthtrace/src/lib/metricset.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/metricset.ts rename to packages/elastic-apm-synthtrace/src/lib/metricset.ts diff --git a/packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts b/packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts similarity index 78% rename from packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts rename to packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts index 31f3e8c8ed270..016f1c5362fb4 100644 --- a/packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts +++ b/packages/elastic-apm-synthtrace/src/lib/output/to_elasticsearch_output.ts @@ -22,6 +22,18 @@ export interface ElasticsearchOutputWriteTargets { metric: string; } +const observerDefaults = getObserverDefaults(); + +const esDocumentDefaults = { + ecs: { + version: '1.4', + }, +}; + +// eslint-disable-next-line guard-for-in +for (const key in observerDefaults) { + set(esDocumentDefaults, key, observerDefaults[key as keyof typeof observerDefaults]); +} export function toElasticsearchOutput({ events, writeTargets, @@ -30,22 +42,25 @@ export function toElasticsearchOutput({ writeTargets: ElasticsearchOutputWriteTargets; }): ElasticsearchOutput[] { return events.map((event) => { - const values = { - ...event, - ...getObserverDefaults(), + const values = {}; + + Object.assign(values, event, { '@timestamp': new Date(event['@timestamp']!).toISOString(), 'timestamp.us': event['@timestamp']! * 1000, - 'ecs.version': '1.4', 'service.node.name': event['service.node.name'] || event['container.id'] || event['host.name'], - }; + }); const document = {}; + + Object.assign(document, esDocumentDefaults); + // eslint-disable-next-line guard-for-in for (const key in values) { const val = values[key as keyof typeof values]; set(document, key, val); } + return { _index: writeTargets[event['processor.event'] as keyof ElasticsearchOutputWriteTargets], _source: document, diff --git a/packages/elastic-apm-generator/src/lib/serializable.ts b/packages/elastic-apm-synthtrace/src/lib/serializable.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/serializable.ts rename to packages/elastic-apm-synthtrace/src/lib/serializable.ts diff --git a/packages/elastic-apm-generator/src/lib/service.ts b/packages/elastic-apm-synthtrace/src/lib/service.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/service.ts rename to packages/elastic-apm-synthtrace/src/lib/service.ts diff --git a/packages/elastic-apm-generator/src/lib/span.ts b/packages/elastic-apm-synthtrace/src/lib/span.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/span.ts rename to packages/elastic-apm-synthtrace/src/lib/span.ts diff --git a/packages/elastic-apm-generator/src/lib/timerange.ts b/packages/elastic-apm-synthtrace/src/lib/timerange.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/timerange.ts rename to packages/elastic-apm-synthtrace/src/lib/timerange.ts diff --git a/packages/elastic-apm-generator/src/lib/transaction.ts b/packages/elastic-apm-synthtrace/src/lib/transaction.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/transaction.ts rename to packages/elastic-apm-synthtrace/src/lib/transaction.ts diff --git a/packages/elastic-apm-generator/src/lib/utils/aggregate.ts b/packages/elastic-apm-synthtrace/src/lib/utils/aggregate.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/utils/aggregate.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/aggregate.ts diff --git a/packages/elastic-apm-generator/src/lib/utils/create_picker.ts b/packages/elastic-apm-synthtrace/src/lib/utils/create_picker.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/utils/create_picker.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/create_picker.ts diff --git a/packages/elastic-apm-generator/src/lib/utils/generate_id.ts b/packages/elastic-apm-synthtrace/src/lib/utils/generate_id.ts similarity index 63% rename from packages/elastic-apm-generator/src/lib/utils/generate_id.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/generate_id.ts index cc372a56209aa..c65c2843ddd3b 100644 --- a/packages/elastic-apm-generator/src/lib/utils/generate_id.ts +++ b/packages/elastic-apm-synthtrace/src/lib/utils/generate_id.ts @@ -6,20 +6,17 @@ * Side Public License, v 1. */ -import uuidv5 from 'uuid/v5'; - let seq = 0; -const namespace = 'f38d5b83-8eee-4f5b-9aa6-2107e15a71e3'; - -function generateId(seed?: string) { - return uuidv5(seed ?? String(seq++), namespace).replace(/-/g, ''); +function generateId(seed?: string, length: number = 32) { + const str = seed ?? String(seq++); + return str.padStart(length, '0'); } export function generateShortId(seed?: string) { - return generateId(seed).substr(0, 16); + return generateId(seed, 16); } export function generateLongId(seed?: string) { - return generateId(seed).substr(0, 32); + return generateId(seed, 32); } diff --git a/packages/elastic-apm-generator/src/lib/utils/get_breakdown_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/utils/get_breakdown_metrics.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/utils/get_breakdown_metrics.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/get_breakdown_metrics.ts diff --git a/packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/utils/get_span_destination_metrics.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/get_span_destination_metrics.ts diff --git a/packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/utils/get_transaction_metrics.ts similarity index 100% rename from packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts rename to packages/elastic-apm-synthtrace/src/lib/utils/get_transaction_metrics.ts diff --git a/packages/elastic-apm-generator/src/scripts/examples/01_simple_trace.ts b/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts similarity index 56% rename from packages/elastic-apm-generator/src/scripts/examples/01_simple_trace.ts rename to packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts index 6b857391b4f96..8c1f24bd5e64f 100644 --- a/packages/elastic-apm-generator/src/scripts/examples/01_simple_trace.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts @@ -10,16 +10,20 @@ import { service, timerange, getTransactionMetrics, getSpanDestinationMetrics } import { getBreakdownMetrics } from '../../lib/utils/get_breakdown_metrics'; export default function ({ from, to }: { from: number; to: number }) { - const instance = service('opbeans-go', 'production', 'go').instance('instance'); + const numServices = 3; const range = timerange(from, to); const transactionName = '240rpm/75% 1000ms'; - const successfulTraceEvents = range - .interval('1s') - .rate(3) - .flatMap((timestamp) => + const successfulTimestamps = range.interval('1s').rate(3); + + const failedTimestamps = range.interval('1s').rate(1); + + return new Array(numServices).fill(undefined).flatMap((_, index) => { + const instance = service(`opbeans-go-${index}`, 'production', 'go').instance('instance'); + + const successfulTraceEvents = successfulTimestamps.flatMap((timestamp) => instance .transaction(transactionName) .timestamp(timestamp) @@ -37,10 +41,7 @@ export default function ({ from, to }: { from: number; to: number }) { .serialize() ); - const failedTraceEvents = range - .interval('1s') - .rate(1) - .flatMap((timestamp) => + const failedTraceEvents = failedTimestamps.flatMap((timestamp) => instance .transaction(transactionName) .timestamp(timestamp) @@ -52,27 +53,28 @@ export default function ({ from, to }: { from: number; to: number }) { .serialize() ); - const metricsets = range - .interval('30s') - .rate(1) - .flatMap((timestamp) => - instance - .appMetrics({ - 'system.memory.actual.free': 800, - 'system.memory.total': 1000, - 'system.cpu.total.norm.pct': 0.6, - 'system.process.cpu.total.norm.pct': 0.7, - }) - .timestamp(timestamp) - .serialize() - ); - const events = successfulTraceEvents.concat(failedTraceEvents); + const metricsets = range + .interval('30s') + .rate(1) + .flatMap((timestamp) => + instance + .appMetrics({ + 'system.memory.actual.free': 800, + 'system.memory.total': 1000, + 'system.cpu.total.norm.pct': 0.6, + 'system.process.cpu.total.norm.pct': 0.7, + }) + .timestamp(timestamp) + .serialize() + ); + const events = successfulTraceEvents.concat(failedTraceEvents); - return [ - ...events, - ...metricsets, - ...getTransactionMetrics(events), - ...getSpanDestinationMetrics(events), - ...getBreakdownMetrics(events), - ]; + return [ + ...events, + ...metricsets, + ...getTransactionMetrics(events), + ...getSpanDestinationMetrics(events), + ...getBreakdownMetrics(events), + ]; + }); } diff --git a/packages/elastic-apm-generator/src/scripts/run.js b/packages/elastic-apm-synthtrace/src/scripts/run.js similarity index 100% rename from packages/elastic-apm-generator/src/scripts/run.js rename to packages/elastic-apm-synthtrace/src/scripts/run.js diff --git a/packages/elastic-apm-generator/src/scripts/run.ts b/packages/elastic-apm-synthtrace/src/scripts/run.ts similarity index 59% rename from packages/elastic-apm-generator/src/scripts/run.ts rename to packages/elastic-apm-synthtrace/src/scripts/run.ts index ad453ac96ff10..367cdc2b91505 100644 --- a/packages/elastic-apm-generator/src/scripts/run.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/run.ts @@ -8,15 +8,6 @@ import datemath from '@elastic/datemath'; import yargs from 'yargs/yargs'; import { cleanWriteTargets } from './utils/clean_write_targets'; -import { - bucketSizeOption, - cleanOption, - fileOption, - intervalOption, - targetOption, - workerOption, - logLevelOption, -} from './utils/common_options'; import { intervalToMs } from './utils/interval_to_ms'; import { getCommonResources } from './utils/get_common_resources'; import { startHistoricalDataUpload } from './utils/start_historical_data_upload'; @@ -28,13 +19,16 @@ yargs(process.argv.slice(2)) 'Generate data and index into Elasticsearch', (y) => { return y - .positional('file', fileOption) - .option('bucketSize', bucketSizeOption) - .option('workers', workerOption) - .option('interval', intervalOption) - .option('clean', cleanOption) - .option('target', targetOption) - .option('logLevel', logLevelOption) + .positional('file', { + describe: 'File that contains the trace scenario', + demandOption: true, + string: true, + }) + .option('target', { + describe: 'Elasticsearch target, including username/password', + demandOption: true, + string: true, + }) .option('from', { description: 'The start of the time window', }) @@ -45,20 +39,47 @@ yargs(process.argv.slice(2)) description: 'Generate and index data continuously', boolean: true, }) + .option('clean', { + describe: 'Clean APM indices before indexing new data', + default: false, + boolean: true, + }) + .option('workers', { + describe: 'Amount of Node.js worker threads', + default: 5, + }) + .option('bucketSize', { + describe: 'Size of bucket for which to generate data', + default: '15m', + }) + .option('interval', { + describe: 'The interval at which to index data', + default: '10s', + }) + .option('clientWorkers', { + describe: 'Number of concurrently connected ES clients', + default: 5, + }) + .option('batchSize', { + describe: 'Number of documents per bulk index request', + default: 1000, + }) + .option('logLevel', { + describe: 'Log level', + default: 'info', + }) .conflicts('to', 'live'); }, async (argv) => { - const { - scenario, - intervalInMs, - bucketSizeInMs, - target, - workers, - clean, - logger, - writeTargets, - client, - } = await getCommonResources(argv); + const file = String(argv.file || argv._[0]); + + const { target, workers, clean, clientWorkers, batchSize } = argv; + + const { scenario, intervalInMs, bucketSizeInMs, logger, writeTargets, client, logLevel } = + await getCommonResources({ + ...argv, + file, + }); if (clean) { await cleanWriteTargets({ writeTargets, client, logger }); @@ -91,13 +112,16 @@ yargs(process.argv.slice(2)) startHistoricalDataUpload({ from, to, - scenario, - intervalInMs, + file, bucketSizeInMs, client, workers, + clientWorkers, + batchSize, writeTargets, logger, + logLevel, + target, }); if (live) { @@ -108,7 +132,8 @@ yargs(process.argv.slice(2)) logger, scenario, start: to, - workers, + clientWorkers, + batchSize, writeTargets, }); } diff --git a/packages/elastic-apm-generator/src/scripts/utils/clean_write_targets.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/clean_write_targets.ts similarity index 84% rename from packages/elastic-apm-generator/src/scripts/utils/clean_write_targets.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/clean_write_targets.ts index efa24f164d51e..3c514e1097b31 100644 --- a/packages/elastic-apm-generator/src/scripts/utils/clean_write_targets.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/clean_write_targets.ts @@ -35,7 +35,7 @@ export async function cleanWriteTargets({ wait_for_completion: false, }); - const task = response.body.task; + const task = response.task; if (task) { await new Promise((resolve, reject) => { @@ -45,13 +45,13 @@ export async function cleanWriteTargets({ }); logger.debug( - `Polled for task:\n${JSON.stringify(taskResponse.body, ['completed', 'error'], 2)}` + `Polled for task:\n${JSON.stringify(taskResponse, ['completed', 'error'], 2)}` ); - if (taskResponse.body.completed) { + if (taskResponse.completed) { resolve(); - } else if (taskResponse.body.error) { - reject(taskResponse.body.error); + } else if (taskResponse.error) { + reject(taskResponse.error); } else { setTimeout(pollForTaskCompletion, 2500); } diff --git a/packages/elastic-apm-generator/src/scripts/utils/get_common_resources.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_resources.ts similarity index 82% rename from packages/elastic-apm-generator/src/scripts/utils/get_common_resources.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/get_common_resources.ts index 1288c1390e92c..3b51ac6c0c0a7 100644 --- a/packages/elastic-apm-generator/src/scripts/utils/get_common_resources.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_resources.ts @@ -16,21 +16,21 @@ export async function getCommonResources({ file, interval, bucketSize, - workers, target, - clean, logLevel, }: { - file: unknown; - interval: unknown; - bucketSize: unknown; - workers: unknown; - target: unknown; - clean: boolean; - logLevel: unknown; + file: string; + interval: string; + bucketSize: string; + target: string; + logLevel: string; }) { let parsedLogLevel = LogLevel.info; switch (logLevel) { + case 'trace': + parsedLogLevel = LogLevel.trace; + break; + case 'info': parsedLogLevel = LogLevel.info; break; @@ -39,8 +39,8 @@ export async function getCommonResources({ parsedLogLevel = LogLevel.debug; break; - case 'quiet': - parsedLogLevel = LogLevel.quiet; + case 'error': + parsedLogLevel = LogLevel.error; break; } @@ -58,7 +58,7 @@ export async function getCommonResources({ } const client = new Client({ - node: String(target), + node: target, }); const [scenario, writeTargets] = await Promise.all([ @@ -73,8 +73,6 @@ export async function getCommonResources({ client, intervalInMs, bucketSizeInMs, - workers: Number(workers), - target: String(target), - clean, + logLevel: parsedLogLevel, }; } diff --git a/packages/elastic-apm-generator/src/scripts/utils/get_scenario.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/get_scenario.ts similarity index 100% rename from packages/elastic-apm-generator/src/scripts/utils/get_scenario.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/get_scenario.ts diff --git a/packages/elastic-apm-generator/src/scripts/utils/get_write_targets.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/get_write_targets.ts similarity index 82% rename from packages/elastic-apm-generator/src/scripts/utils/get_write_targets.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/get_write_targets.ts index 3640e4efaf796..fbe11d295e099 100644 --- a/packages/elastic-apm-generator/src/scripts/utils/get_write_targets.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/get_write_targets.ts @@ -24,21 +24,21 @@ export async function getWriteTargets({ ]); function getDataStreamName(filter: string) { - return datastreamsResponse.body.data_streams.find((stream) => stream.name.includes(filter)) - ?.name; + return datastreamsResponse.data_streams.find((stream) => stream.name.includes(filter))?.name; } function getAlias(filter: string) { - return Object.keys(indicesResponse.body) + return Object.keys(indicesResponse) .map((key) => { return { key, - writeIndexAlias: Object.entries(indicesResponse.body[key].aliases).find( + writeIndexAlias: Object.entries(indicesResponse[key].aliases).find( ([_, alias]) => alias.is_write_index )?.[0], }; }) - .find(({ key }) => key.includes(filter))?.writeIndexAlias!; + .find(({ key, writeIndexAlias }) => writeIndexAlias && key.includes(filter)) + ?.writeIndexAlias!; } const targets = { diff --git a/packages/elastic-apm-generator/src/scripts/utils/interval_to_ms.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/interval_to_ms.ts similarity index 100% rename from packages/elastic-apm-generator/src/scripts/utils/interval_to_ms.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/interval_to_ms.ts diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/logger.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/logger.ts new file mode 100644 index 0000000000000..4afdda74105cf --- /dev/null +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/logger.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPromise } from 'util/types'; + +export enum LogLevel { + trace = 0, + debug = 1, + info = 2, + error = 3, +} + +function getTimeString() { + return `[${new Date().toLocaleTimeString()}]`; +} + +export function createLogger(logLevel: LogLevel) { + function logPerf(name: string, start: bigint) { + // eslint-disable-next-line no-console + console.debug( + getTimeString(), + `${name}: ${Number(process.hrtime.bigint() - start) / 1000000}ms` + ); + } + return { + perf: (name: string, cb: () => T): T => { + if (logLevel <= LogLevel.trace) { + const start = process.hrtime.bigint(); + const val = cb(); + if (isPromise(val)) { + val.then(() => { + logPerf(name, start); + }); + } else { + logPerf(name, start); + } + return val; + } + return cb(); + }, + debug: (...args: any[]) => { + if (logLevel <= LogLevel.debug) { + // eslint-disable-next-line no-console + console.debug(getTimeString(), ...args); + } + }, + info: (...args: any[]) => { + if (logLevel <= LogLevel.info) { + // eslint-disable-next-line no-console + console.log(getTimeString(), ...args); + } + }, + error: (...args: any[]) => { + if (logLevel <= LogLevel.error) { + // eslint-disable-next-line no-console + console.log(getTimeString(), ...args); + } + }, + }; +} + +export type Logger = ReturnType; diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts new file mode 100644 index 0000000000000..e940896fb3687 --- /dev/null +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { Client } from '@elastic/elasticsearch'; +import pLimit from 'p-limit'; +import Path from 'path'; +import { Worker } from 'worker_threads'; +import { ElasticsearchOutputWriteTargets } from '../../lib/output/to_elasticsearch_output'; +import { Logger, LogLevel } from './logger'; + +export async function startHistoricalDataUpload({ + from, + to, + bucketSizeInMs, + workers, + clientWorkers, + batchSize, + writeTargets, + logLevel, + logger, + target, + file, +}: { + from: number; + to: number; + bucketSizeInMs: number; + client: Client; + workers: number; + clientWorkers: number; + batchSize: number; + writeTargets: ElasticsearchOutputWriteTargets; + logger: Logger; + logLevel: LogLevel; + target: string; + file: string; +}) { + let requestedUntil: number = from; + + function processNextBatch() { + const bucketFrom = requestedUntil; + const bucketTo = Math.min(to, bucketFrom + bucketSizeInMs); + + if (bucketFrom === bucketTo) { + return; + } + + requestedUntil = bucketTo; + + logger.info( + `Starting worker for ${new Date(bucketFrom).toISOString()} to ${new Date( + bucketTo + ).toISOString()}` + ); + + const worker = new Worker(Path.join(__dirname, './upload_next_batch.js'), { + workerData: { + bucketFrom, + bucketTo, + logLevel, + writeTargets, + target, + file, + clientWorkers, + batchSize, + }, + }); + + logger.perf('created_worker', () => { + return new Promise((resolve, reject) => { + worker.on('online', () => { + resolve(); + }); + }); + }); + + logger.perf('completed_worker', () => { + return new Promise((resolve, reject) => { + worker.on('exit', () => { + resolve(); + }); + }); + }); + + return new Promise((resolve, reject) => { + worker.on('error', (err) => { + reject(err); + }); + + worker.on('exit', (code) => { + if (code !== 0) { + reject(new Error(`Worker stopped: exit code ${code}`)); + return; + } + logger.debug('Worker completed'); + resolve(); + }); + }); + } + + const numBatches = Math.ceil((to - from) / bucketSizeInMs); + + const limiter = pLimit(workers); + + return Promise.all(new Array(numBatches).fill(undefined).map((_) => limiter(processNextBatch))); +} diff --git a/packages/elastic-apm-generator/src/scripts/utils/start_live_data_upload.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts similarity index 94% rename from packages/elastic-apm-generator/src/scripts/utils/start_live_data_upload.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts index bf330732f343e..0032df1d700e9 100644 --- a/packages/elastic-apm-generator/src/scripts/utils/start_live_data_upload.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts @@ -18,7 +18,8 @@ export function startLiveDataUpload({ start, bucketSizeInMs, intervalInMs, - workers, + clientWorkers, + batchSize, writeTargets, scenario, client, @@ -27,7 +28,8 @@ export function startLiveDataUpload({ start: number; bucketSizeInMs: number; intervalInMs: number; - workers: number; + clientWorkers: number; + batchSize: number; writeTargets: ElasticsearchOutputWriteTargets; scenario: Scenario; client: Client; @@ -63,7 +65,8 @@ export function startLiveDataUpload({ uploadEvents({ events: eventsToUpload, client, - workers, + clientWorkers, + batchSize, writeTargets, logger, }); diff --git a/packages/elastic-apm-generator/src/scripts/utils/upload_events.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts similarity index 69% rename from packages/elastic-apm-generator/src/scripts/utils/upload_events.ts rename to packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts index 89cf4d4602177..72258ec2815a8 100644 --- a/packages/elastic-apm-generator/src/scripts/utils/upload_events.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts @@ -19,20 +19,24 @@ import { Logger } from './logger'; export function uploadEvents({ events, client, - workers, + clientWorkers, + batchSize, writeTargets, logger, }: { events: Fields[]; client: Client; - workers: number; + clientWorkers: number; + batchSize: number; writeTargets: ElasticsearchOutputWriteTargets; logger: Logger; }) { - const esDocuments = toElasticsearchOutput({ events, writeTargets }); - const fn = pLimit(workers); + const esDocuments = logger.perf('to_elasticsearch_output', () => { + return toElasticsearchOutput({ events, writeTargets }); + }); + const fn = pLimit(clientWorkers); - const batches = chunk(esDocuments, 5000); + const batches = chunk(esDocuments, batchSize); logger.debug(`Uploading ${esDocuments.length} in ${batches.length} batches`); @@ -41,24 +45,26 @@ export function uploadEvents({ return Promise.all( batches.map((batch) => fn(() => { - return client.bulk({ - require_alias: true, - body: batch.flatMap((doc) => { - return [{ index: { _index: doc._index } }, doc._source]; - }), - }); + return logger.perf('bulk_upload', () => + client.bulk({ + require_alias: true, + refresh: false, + body: batch.flatMap((doc) => { + return [{ index: { _index: doc._index } }, doc._source]; + }), + }) + ); }) ) ) .then((results) => { const errors = results - .flatMap((result) => result.body.items) + .flatMap((result) => result.items) .filter((item) => !!item.index?.error) .map((item) => item.index?.error); if (errors.length) { - // eslint-disable-next-line no-console - console.error(inspect(errors.slice(0, 10), { depth: null })); + logger.error(inspect(errors.slice(0, 10), { depth: null })); throw new Error('Failed to upload some items'); } diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.js b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.js new file mode 100644 index 0000000000000..86c7b67c24ff7 --- /dev/null +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.js @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* eslint-disable @typescript-eslint/no-var-requires*/ +require('@babel/register')({ + extensions: ['.ts', '.js'], + presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], +}); + +require('./upload_next_batch.ts'); diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts new file mode 100644 index 0000000000000..1e0280382e4db --- /dev/null +++ b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// add this to workerExample.js file. +import { Client } from '@elastic/elasticsearch'; +import { workerData } from 'worker_threads'; +import { ElasticsearchOutputWriteTargets } from '../../lib/output/to_elasticsearch_output'; +import { getScenario } from './get_scenario'; +import { createLogger, LogLevel } from './logger'; +import { uploadEvents } from './upload_events'; + +const { bucketFrom, bucketTo, file, logLevel, target, writeTargets, clientWorkers, batchSize } = + workerData as { + bucketFrom: number; + bucketTo: number; + file: string; + logLevel: LogLevel; + target: string; + writeTargets: ElasticsearchOutputWriteTargets; + clientWorkers: number; + batchSize: number; + }; + +async function uploadNextBatch() { + if (bucketFrom === bucketTo) { + return; + } + + const logger = createLogger(logLevel); + const client = new Client({ + node: target, + }); + + const scenario = await logger.perf('get_scenario', () => getScenario({ file, logger })); + + const events = logger.perf('execute_scenario', () => + scenario({ from: bucketFrom, to: bucketTo }) + ); + + return uploadEvents({ + events, + client, + clientWorkers, + batchSize, + writeTargets, + logger, + }); +} + +uploadNextBatch() + .then(() => { + process.exit(0); + }) + .catch(() => { + process.exit(1); + }); diff --git a/packages/elastic-apm-generator/src/test/scenarios/01_simple_trace.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts similarity index 92% rename from packages/elastic-apm-generator/src/test/scenarios/01_simple_trace.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts index 866a9745befc3..fc20202e210ff 100644 --- a/packages/elastic-apm-generator/src/test/scenarios/01_simple_trace.test.ts +++ b/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts @@ -75,9 +75,9 @@ describe('simple trace', () => { 'service.environment': 'production', 'service.name': 'opbeans-java', 'service.node.name': 'instance-1', - 'trace.id': 'f6eb2f1cbba2597e89d2a63771c4344d', + 'trace.id': '00000000000000000000000000000241', 'transaction.duration.us': 1000000, - 'transaction.id': 'e9ece67cbacb52bf', + 'transaction.id': '0000000000000240', 'transaction.name': 'GET /api/product/list', 'transaction.type': 'request', 'transaction.sampled': true, @@ -92,19 +92,19 @@ describe('simple trace', () => { 'agent.name': 'java', 'container.id': 'instance-1', 'event.outcome': 'success', - 'parent.id': 'e7433020f2745625', + 'parent.id': '0000000000000300', 'processor.event': 'span', 'processor.name': 'transaction', 'service.environment': 'production', 'service.name': 'opbeans-java', 'service.node.name': 'instance-1', 'span.duration.us': 900000, - 'span.id': '21a776b44b9853dd', + 'span.id': '0000000000000302', 'span.name': 'GET apm-*/_search', 'span.subtype': 'elasticsearch', 'span.type': 'db', - 'trace.id': '048a0647263853abb94649ec0b92bdb4', - 'transaction.id': 'e7433020f2745625', + 'trace.id': '00000000000000000000000000000301', + 'transaction.id': '0000000000000300', }); }); }); diff --git a/packages/elastic-apm-generator/src/test/scenarios/02_transaction_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts similarity index 100% rename from packages/elastic-apm-generator/src/test/scenarios/02_transaction_metrics.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts diff --git a/packages/elastic-apm-generator/src/test/scenarios/03_span_destination_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts similarity index 100% rename from packages/elastic-apm-generator/src/test/scenarios/03_span_destination_metrics.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts diff --git a/packages/elastic-apm-generator/src/test/scenarios/04_breakdown_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts similarity index 100% rename from packages/elastic-apm-generator/src/test/scenarios/04_breakdown_metrics.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts diff --git a/packages/elastic-apm-generator/src/test/scenarios/05_transactions_with_errors.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts similarity index 98% rename from packages/elastic-apm-generator/src/test/scenarios/05_transactions_with_errors.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts index 289fdfa6cf565..63fdb691e8e5c 100644 --- a/packages/elastic-apm-generator/src/test/scenarios/05_transactions_with_errors.test.ts +++ b/packages/elastic-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts @@ -61,6 +61,6 @@ describe('transactions with errors', () => { .serialize(); expect(error['error.grouping_name']).toEqual('test error'); - expect(error['error.grouping_key']).toMatchInlineSnapshot(`"8b96fa10a7f85a5d960198627bf50840"`); + expect(error['error.grouping_key']).toMatchInlineSnapshot(`"0000000000000000000000test error"`); }); }); diff --git a/packages/elastic-apm-generator/src/test/scenarios/06_application_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/06_application_metrics.test.ts similarity index 100% rename from packages/elastic-apm-generator/src/test/scenarios/06_application_metrics.test.ts rename to packages/elastic-apm-synthtrace/src/test/scenarios/06_application_metrics.test.ts diff --git a/packages/elastic-apm-generator/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap b/packages/elastic-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap similarity index 78% rename from packages/elastic-apm-generator/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap rename to packages/elastic-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap index 00a55cb87b125..76a76d41ec81d 100644 --- a/packages/elastic-apm-generator/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap +++ b/packages/elastic-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap @@ -12,9 +12,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "b1c6c04a9ac15b138f716d383cc85e6b", + "trace.id": "00000000000000000000000000000001", "transaction.duration.us": 1000000, - "transaction.id": "36c16f18e75058f8", + "transaction.id": "0000000000000000", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -24,19 +24,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "36c16f18e75058f8", + "parent.id": "0000000000000000", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "fe778a305e6d57dd", + "span.id": "0000000000000002", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "b1c6c04a9ac15b138f716d383cc85e6b", - "transaction.id": "36c16f18e75058f8", + "trace.id": "00000000000000000000000000000001", + "transaction.id": "0000000000000000", }, Object { "@timestamp": 1609459260000, @@ -48,9 +48,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "53c6c37bd4c85f4fbc880cd80704a9cd", + "trace.id": "00000000000000000000000000000005", "transaction.duration.us": 1000000, - "transaction.id": "65ce74106eb050be", + "transaction.id": "0000000000000004", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -60,19 +60,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "65ce74106eb050be", + "parent.id": "0000000000000004", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "ad8c5e249a8658ec", + "span.id": "0000000000000006", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "53c6c37bd4c85f4fbc880cd80704a9cd", - "transaction.id": "65ce74106eb050be", + "trace.id": "00000000000000000000000000000005", + "transaction.id": "0000000000000004", }, Object { "@timestamp": 1609459320000, @@ -84,9 +84,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "5eebf2e8d8cc5f85be8c573a1b501c7d", + "trace.id": "00000000000000000000000000000009", "transaction.duration.us": 1000000, - "transaction.id": "91fa709d90625fff", + "transaction.id": "0000000000000008", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -96,19 +96,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "91fa709d90625fff", + "parent.id": "0000000000000008", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "228b569c530c52ac", + "span.id": "0000000000000010", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "5eebf2e8d8cc5f85be8c573a1b501c7d", - "transaction.id": "91fa709d90625fff", + "trace.id": "00000000000000000000000000000009", + "transaction.id": "0000000000000008", }, Object { "@timestamp": 1609459380000, @@ -120,9 +120,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "6e8da4beb752589a86d53287c9d902de", + "trace.id": "00000000000000000000000000000013", "transaction.duration.us": 1000000, - "transaction.id": "6c500d1d19835e68", + "transaction.id": "0000000000000012", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -132,19 +132,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "6c500d1d19835e68", + "parent.id": "0000000000000012", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "5eb13f140bde5334", + "span.id": "0000000000000014", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "6e8da4beb752589a86d53287c9d902de", - "transaction.id": "6c500d1d19835e68", + "trace.id": "00000000000000000000000000000013", + "transaction.id": "0000000000000012", }, Object { "@timestamp": 1609459440000, @@ -156,9 +156,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "0aaa92bd91df543c8fd10b662051d9e8", + "trace.id": "00000000000000000000000000000017", "transaction.duration.us": 1000000, - "transaction.id": "1b3246cc83595869", + "transaction.id": "0000000000000016", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -168,19 +168,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "1b3246cc83595869", + "parent.id": "0000000000000016", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "582221c79fd75a76", + "span.id": "0000000000000018", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "0aaa92bd91df543c8fd10b662051d9e8", - "transaction.id": "1b3246cc83595869", + "trace.id": "00000000000000000000000000000017", + "transaction.id": "0000000000000016", }, Object { "@timestamp": 1609459500000, @@ -192,9 +192,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "26be5f0e2c16576ebf5f39c505eb1ff2", + "trace.id": "00000000000000000000000000000021", "transaction.duration.us": 1000000, - "transaction.id": "12b49e3c83fe58d5", + "transaction.id": "0000000000000020", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -204,19 +204,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "12b49e3c83fe58d5", + "parent.id": "0000000000000020", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "526d186996835c09", + "span.id": "0000000000000022", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "26be5f0e2c16576ebf5f39c505eb1ff2", - "transaction.id": "12b49e3c83fe58d5", + "trace.id": "00000000000000000000000000000021", + "transaction.id": "0000000000000020", }, Object { "@timestamp": 1609459560000, @@ -228,9 +228,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "c17c414c0b51564ca30e2ad839393180", + "trace.id": "00000000000000000000000000000025", "transaction.duration.us": 1000000, - "transaction.id": "d9272009dd4354a1", + "transaction.id": "0000000000000024", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -240,19 +240,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "d9272009dd4354a1", + "parent.id": "0000000000000024", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "7582541fcbfc5dc6", + "span.id": "0000000000000026", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "c17c414c0b51564ca30e2ad839393180", - "transaction.id": "d9272009dd4354a1", + "trace.id": "00000000000000000000000000000025", + "transaction.id": "0000000000000024", }, Object { "@timestamp": 1609459620000, @@ -264,9 +264,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "0280b1ffaae75e7ab097c0b52c3b3e6a", + "trace.id": "00000000000000000000000000000029", "transaction.duration.us": 1000000, - "transaction.id": "bc52ca08063c505b", + "transaction.id": "0000000000000028", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -276,19 +276,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "bc52ca08063c505b", + "parent.id": "0000000000000028", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "37ab978487935abb", + "span.id": "0000000000000030", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "0280b1ffaae75e7ab097c0b52c3b3e6a", - "transaction.id": "bc52ca08063c505b", + "trace.id": "00000000000000000000000000000029", + "transaction.id": "0000000000000028", }, Object { "@timestamp": 1609459680000, @@ -300,9 +300,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "6fb5191297fb59cebdb6a0196e273676", + "trace.id": "00000000000000000000000000000033", "transaction.duration.us": 1000000, - "transaction.id": "186858dd88b75d59", + "transaction.id": "0000000000000032", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -312,19 +312,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "186858dd88b75d59", + "parent.id": "0000000000000032", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "5ab56f27d0ae569b", + "span.id": "0000000000000034", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "6fb5191297fb59cebdb6a0196e273676", - "transaction.id": "186858dd88b75d59", + "trace.id": "00000000000000000000000000000033", + "transaction.id": "0000000000000032", }, Object { "@timestamp": 1609459740000, @@ -336,9 +336,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "77b5ffe303ae59b49f9b0e5d5270c16a", + "trace.id": "00000000000000000000000000000037", "transaction.duration.us": 1000000, - "transaction.id": "0d5f44d48189546c", + "transaction.id": "0000000000000036", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -348,19 +348,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "0d5f44d48189546c", + "parent.id": "0000000000000036", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "80e94b0847cd5104", + "span.id": "0000000000000038", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "77b5ffe303ae59b49f9b0e5d5270c16a", - "transaction.id": "0d5f44d48189546c", + "trace.id": "00000000000000000000000000000037", + "transaction.id": "0000000000000036", }, Object { "@timestamp": 1609459800000, @@ -372,9 +372,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "51c6b70db4dc5cf89b690de45c0c7b71", + "trace.id": "00000000000000000000000000000041", "transaction.duration.us": 1000000, - "transaction.id": "7483e0606e435c83", + "transaction.id": "0000000000000040", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -384,19 +384,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "7483e0606e435c83", + "parent.id": "0000000000000040", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "2e99d193e0f954c1", + "span.id": "0000000000000042", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "51c6b70db4dc5cf89b690de45c0c7b71", - "transaction.id": "7483e0606e435c83", + "trace.id": "00000000000000000000000000000041", + "transaction.id": "0000000000000040", }, Object { "@timestamp": 1609459860000, @@ -408,9 +408,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "5d91a6cde6015897935e413bc500f211", + "trace.id": "00000000000000000000000000000045", "transaction.duration.us": 1000000, - "transaction.id": "f142c4cbc7f3568e", + "transaction.id": "0000000000000044", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -420,19 +420,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "f142c4cbc7f3568e", + "parent.id": "0000000000000044", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "1fc52f16e2f551ea", + "span.id": "0000000000000046", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "5d91a6cde6015897935e413bc500f211", - "transaction.id": "f142c4cbc7f3568e", + "trace.id": "00000000000000000000000000000045", + "transaction.id": "0000000000000044", }, Object { "@timestamp": 1609459920000, @@ -444,9 +444,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "c097c19d884d52579bb11a601b8a98b3", + "trace.id": "00000000000000000000000000000049", "transaction.duration.us": 1000000, - "transaction.id": "2e3a47fa2d905519", + "transaction.id": "0000000000000048", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -456,19 +456,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "2e3a47fa2d905519", + "parent.id": "0000000000000048", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "7c7828c850685337", + "span.id": "0000000000000050", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "c097c19d884d52579bb11a601b8a98b3", - "transaction.id": "2e3a47fa2d905519", + "trace.id": "00000000000000000000000000000049", + "transaction.id": "0000000000000048", }, Object { "@timestamp": 1609459980000, @@ -480,9 +480,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "4591e57f4d7f5986bdd7892561224e0f", + "trace.id": "00000000000000000000000000000053", "transaction.duration.us": 1000000, - "transaction.id": "de5eaa1e47dc56b1", + "transaction.id": "0000000000000052", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -492,19 +492,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "de5eaa1e47dc56b1", + "parent.id": "0000000000000052", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "8f62257f4a41546a", + "span.id": "0000000000000054", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "4591e57f4d7f5986bdd7892561224e0f", - "transaction.id": "de5eaa1e47dc56b1", + "trace.id": "00000000000000000000000000000053", + "transaction.id": "0000000000000052", }, Object { "@timestamp": 1609460040000, @@ -516,9 +516,9 @@ Array [ "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", - "trace.id": "85ee8e618433577b9316a1e14961aa89", + "trace.id": "00000000000000000000000000000057", "transaction.duration.us": 1000000, - "transaction.id": "af7eac7ae61e576a", + "transaction.id": "0000000000000056", "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -528,19 +528,19 @@ Array [ "agent.name": "java", "container.id": "instance-1", "event.outcome": "success", - "parent.id": "af7eac7ae61e576a", + "parent.id": "0000000000000056", "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "cc88b4cd921e590e", + "span.id": "0000000000000058", "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", - "trace.id": "85ee8e618433577b9316a1e14961aa89", - "transaction.id": "af7eac7ae61e576a", + "trace.id": "00000000000000000000000000000057", + "transaction.id": "0000000000000056", }, ] `; diff --git a/packages/elastic-apm-generator/src/test/to_elasticsearch_output.test.ts b/packages/elastic-apm-synthtrace/src/test/to_elasticsearch_output.test.ts similarity index 63% rename from packages/elastic-apm-generator/src/test/to_elasticsearch_output.test.ts rename to packages/elastic-apm-synthtrace/src/test/to_elasticsearch_output.test.ts index d15ea89083112..02d17f6b561ae 100644 --- a/packages/elastic-apm-generator/src/test/to_elasticsearch_output.test.ts +++ b/packages/elastic-apm-synthtrace/src/test/to_elasticsearch_output.test.ts @@ -24,6 +24,7 @@ describe('output to elasticsearch', () => { '@timestamp': new Date('2020-12-31T23:00:00.000Z').getTime(), 'processor.event': 'transaction', 'processor.name': 'transaction', + 'service.node.name': 'instance-a', }; }); @@ -41,4 +42,33 @@ describe('output to elasticsearch', () => { name: 'transaction', }); }); + + it('formats all fields consistently', () => { + const doc = toElasticsearchOutput({ events: [event], writeTargets })[0] as any; + + expect(doc._source).toMatchInlineSnapshot(` + Object { + "@timestamp": "2020-12-31T23:00:00.000Z", + "ecs": Object { + "version": "1.4", + }, + "observer": Object { + "version": "7.16.0", + "version_major": 7, + }, + "processor": Object { + "event": "transaction", + "name": "transaction", + }, + "service": Object { + "node": Object { + "name": "instance-a", + }, + }, + "timestamp": Object { + "us": 1609455600000000, + }, + } + `); + }); }); diff --git a/packages/elastic-apm-synthtrace/tsconfig.json b/packages/elastic-apm-synthtrace/tsconfig.json new file mode 100644 index 0000000000000..6ae9c20b4387b --- /dev/null +++ b/packages/elastic-apm-synthtrace/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "./src", + "sourceMap": true, + "sourceRoot": "../../../../packages/elastic-apm-synthtrace/src", + "types": ["node", "jest"] + }, + "include": ["./src/**/*.ts"] +} diff --git a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts index 24a1de10b2b1d..96b5b5f8e98e5 100644 --- a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts +++ b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; @@ -17,7 +17,7 @@ export async function emptyKibanaIndexAction({ log, kbnClient, }: { - client: KibanaClient; + client: Client; log: ToolingLog; kbnClient: KbnClient; }) { diff --git a/packages/kbn-es-archiver/src/actions/load.ts b/packages/kbn-es-archiver/src/actions/load.ts index 673fa7e7d96c8..619c946f0c988 100644 --- a/packages/kbn-es-archiver/src/actions/load.ts +++ b/packages/kbn-es-archiver/src/actions/load.ts @@ -11,7 +11,7 @@ import { createReadStream } from 'fs'; import { Readable } from 'stream'; import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { createPromiseFromStreams, concatStreamProviders } from '@kbn/utils'; import { ES_CLIENT_HEADERS } from '../client_headers'; @@ -47,7 +47,7 @@ export async function loadAction({ inputDir: string; skipExisting: boolean; useCreate: boolean; - client: KibanaClient; + client: Client; log: ToolingLog; kbnClient: KbnClient; }) { diff --git a/packages/kbn-es-archiver/src/actions/save.ts b/packages/kbn-es-archiver/src/actions/save.ts index da0966920de24..07ed2b206c1dd 100644 --- a/packages/kbn-es-archiver/src/actions/save.ts +++ b/packages/kbn-es-archiver/src/actions/save.ts @@ -9,7 +9,7 @@ import { resolve, relative } from 'path'; import { createWriteStream, mkdirSync } from 'fs'; import { Readable, Writable } from 'stream'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import { createListStream, createPromiseFromStreams } from '@kbn/utils'; @@ -31,7 +31,7 @@ export async function saveAction({ }: { outputDir: string; indices: string | string[]; - client: KibanaClient; + client: Client; log: ToolingLog; raw: boolean; query?: Record; diff --git a/packages/kbn-es-archiver/src/actions/unload.ts b/packages/kbn-es-archiver/src/actions/unload.ts index 98bae36095b88..1c5f4cd5d7d03 100644 --- a/packages/kbn-es-archiver/src/actions/unload.ts +++ b/packages/kbn-es-archiver/src/actions/unload.ts @@ -9,7 +9,7 @@ import { resolve, relative } from 'path'; import { createReadStream } from 'fs'; import { Readable, Writable } from 'stream'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; import { createPromiseFromStreams } from '@kbn/utils'; @@ -31,7 +31,7 @@ export async function unloadAction({ kbnClient, }: { inputDir: string; - client: KibanaClient; + client: Client; log: ToolingLog; kbnClient: KbnClient; }) { diff --git a/packages/kbn-es-archiver/src/cli.ts b/packages/kbn-es-archiver/src/cli.ts index 8e4a879282765..db54a3bade74b 100644 --- a/packages/kbn-es-archiver/src/cli.ts +++ b/packages/kbn-es-archiver/src/cli.ts @@ -19,7 +19,7 @@ import Fs from 'fs'; import { RunWithCommands, createFlagError, CA_CERT_PATH } from '@kbn/dev-utils'; import { readConfigFile, KbnClient } from '@kbn/test'; -import { Client } from '@elastic/elasticsearch'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; import { EsArchiver } from './es_archiver'; @@ -106,7 +106,8 @@ export function runCli() { const client = new Client({ node: esUrl, - ssl: esCa ? { ca: esCa } : undefined, + tls: esCa ? { ca: esCa } : undefined, + Connection: HttpConnection, }); addCleanupTask(() => client.close()); diff --git a/packages/kbn-es-archiver/src/es_archiver.ts b/packages/kbn-es-archiver/src/es_archiver.ts index 06a56b79e3012..ed27bc0afcf34 100644 --- a/packages/kbn-es-archiver/src/es_archiver.ts +++ b/packages/kbn-es-archiver/src/es_archiver.ts @@ -9,7 +9,7 @@ import Fs from 'fs'; import Path from 'path'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; @@ -23,14 +23,14 @@ import { } from './actions'; interface Options { - client: KibanaClient; + client: Client; baseDir?: string; log: ToolingLog; kbnClient: KbnClient; } export class EsArchiver { - private readonly client: KibanaClient; + private readonly client: Client; private readonly baseDir: string; private readonly log: ToolingLog; private readonly kbnClient: KbnClient; diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts index da7ed4c81b666..2902812f51493 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts @@ -99,10 +99,8 @@ it('transforms each input index to a stream of docs using scrollSearch helper', Array [ Object { "_source": "true", - "body": Object { - "query": undefined, - }, "index": "bar", + "query": undefined, "rest_total_hits_as_int": true, "scroll": "1m", "size": 1000, @@ -116,10 +114,8 @@ it('transforms each input index to a stream of docs using scrollSearch helper', Array [ Object { "_source": "true", - "body": Object { - "query": undefined, - }, "index": "foo", + "query": undefined, "rest_total_hits_as_int": true, "scroll": "1m", "size": 1000, diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts index 88e167b3705cb..a0636d6a3f76a 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts @@ -7,7 +7,7 @@ */ import { Transform } from 'stream'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { Stats } from '../stats'; import { Progress } from '../progress'; import { ES_CLIENT_HEADERS } from '../../client_headers'; @@ -21,7 +21,7 @@ export function createGenerateDocRecordsStream({ progress, query, }: { - client: KibanaClient; + client: Client; stats: Stats; progress: Progress; query?: Record; @@ -37,9 +37,7 @@ export function createGenerateDocRecordsStream({ scroll: SCROLL_TIMEOUT, size: SCROLL_SIZE, _source: 'true', - body: { - query, - }, + query, rest_total_hits_as_int: true, }, { diff --git a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts index 028ff16c9afb2..749bfd0872353 100644 --- a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import AggregateError from 'aggregate-error'; import { Writable } from 'stream'; import { Stats } from '../stats'; @@ -14,7 +14,7 @@ import { Progress } from '../progress'; import { ES_CLIENT_HEADERS } from '../../client_headers'; export function createIndexDocRecordsStream( - client: KibanaClient, + client: Client, stats: Stats, progress: Progress, useCreate: boolean = false diff --git a/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts b/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts index 7dde4075dc3f2..ded56ddfdf0de 100644 --- a/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts +++ b/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import sinon from 'sinon'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../../stats'; @@ -67,7 +67,7 @@ const createEsClientError = (errorType: string) => { const indexAlias = (aliases: Record, index: string) => Object.keys(aliases).find((k) => aliases[k] === index); -type StubClient = KibanaClient; +type StubClient = Client; export const createStubClient = ( existingIndices: string[] = [], diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts index 28c8ccd1c28a8..3a8180b724e07 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts @@ -71,6 +71,7 @@ describe('esArchiver: createCreateIndexStream()', () => { "ignore": Array [ 404, ], + "meta": true, }, ], ] diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index fba3df24e896f..50d13fc728c79 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -9,8 +9,8 @@ import { Transform, Readable } from 'stream'; import { inspect } from 'util'; -import { estypes } from '@elastic/elasticsearch'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; @@ -31,7 +31,7 @@ export function createCreateIndexStream({ skipExisting = false, log, }: { - client: KibanaClient; + client: Client; stats: Stats; skipExisting?: boolean; log: ToolingLog; diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts index d3d6f85d7a360..3bba96d32ba95 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; import { ES_CLIENT_HEADERS } from '../../client_headers'; @@ -15,7 +15,7 @@ import { ES_CLIENT_HEADERS } from '../../client_headers'; const PENDING_SNAPSHOT_STATUSES = ['INIT', 'STARTED', 'WAITING']; export async function deleteIndex(options: { - client: KibanaClient; + client: Client; stats: Stats; index: string | string[]; log: ToolingLog; @@ -32,6 +32,7 @@ export async function deleteIndex(options: { { ignore: [404], headers: ES_CLIENT_HEADERS, + meta: true, } ); @@ -84,15 +85,13 @@ export function isDeleteWhileSnapshotInProgressError(error: any) { * snapshotting this index to complete. */ export async function waitForSnapshotCompletion( - client: KibanaClient, + client: Client, index: string | string[], log: ToolingLog ) { const isSnapshotPending = async (repository: string, snapshot: string) => { const { - body: { - snapshots: [status], - }, + snapshots: [status], } = await client.snapshot.status( { repository, @@ -108,9 +107,7 @@ export async function waitForSnapshotCompletion( }; const getInProgressSnapshots = async (repository: string) => { - const { - body: { snapshots: inProgressSnapshots }, - } = await client.snapshot.get( + const { snapshots: inProgressSnapshots } = await client.snapshot.get( { repository, snapshot: '_current', @@ -123,7 +120,7 @@ export async function waitForSnapshotCompletion( return inProgressSnapshots; }; - const { body: repositoryMap } = await client.snapshot.getRepository({} as any); + const repositoryMap = await client.snapshot.getRepository({}); for (const repository of Object.keys(repositoryMap)) { const allInProgress = await getInProgressSnapshots(repository); const found = allInProgress?.find((s: any) => s.indices.includes(index)); diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts index 7765419bb9d15..e7763ca251e6f 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts @@ -7,14 +7,14 @@ */ import { Transform } from 'stream'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; import { cleanKibanaIndices } from './kibana_index'; -export function createDeleteIndexStream(client: KibanaClient, stats: Stats, log: ToolingLog) { +export function createDeleteIndexStream(client: Client, stats: Stats, log: ToolingLog) { return new Transform({ readableObjectMode: true, writableObjectMode: true, diff --git a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts index 6619f1b3a601e..d647a4fe5f501 100644 --- a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ +import type { Client } from '@elastic/elasticsearch'; import { Transform } from 'stream'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; import { Stats } from '../stats'; import { ES_CLIENT_HEADERS } from '../../client_headers'; -export function createGenerateIndexRecordsStream(client: KibanaClient, stats: Stats) { +export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { return new Transform({ writableObjectMode: true, readableObjectMode: true, @@ -37,9 +37,10 @@ export function createGenerateIndexRecordsStream(client: KibanaClient, stats: St }, { headers: ES_CLIENT_HEADERS, + meta: true, } ) - ).body as Record; + ).body; for (const [index, { settings, mappings }] of Object.entries(resp)) { const { @@ -50,6 +51,7 @@ export function createGenerateIndexRecordsStream(client: KibanaClient, stats: St { index }, { headers: ES_CLIENT_HEADERS, + meta: true, } ); diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index 635e432468846..069db636c596b 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -8,7 +8,7 @@ import { inspect } from 'util'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; import { Stats } from '../stats'; @@ -23,7 +23,7 @@ export async function deleteKibanaIndices({ stats, log, }: { - client: KibanaClient; + client: Client; stats: Stats; log: ToolingLog; }) { @@ -35,7 +35,7 @@ export async function deleteKibanaIndices({ await client.indices.putSettings( { index: indexNames, - body: { settings: { blocks: { read_only: false } } }, + body: { blocks: { read_only: false } }, }, { headers: ES_CLIENT_HEADERS, @@ -75,7 +75,7 @@ function isKibanaIndex(index?: string): index is string { ); } -async function fetchKibanaIndices(client: KibanaClient) { +async function fetchKibanaIndices(client: Client) { const resp = await client.cat.indices( { index: '.kibana*', format: 'json' }, { @@ -83,11 +83,11 @@ async function fetchKibanaIndices(client: KibanaClient) { } ); - if (!Array.isArray(resp.body)) { - throw new Error(`expected response to be an array ${inspect(resp.body)}`); + if (!Array.isArray(resp)) { + throw new Error(`expected response to be an array ${inspect(resp)}`); } - return resp.body.map((x: { index?: string }) => x.index).filter(isKibanaIndex); + return resp.map((x: { index?: string }) => x.index).filter(isKibanaIndex); } const delay = (delayInMs: number) => new Promise((resolve) => setTimeout(resolve, delayInMs)); @@ -97,7 +97,7 @@ export async function cleanKibanaIndices({ stats, log, }: { - client: KibanaClient; + client: Client; stats: Stats; log: ToolingLog; }) { @@ -123,11 +123,11 @@ export async function cleanKibanaIndices({ } ); - if (resp.body.total !== resp.body.deleted) { + if (resp.total !== resp.deleted) { log.warning( 'delete by query deleted %d of %d total documents, trying again', - resp.body.deleted, - resp.body.total + resp.deleted, + resp.total ); await delay(200); continue; @@ -144,13 +144,7 @@ export async function cleanKibanaIndices({ stats.deletedIndex('.kibana'); } -export async function createDefaultSpace({ - index, - client, -}: { - index: string; - client: KibanaClient; -}) { +export async function createDefaultSpace({ index, client }: { index: string; client: Client }) { await client.create( { index, diff --git a/packages/kbn-es-query/src/es_query/decorate_query.ts b/packages/kbn-es-query/src/es_query/decorate_query.ts index e5bcf01a45915..a58eca575f4bf 100644 --- a/packages/kbn-es-query/src/es_query/decorate_query.ts +++ b/packages/kbn-es-query/src/es_query/decorate_query.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SerializableRecord } from '@kbn/utility-types'; import { extend, defaults } from 'lodash'; import { getTimeZoneFromSettings } from '../utils'; diff --git a/packages/kbn-es-query/src/es_query/from_filters.ts b/packages/kbn-es-query/src/es_query/from_filters.ts index ac6c8a4a6b2b8..28d8653246e3d 100644 --- a/packages/kbn-es-query/src/es_query/from_filters.ts +++ b/packages/kbn-es-query/src/es_query/from_filters.ts @@ -7,7 +7,7 @@ */ import { isUndefined } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { migrateFilter } from './migrate_filter'; import { filterMatchesIndex } from './filter_matches_index'; import { Filter, cleanFilter, isFilterDisabled } from '../filters'; diff --git a/packages/kbn-es-query/src/es_query/lucene_string_to_dsl.ts b/packages/kbn-es-query/src/es_query/lucene_string_to_dsl.ts index 91a912a5da0e3..07b56f281e80e 100644 --- a/packages/kbn-es-query/src/es_query/lucene_string_to_dsl.ts +++ b/packages/kbn-es-query/src/es_query/lucene_string_to_dsl.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isString } from 'lodash'; /** diff --git a/packages/kbn-es-query/src/es_query/types.ts b/packages/kbn-es-query/src/es_query/types.ts index 75ea320b3431f..9e9888f5d14f6 100644 --- a/packages/kbn-es-query/src/es_query/types.ts +++ b/packages/kbn-es-query/src/es_query/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /** * A field's sub type diff --git a/packages/kbn-es-query/src/filters/build_filters/custom_filter.ts b/packages/kbn-es-query/src/filters/build_filters/custom_filter.ts index 72b775bc688cc..77356006d98ef 100644 --- a/packages/kbn-es-query/src/filters/build_filters/custom_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/custom_filter.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Filter, FilterMeta, FILTERS, FilterStateStore } from './types'; /** @public */ diff --git a/packages/kbn-es-query/src/filters/build_filters/match_all_filter.ts b/packages/kbn-es-query/src/filters/build_filters/match_all_filter.ts index 2d14ee8096f13..5e8083c1d1415 100644 --- a/packages/kbn-es-query/src/filters/build_filters/match_all_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/match_all_filter.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { has } from 'lodash'; import type { Filter, FilterMeta } from './types'; diff --git a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts index 13f18ad0cc7ea..87a7812165a66 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts @@ -14,7 +14,7 @@ import { } from './phrase_filter'; import { fields, getField } from '../stubs'; import { DataViewBase } from '../../es_query'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; describe('Phrase filter builder', () => { let indexPattern: DataViewBase; diff --git a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts index 1e123900463b5..4c1827dc58c04 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { get, has, isPlainObject } from 'lodash'; import type { Filter, FilterMeta } from './types'; import type { IndexPatternFieldBase, IndexPatternBase } from '../../es_query'; diff --git a/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts b/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts index 0e09a191fd549..fe895bbd60a74 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Filter, FilterMeta, FILTERS } from './types'; import { getPhraseScript, PhraseFilterValue } from './phrase_filter'; import type { IndexPatternFieldBase, IndexPatternBase } from '../../es_query'; diff --git a/packages/kbn-es-query/src/filters/build_filters/range_filter.ts b/packages/kbn-es-query/src/filters/build_filters/range_filter.ts index e559e4d7e1d80..51e8fefe95f70 100644 --- a/packages/kbn-es-query/src/filters/build_filters/range_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/range_filter.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { map, reduce, mapValues, has, get, keys, pickBy } from 'lodash'; import type { Filter, FilterMeta } from './types'; import type { IndexPatternBase, IndexPatternFieldBase } from '../../es_query'; diff --git a/packages/kbn-es-query/src/kuery/ast/ast.ts b/packages/kbn-es-query/src/kuery/ast/ast.ts index c1b4380ecbfe3..683de9f193901 100644 --- a/packages/kbn-es-query/src/kuery/ast/ast.ts +++ b/packages/kbn-es-query/src/kuery/ast/ast.ts @@ -7,7 +7,7 @@ */ import { JsonObject } from '@kbn/utility-types'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { nodeTypes } from '../node_types/index'; import { KQLSyntaxError } from '../kuery_syntax_error'; import { KueryNode, KueryParseOptions, KueryQueryOptions } from '../types'; diff --git a/packages/kbn-es-query/src/kuery/functions/exists.ts b/packages/kbn-es-query/src/kuery/functions/exists.ts index d1d0cb7835bca..a0d779c4c7d49 100644 --- a/packages/kbn-es-query/src/kuery/functions/exists.ts +++ b/packages/kbn-es-query/src/kuery/functions/exists.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IndexPatternFieldBase, IndexPatternBase, KueryNode, KueryQueryOptions } from '../..'; import * as literal from '../node_types/literal'; diff --git a/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.test.ts b/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.test.ts index 9c4a33f50020f..7580765d59282 100644 --- a/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.test.ts +++ b/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.test.ts @@ -109,7 +109,6 @@ describe('kuery functions', () => { const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params); const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern); - // @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoBoundingBoxQuery expect(result.geo_bounding_box!.ignore_unmapped).toBe(true); }); diff --git a/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.ts b/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.ts index 1dae0b40ff08e..1808b7a2c0106 100644 --- a/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.ts +++ b/packages/kbn-es-query/src/kuery/functions/geo_bounding_box.ts @@ -7,7 +7,7 @@ */ import _ from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { nodeTypes } from '../node_types'; import * as ast from '../ast'; import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..'; @@ -53,7 +53,6 @@ export function toElasticsearchQuery( } return { - // @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoBoundingBoxQuery geo_bounding_box: { [fieldName]: queryParams, ignore_unmapped: true, diff --git a/packages/kbn-es-query/src/kuery/functions/geo_polygon.ts b/packages/kbn-es-query/src/kuery/functions/geo_polygon.ts index cf0bcdafa04c7..0cc95f8012a42 100644 --- a/packages/kbn-es-query/src/kuery/functions/geo_polygon.ts +++ b/packages/kbn-es-query/src/kuery/functions/geo_polygon.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { nodeTypes } from '../node_types'; import * as ast from '../ast'; import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..'; @@ -49,7 +49,6 @@ export function toElasticsearchQuery( } return { - // @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoPolygonQuery geo_polygon: { [fieldName]: queryParams, ignore_unmapped: true, diff --git a/packages/kbn-es-query/src/kuery/functions/is.test.ts b/packages/kbn-es-query/src/kuery/functions/is.test.ts index fbc6011331dbb..2ec53629b9dca 100644 --- a/packages/kbn-es-query/src/kuery/functions/is.test.ts +++ b/packages/kbn-es-query/src/kuery/functions/is.test.ts @@ -11,7 +11,7 @@ import { fields } from '../../filters/stubs'; import * as is from './is'; import { DataViewBase } from '../..'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; jest.mock('../grammar'); diff --git a/packages/kbn-es-query/src/kuery/functions/is.ts b/packages/kbn-es-query/src/kuery/functions/is.ts index 38a62309721a2..854dcd95dc7aa 100644 --- a/packages/kbn-es-query/src/kuery/functions/is.ts +++ b/packages/kbn-es-query/src/kuery/functions/is.ts @@ -7,7 +7,7 @@ */ import { isUndefined } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getPhraseScript } from '../../filters'; import { getFields } from './utils/get_fields'; import { getTimeZoneFromSettings, getDataViewFieldSubtypeNested } from '../../utils'; diff --git a/packages/kbn-es-query/src/kuery/functions/nested.ts b/packages/kbn-es-query/src/kuery/functions/nested.ts index e59f7a6acc07d..3a466e9ddca02 100644 --- a/packages/kbn-es-query/src/kuery/functions/nested.ts +++ b/packages/kbn-es-query/src/kuery/functions/nested.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as ast from '../ast'; import * as literal from '../node_types/literal'; import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..'; diff --git a/packages/kbn-es-query/src/kuery/functions/not.ts b/packages/kbn-es-query/src/kuery/functions/not.ts index 01ec89e9b499d..91954c6a09fc4 100644 --- a/packages/kbn-es-query/src/kuery/functions/not.ts +++ b/packages/kbn-es-query/src/kuery/functions/not.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as ast from '../ast'; import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..'; diff --git a/packages/kbn-es-query/src/kuery/functions/or.ts b/packages/kbn-es-query/src/kuery/functions/or.ts index d48ddb4c32d73..d06f51d2918bd 100644 --- a/packages/kbn-es-query/src/kuery/functions/or.ts +++ b/packages/kbn-es-query/src/kuery/functions/or.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as ast from '../ast'; import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..'; diff --git a/packages/kbn-es-query/src/kuery/functions/range.test.ts b/packages/kbn-es-query/src/kuery/functions/range.test.ts index c541b26ce176f..2a97a74ac385d 100644 --- a/packages/kbn-es-query/src/kuery/functions/range.test.ts +++ b/packages/kbn-es-query/src/kuery/functions/range.test.ts @@ -13,7 +13,7 @@ import { DataViewBase } from '../..'; import { RangeFilterParams } from '../../filters'; import * as range from './range'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; jest.mock('../grammar'); describe('kuery functions', () => { diff --git a/packages/kbn-es-query/src/kuery/functions/range.ts b/packages/kbn-es-query/src/kuery/functions/range.ts index c5f24a1afdd6f..e016feb908bc7 100644 --- a/packages/kbn-es-query/src/kuery/functions/range.ts +++ b/packages/kbn-es-query/src/kuery/functions/range.ts @@ -7,7 +7,7 @@ */ import { pick, map, mapValues } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { nodeTypes } from '../node_types'; import * as ast from '../ast'; import { getRangeScript, RangeFilterParams } from '../../filters'; diff --git a/packages/kbn-es-query/src/kuery/index.ts b/packages/kbn-es-query/src/kuery/index.ts index 15f3a768ebbd3..6e03b3cb18f4c 100644 --- a/packages/kbn-es-query/src/kuery/index.ts +++ b/packages/kbn-es-query/src/kuery/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { toElasticsearchQuery as astToElasticsearchQuery } from './ast'; /** diff --git a/packages/kbn-es-query/src/kuery/types.ts b/packages/kbn-es-query/src/kuery/types.ts index 1ab2d07a60a11..c074fa6d90845 100644 --- a/packages/kbn-es-query/src/kuery/types.ts +++ b/packages/kbn-es-query/src/kuery/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SerializableRecord } from '@kbn/utility-types'; import { NodeTypes } from './node_types'; diff --git a/packages/kbn-es/src/utils/native_realm.js b/packages/kbn-es/src/utils/native_realm.js index c1682e0d18002..5c81d1e1147d1 100644 --- a/packages/kbn-es/src/utils/native_realm.js +++ b/packages/kbn-es/src/utils/native_realm.js @@ -16,7 +16,7 @@ exports.NativeRealm = class NativeRealm { const auth = { username: 'elastic', password: elasticPassword }; this._client = new Client( ssl - ? { node: `https://localhost:${port}`, ssl: { ca: caCert, rejectUnauthorized: true }, auth } + ? { node: `https://localhost:${port}`, tls: { ca: caCert, rejectUnauthorized: true }, auth } : { node: `http://localhost:${port}`, auth } ); this._elasticPassword = elasticPassword; @@ -67,9 +67,7 @@ exports.NativeRealm = class NativeRealm { async getReservedUsers(retryOpts = {}) { return await this._autoRetry(retryOpts, async () => { const resp = await this._client.security.getUser(); - const usernames = Object.keys(resp.body).filter( - (user) => resp.body[user].metadata._reserved === true - ); + const usernames = Object.keys(resp).filter((user) => resp[user].metadata._reserved === true); if (!usernames?.length) { throw new Error('no reserved users found, unable to set native realm passwords'); @@ -82,9 +80,7 @@ exports.NativeRealm = class NativeRealm { async isSecurityEnabled(retryOpts = {}) { try { return await this._autoRetry(retryOpts, async () => { - const { - body: { features }, - } = await this._client.xpack.info({ categories: 'features' }); + const { features } = await this._client.xpack.info({ categories: 'features' }); return features.security && features.security.enabled && features.security.available; }); } catch (error) { diff --git a/packages/kbn-es/src/utils/native_realm.test.js b/packages/kbn-es/src/utils/native_realm.test.js index 6d07b1e73b547..e3cb6aee84198 100644 --- a/packages/kbn-es/src/utils/native_realm.test.js +++ b/packages/kbn-es/src/utils/native_realm.test.js @@ -38,12 +38,10 @@ afterAll(() => { function mockXPackInfo(available, enabled) { mockClient.xpack.info.mockImplementation(() => ({ - body: { - features: { - security: { - available, - enabled, - }, + features: { + security: { + available, + enabled, }, }, })); @@ -97,31 +95,29 @@ describe('setPasswords', () => { mockXPackInfo(true, true); mockClient.security.getUser.mockImplementation(() => ({ - body: { - kibana_system: { - metadata: { - _reserved: true, - }, + kibana_system: { + metadata: { + _reserved: true, }, - non_native: { - metadata: { - _reserved: false, - }, + }, + non_native: { + metadata: { + _reserved: false, }, - logstash_system: { - metadata: { - _reserved: true, - }, + }, + logstash_system: { + metadata: { + _reserved: true, }, - elastic: { - metadata: { - _reserved: true, - }, + }, + elastic: { + metadata: { + _reserved: true, }, - beats_system: { - metadata: { - _reserved: true, - }, + }, + beats_system: { + metadata: { + _reserved: true, }, }, })); @@ -176,21 +172,19 @@ Array [ describe('getReservedUsers', () => { it('returns array of reserved usernames', async () => { mockClient.security.getUser.mockImplementation(() => ({ - body: { - kibana_system: { - metadata: { - _reserved: true, - }, + kibana_system: { + metadata: { + _reserved: true, }, - non_native: { - metadata: { - _reserved: false, - }, + }, + non_native: { + metadata: { + _reserved: false, }, - logstash_system: { - metadata: { - _reserved: true, - }, + }, + logstash_system: { + metadata: { + _reserved: true, }, }, })); diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index d1491ba63e6e6..453e5c174452d 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -94,7 +94,7 @@ pageLoadAssetSize: expressionShape: 34008 interactiveSetup: 80000 expressionTagcloud: 27505 - securitySolution: 231753 + securitySolution: 273763 customIntegrations: 28810 expressionMetricVis: 23121 visTypeMetric: 23332 diff --git a/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts b/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts index d167b17b83f23..d68f6df5cc4d2 100644 --- a/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts +++ b/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EsQueryConfig } from '@kbn/es-query'; /** diff --git a/packages/kbn-rule-data-utils/src/technical_field_names.ts b/packages/kbn-rule-data-utils/src/technical_field_names.ts index 6ac897bbafb08..49e1397d10f97 100644 --- a/packages/kbn-rule-data-utils/src/technical_field_names.ts +++ b/packages/kbn-rule-data-utils/src/technical_field_names.ts @@ -17,6 +17,7 @@ const CONSUMERS = `${KIBANA_NAMESPACE}.consumers` as const; const ECS_VERSION = 'ecs.version' as const; const EVENT_ACTION = 'event.action' as const; const EVENT_KIND = 'event.kind' as const; +const EVENT_MODULE = 'event.module' as const; const SPACE_IDS = `${KIBANA_NAMESPACE}.space_ids` as const; const TAGS = 'tags' as const; const TIMESTAMP = '@timestamp' as const; @@ -88,6 +89,7 @@ const fields = { ECS_VERSION, EVENT_KIND, EVENT_ACTION, + EVENT_MODULE, TAGS, TIMESTAMP, ALERT_ACTION_GROUP, @@ -189,6 +191,7 @@ export { ECS_VERSION, EVENT_ACTION, EVENT_KIND, + EVENT_MODULE, KIBANA_NAMESPACE, ALERT_RULE_UUID, ALERT_RULE_CATEGORY, diff --git a/packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts b/packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts index 6a177f5caac21..973fe27ad7537 100644 --- a/packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts @@ -16,15 +16,18 @@ export const createBootstrapIndex = async ( index: string ): Promise => { return ( - await esClient.indices.create({ - index: `${index}-000001`, - body: { - aliases: { - [index]: { - is_write_index: true, + await esClient.indices.create( + { + index: `${index}-000001`, + body: { + aliases: { + [index]: { + is_write_index: true, + }, }, }, }, - }) + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/decode_version/index.ts b/packages/kbn-securitysolution-es-utils/src/decode_version/index.ts index d58c7add67a27..8b3fb6f63d59a 100644 --- a/packages/kbn-securitysolution-es-utils/src/decode_version/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/decode_version/index.ts @@ -23,8 +23,8 @@ export const decodeVersion = ( const parsed = JSON.parse(decoded); if (Array.isArray(parsed) && Number.isInteger(parsed[0]) && Number.isInteger(parsed[1])) { return { - ifPrimaryTerm: parsed[1], - ifSeqNo: parsed[0], + if_primary_term: parsed[1], + if_seq_no: parsed[0], }; } else { return {}; diff --git a/packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts b/packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts index 580c104752aea..2ff93f668ea27 100644 --- a/packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts @@ -25,7 +25,7 @@ export const deleteAllIndex = async ( { index: pattern, }, - { ignore: [404] } + { ignore: [404], meta: true } ); // @ts-expect-error status doesn't exist on response diff --git a/packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts b/packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts index 60a15f6d4625d..af6dca4619004 100644 --- a/packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts @@ -10,10 +10,7 @@ import type { ElasticsearchClient } from '../elasticsearch_client'; export const deletePolicy = async ( esClient: ElasticsearchClient, - policy: string + name: string ): Promise => { - return ( - // @ts-expect-error policy_id is required by mistake. fixed in the v8.0 - (await esClient.ilm.deleteLifecycle({ policy })).body - ); + return (await esClient.ilm.deleteLifecycle({ name }, { meta: true })).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/delete_template/index.ts b/packages/kbn-securitysolution-es-utils/src/delete_template/index.ts index 86565a0c43b3a..92eeadfff860a 100644 --- a/packages/kbn-securitysolution-es-utils/src/delete_template/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/delete_template/index.ts @@ -13,8 +13,11 @@ export const deleteTemplate = async ( name: string ): Promise => { return ( - await esClient.indices.deleteTemplate({ - name, - }) + await esClient.indices.deleteTemplate( + { + name, + }, + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts b/packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts index a1fb3ff3ecf31..95fa040142c15 100644 --- a/packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts @@ -9,7 +9,7 @@ // Copied from src/core/server/elasticsearch/client/types.ts // as these types aren't part of any package yet. Once they are, remove this completely -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; /** * Client used to query the elasticsearch cluster. @@ -18,5 +18,5 @@ import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; */ export type ElasticsearchClient = Omit< KibanaClient, - 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' + 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' | 'diagnostic' >; diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts b/packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts index ba00c1144edfc..9a0d0fed1b63e 100644 --- a/packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts @@ -39,9 +39,12 @@ export const getIndexAliases = async ({ esClient: ElasticsearchClient; alias: string; }): Promise => { - const response = await esClient.indices.getAlias({ - name: alias, - }); + const response = await esClient.indices.getAlias( + { + name: alias, + }, + { meta: true } + ); return Object.keys(response.body).map((index) => ({ alias, diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts b/packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts index b1dcd4fd0ad9b..59cae505bfded 100644 --- a/packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts @@ -23,9 +23,12 @@ export const getIndexCount = async ({ esClient: ElasticsearchClient; index: string; }): Promise => { - const response = await esClient.count<{ count: number }>({ - index, - }); + const response = await esClient.count<{ count: number }>( + { + index, + }, + { meta: true } + ); return response.body.count; }; diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts b/packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts index 9208773048474..50ba298d10259 100644 --- a/packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts @@ -13,14 +13,17 @@ export const getIndexExists = async ( index: string ): Promise => { try { - const { body: response } = await esClient.search({ - index, - size: 0, - allow_no_indices: true, - body: { - terminate_after: 1, + const { body: response } = await esClient.search( + { + index, + size: 0, + allow_no_indices: true, + body: { + terminate_after: 1, + }, }, - }); + { meta: true } + ); return response._shards.total > 0; } catch (err) { if (err.body != null && err.body.status === 404) { diff --git a/packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts b/packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts index 8172cfb2abaa0..a62ea6e224e7d 100644 --- a/packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts @@ -9,11 +9,11 @@ import type { ElasticsearchClient } from '../elasticsearch_client'; export const getPolicyExists = async ( esClient: ElasticsearchClient, - policy: string + name: string ): Promise => { try { await esClient.ilm.getLifecycle({ - policy, + name, }); // Return true that there exists a policy which is not 404 or some error // Since there is not a policy exists API, this is how we create one by calling diff --git a/packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts b/packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts index 72a3a93654482..a310d1d6e9e0e 100644 --- a/packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts @@ -13,8 +13,11 @@ export const getTemplateExists = async ( template: string ): Promise => { return ( - await esClient.indices.existsTemplate({ - name: template, - }) + await esClient.indices.existsTemplate( + { + name: template, + }, + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/read_index/index.ts b/packages/kbn-securitysolution-es-utils/src/read_index/index.ts index 206a4208b2ecc..a1112f8fceb64 100644 --- a/packages/kbn-securitysolution-es-utils/src/read_index/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/read_index/index.ts @@ -9,7 +9,10 @@ import type { ElasticsearchClient } from '../elasticsearch_client'; export const readIndex = async (esClient: ElasticsearchClient, index: string): Promise => { - return esClient.indices.get({ - index, - }); + return esClient.indices.get( + { + index, + }, + { meta: true } + ); }; diff --git a/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts b/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts index 772a6afa18c95..614eb55297980 100644 --- a/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts @@ -13,60 +13,63 @@ export const readPrivileges = async ( index: string ): Promise => { return ( - await esClient.security.hasPrivileges({ - body: { - cluster: [ - 'all', - 'create_snapshot', - 'manage', - 'manage_api_key', - 'manage_ccr', - 'manage_transform', - 'manage_ilm', - 'manage_index_templates', - 'manage_ingest_pipelines', - 'manage_ml', - 'manage_own_api_key', - 'manage_pipeline', - 'manage_rollup', - 'manage_saml', - 'manage_security', - 'manage_token', - 'manage_watcher', - 'monitor', - 'monitor_transform', - 'monitor_ml', - 'monitor_rollup', - 'monitor_watcher', - 'read_ccr', - 'read_ilm', - 'transport_client', - ], - index: [ - { - names: [index], - privileges: [ - 'all', - 'create', - 'create_doc', - 'create_index', - 'delete', - 'delete_index', - 'index', - 'manage', - 'maintenance', - 'manage_follow_index', - 'manage_ilm', - 'manage_leader_index', - 'monitor', - 'read', - 'read_cross_cluster', - 'view_index_metadata', - 'write', - ], - }, - ], + await esClient.security.hasPrivileges( + { + body: { + cluster: [ + 'all', + 'create_snapshot', + 'manage', + 'manage_api_key', + 'manage_ccr', + 'manage_transform', + 'manage_ilm', + 'manage_index_templates', + 'manage_ingest_pipelines', + 'manage_ml', + 'manage_own_api_key', + 'manage_pipeline', + 'manage_rollup', + 'manage_saml', + 'manage_security', + 'manage_token', + 'manage_watcher', + 'monitor', + 'monitor_transform', + 'monitor_ml', + 'monitor_rollup', + 'monitor_watcher', + 'read_ccr', + 'read_ilm', + 'transport_client', + ], + index: [ + { + names: [index], + privileges: [ + 'all', + 'create', + 'create_doc', + 'create_index', + 'delete', + 'delete_index', + 'index', + 'manage', + 'maintenance', + 'manage_follow_index', + 'manage_ilm', + 'manage_leader_index', + 'monitor', + 'read', + 'read_cross_cluster', + 'view_index_metadata', + 'write', + ], + }, + ], + }, }, - }) + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/set_policy/index.ts b/packages/kbn-securitysolution-es-utils/src/set_policy/index.ts index f6c2dcf7c3c3a..091155e491e05 100644 --- a/packages/kbn-securitysolution-es-utils/src/set_policy/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/set_policy/index.ts @@ -9,13 +9,16 @@ import type { ElasticsearchClient } from '../elasticsearch_client'; export const setPolicy = async ( esClient: ElasticsearchClient, - policy: string, + name: string, body: Record ): Promise => { return ( - await esClient.ilm.putLifecycle({ - policy, - body, - }) + await esClient.ilm.putLifecycle( + { + name, + body, + }, + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-es-utils/src/set_template/index.ts b/packages/kbn-securitysolution-es-utils/src/set_template/index.ts index 20f6fd5719d51..7e1d6a4fb0a1e 100644 --- a/packages/kbn-securitysolution-es-utils/src/set_template/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/set_template/index.ts @@ -14,9 +14,12 @@ export const setTemplate = async ( body: Record ): Promise => { return ( - await esClient.indices.putTemplate({ - name, - body, - }) + await esClient.indices.putTemplate( + { + name, + body, + }, + { meta: true } + ) ).body; }; diff --git a/packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts b/packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts index 2aa4cf64073ab..dc00314ece266 100644 --- a/packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts @@ -23,7 +23,7 @@ import { } from '@kbn/securitysolution-io-ts-list-types'; import { Filter } from '@kbn/es-query'; -import { QueryDslBoolQuery, QueryDslNestedQuery } from '@elastic/elasticsearch/api/types'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { hasLargeValueList } from '../has_large_value_list'; type NonListEntry = EntryMatch | EntryMatchAny | EntryNested | EntryExists; @@ -40,11 +40,11 @@ export type ExceptionItemSansLargeValueLists = | CreateExceptionListItemNonLargeList; export interface BooleanFilter { - bool: QueryDslBoolQuery; + bool: estypes.QueryDslBoolQuery; } export interface NestedFilter { - nested: QueryDslNestedQuery; + nested: estypes.QueryDslNestedQuery; } export const chunkExceptions = ( diff --git a/packages/kbn-securitysolution-rules/BUILD.bazel b/packages/kbn-securitysolution-rules/BUILD.bazel new file mode 100644 index 0000000000000..d8d0122fc4f5f --- /dev/null +++ b/packages/kbn-securitysolution-rules/BUILD.bazel @@ -0,0 +1,95 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") + +PKG_BASE_NAME = "kbn-securitysolution-rules" + +PKG_REQUIRE_NAME = "@kbn/securitysolution-rules" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + "**/*.mock.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md", +] + +RUNTIME_DEPS = [ + "@npm//lodash", + "@npm//tslib", + "@npm//uuid", +] + +TYPES_DEPS = [ + "@npm//tslib", + "@npm//@types/jest", + "@npm//@types/lodash", + "@npm//@types/node", + "@npm//@types/uuid" +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ["--pretty"], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + source_map = True, + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ], +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-securitysolution-rules/README.md b/packages/kbn-securitysolution-rules/README.md new file mode 100644 index 0000000000000..830281574b1d3 --- /dev/null +++ b/packages/kbn-securitysolution-rules/README.md @@ -0,0 +1,3 @@ +# kbn-securitysolution-rules + +This contains alerts-as-data rule-specific constants and mappings that can be used across plugins. diff --git a/packages/kbn-securitysolution-rules/jest.config.js b/packages/kbn-securitysolution-rules/jest.config.js new file mode 100644 index 0000000000000..99368edd5372c --- /dev/null +++ b/packages/kbn-securitysolution-rules/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-securitysolution-rules'], +}; diff --git a/packages/kbn-securitysolution-rules/package.json b/packages/kbn-securitysolution-rules/package.json new file mode 100644 index 0000000000000..5fdb1e593b042 --- /dev/null +++ b/packages/kbn-securitysolution-rules/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/securitysolution-rules", + "version": "1.0.0", + "description": "security solution rule utilities to use across plugins", + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target_node/index.js", + "types": "./target_types/index.d.ts", + "private": true +} diff --git a/packages/kbn-securitysolution-rules/src/index.ts b/packages/kbn-securitysolution-rules/src/index.ts new file mode 100644 index 0000000000000..1d59b9842c90d --- /dev/null +++ b/packages/kbn-securitysolution-rules/src/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './rule_type_constants'; +export * from './rule_type_mappings'; +export * from './utils'; diff --git a/packages/kbn-securitysolution-rules/src/rule_type_constants.ts b/packages/kbn-securitysolution-rules/src/rule_type_constants.ts new file mode 100644 index 0000000000000..baf355897b7b5 --- /dev/null +++ b/packages/kbn-securitysolution-rules/src/rule_type_constants.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * Id for the legacy siem signals alerting type + */ +export const SIGNALS_ID = `siem.signals` as const; + +/** + * IDs for alerts-as-data rule types + */ +const RULE_TYPE_PREFIX = `siem` as const; +export const EQL_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.eqlRule` as const; +export const INDICATOR_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.indicatorRule` as const; +export const ML_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.mlRule` as const; +export const QUERY_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.queryRule` as const; +export const SAVED_QUERY_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.savedQueryRule` as const; +export const THRESHOLD_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.thresholdRule` as const; diff --git a/packages/kbn-securitysolution-rules/src/rule_type_mappings.ts b/packages/kbn-securitysolution-rules/src/rule_type_mappings.ts new file mode 100644 index 0000000000000..6036c6418e20c --- /dev/null +++ b/packages/kbn-securitysolution-rules/src/rule_type_mappings.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + EQL_RULE_TYPE_ID, + INDICATOR_RULE_TYPE_ID, + ML_RULE_TYPE_ID, + QUERY_RULE_TYPE_ID, + SAVED_QUERY_RULE_TYPE_ID, + THRESHOLD_RULE_TYPE_ID, +} from './rule_type_constants'; + +/** + * Maps legacy rule types to RAC rule type IDs. + */ +export const ruleTypeMappings = { + eql: EQL_RULE_TYPE_ID, + machine_learning: ML_RULE_TYPE_ID, + query: QUERY_RULE_TYPE_ID, + saved_query: SAVED_QUERY_RULE_TYPE_ID, + threat_match: INDICATOR_RULE_TYPE_ID, + threshold: THRESHOLD_RULE_TYPE_ID, +}; +type RuleTypeMappings = typeof ruleTypeMappings; + +export type RuleType = keyof RuleTypeMappings; +export type RuleTypeId = RuleTypeMappings[keyof RuleTypeMappings]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/flatten_with_prefix.ts b/packages/kbn-securitysolution-rules/src/utils.ts similarity index 52% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/flatten_with_prefix.ts rename to packages/kbn-securitysolution-rules/src/utils.ts index 02f418a151888..17a4e7ab655ad 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/flatten_with_prefix.ts +++ b/packages/kbn-securitysolution-rules/src/utils.ts @@ -1,12 +1,23 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { isPlainObject } from 'lodash'; -import { SearchTypes } from '../../../../../../common/detection_engine/types'; +import { RuleType, RuleTypeId, ruleTypeMappings } from './rule_type_mappings'; + +export const isRuleType = (ruleType: unknown): ruleType is RuleType => { + return Object.keys(ruleTypeMappings).includes(ruleType as string); +}; + +export const isRuleTypeId = (ruleTypeId: unknown): ruleTypeId is RuleTypeId => { + return Object.values(ruleTypeMappings).includes(ruleTypeId as RuleTypeId); +}; + +type SearchTypes = string | number | boolean | object | SearchTypes[] | undefined; export const flattenWithPrefix = ( prefix: string, diff --git a/packages/elastic-apm-generator/tsconfig.json b/packages/kbn-securitysolution-rules/tsconfig.json similarity index 64% rename from packages/elastic-apm-generator/tsconfig.json rename to packages/kbn-securitysolution-rules/tsconfig.json index 534e8481dce9a..3895e13ad28ed 100644 --- a/packages/elastic-apm-generator/tsconfig.json +++ b/packages/kbn-securitysolution-rules/tsconfig.json @@ -5,15 +5,15 @@ "declarationMap": true, "emitDeclarationOnly": true, "outDir": "target_types", - "rootDir": "./src", + "rootDir": "src", "sourceMap": true, - "sourceRoot": "../../../../packages/elastic-apm-generator/src", + "sourceRoot": "../../../../packages/kbn-securitysolution-rules/src", "types": [ - "node", - "jest" + "jest", + "node" ] }, "include": [ - "./src/**/*.ts" + "src/**/*" ] } diff --git a/packages/kbn-test/src/es/client_to_kibana_client.ts b/packages/kbn-test/src/es/client_to_kibana_client.ts new file mode 100644 index 0000000000000..778ee0a7705b3 --- /dev/null +++ b/packages/kbn-test/src/es/client_to_kibana_client.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; +import type { + Client, + TransportRequestParams, + TransportRequestOptions, + TransportResult, +} from '@elastic/elasticsearch'; +import { Transport } from '@elastic/elasticsearch'; + +// remove once https://github.com/elastic/kibana/issues/116095 is addressed +class KibanaTransport extends Transport { + request(params: TransportRequestParams, options?: TransportRequestOptions) { + const opts: TransportRequestOptions = options || {}; + // Enforce the client to return TransportResult. + // It's required for bwc with responses in 7.x version. + if (opts?.meta === undefined) { + opts.meta = true; + } + return super.request(params, opts) as Promise>; + } +} + +export function convertToKibanaClient(esClient: Client): KibanaClient { + // @ts-expect-error @elastic/elasticsearch fix discrepancy between clients + return esClient.child({ + Transport: KibanaTransport, + }); +} diff --git a/packages/kbn-test/src/es/index.ts b/packages/kbn-test/src/es/index.ts index ccfec67dae848..0c19a6b903742 100644 --- a/packages/kbn-test/src/es/index.ts +++ b/packages/kbn-test/src/es/index.ts @@ -9,3 +9,4 @@ export { createTestEsCluster } from './test_es_cluster'; export type { CreateTestEsClusterOptions, EsTestCluster, ICluster } from './test_es_cluster'; export { esTestConfig } from './es_test_config'; +export { convertToKibanaClient } from './client_to_kibana_client'; diff --git a/packages/kbn-test/src/es/test_es_cluster.ts b/packages/kbn-test/src/es/test_es_cluster.ts index 0d31ffdb99cc2..575fc965962eb 100644 --- a/packages/kbn-test/src/es/test_es_cluster.ts +++ b/packages/kbn-test/src/es/test_es_cluster.ts @@ -11,11 +11,12 @@ import { format } from 'url'; import del from 'del'; // @ts-expect-error in js import { Cluster } from '@kbn/es'; -import { Client } from '@elastic/elasticsearch'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import type { ToolingLog } from '@kbn/dev-utils'; import { CI_PARALLEL_PROCESS_PREFIX } from '../ci_parallel_process_prefix'; import { esTestConfig } from './es_test_config'; +import { convertToKibanaClient } from './client_to_kibana_client'; import { KIBANA_ROOT } from '../'; @@ -51,7 +52,8 @@ export interface ICluster { start: () => Promise; stop: () => Promise; cleanup: () => Promise; - getClient: () => KibanaClient; + getClient: () => Client; + getKibanaEsClient: () => KibanaClient; getHostUrls: () => string[]; } @@ -280,12 +282,20 @@ export function createTestEsCluster< /** * Returns an ES Client to the configured cluster */ - getClient(): KibanaClient { + getClient(): Client { return new Client({ node: this.getHostUrls()[0], + Connection: HttpConnection, }); } + /** + * Returns an ES Client to the configured cluster + */ + getKibanaEsClient(): KibanaClient { + return convertToKibanaClient(this.getClient()); + } + getUrl() { if (this.nodes.length > 1) { throw new Error( diff --git a/packages/kbn-test/src/failed_tests_reporter/report_failures_to_es.ts b/packages/kbn-test/src/failed_tests_reporter/report_failures_to_es.ts index 754ce2567cb80..a96ca5822775d 100644 --- a/packages/kbn-test/src/failed_tests_reporter/report_failures_to_es.ts +++ b/packages/kbn-test/src/failed_tests_reporter/report_failures_to_es.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Client } from '@elastic/elasticsearch'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; import { createFailError, ToolingLog } from '@kbn/dev-utils'; import { TestFailure } from './get_failures'; @@ -34,6 +34,7 @@ export async function reportFailuresToEs(log: ToolingLog, failures: TestFailure[ username: process.env.TEST_FAILURES_ES_USERNAME, password: process.env.TEST_FAILURES_ES_PASSWORD, }, + Connection: HttpConnection, }); const body = failures.flatMap((failure) => [ @@ -59,7 +60,7 @@ export async function reportFailuresToEs(log: ToolingLog, failures: TestFailure[ }, ]); - const resp = await client.bulk({ body }); + const resp = await client.bulk({ body }, { meta: true }); if (resp?.body?.errors) { log.error(JSON.stringify(resp.body.items, null, 2)); } diff --git a/packages/kbn-test/src/index.ts b/packages/kbn-test/src/index.ts index dea2ec9d1035e..0ef9fbfed07a0 100644 --- a/packages/kbn-test/src/index.ts +++ b/packages/kbn-test/src/index.ts @@ -31,6 +31,7 @@ export { CreateTestEsClusterOptions, EsTestCluster, ICluster, + convertToKibanaClient, } from './es'; export { kbnTestConfig, kibanaServerTestUser, kibanaTestUser, adminTestUser } from './kbn'; diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js index 601ee3096e0b7..b286cf05a6d71 100644 --- a/scripts/functional_tests.js +++ b/scripts/functional_tests.js @@ -17,6 +17,14 @@ const alwaysImportedTests = [ require.resolve( '../test/interactive_setup_api_integration/manual_configuration_flow_without_tls.config.ts' ), + require.resolve('../test/interactive_setup_functional/enrollment_token.config.ts'), + require.resolve('../test/interactive_setup_functional/manual_configuration.config.ts'), + require.resolve( + '../test/interactive_setup_functional/manual_configuration_without_security.config.ts' + ), + require.resolve( + '../test/interactive_setup_functional/manual_configuration_without_tls.config.ts' + ), ]; // eslint-disable-next-line no-restricted-syntax const onlyNotInCoverageTests = [ diff --git a/src/cli_setup/utils.ts b/src/cli_setup/utils.ts index 65a46b8f5b278..21406bf7e57e0 100644 --- a/src/cli_setup/utils.ts +++ b/src/cli_setup/utils.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getConfigPath } from '@kbn/utils'; +import { getConfigPath, getDataPath } from '@kbn/utils'; import inquirer from 'inquirer'; import { duration } from 'moment'; import { merge } from 'lodash'; @@ -30,7 +30,7 @@ const logger: Logger = { get: () => logger, }; -export const kibanaConfigWriter = new KibanaConfigWriter(getConfigPath(), logger); +export const kibanaConfigWriter = new KibanaConfigWriter(getConfigPath(), getDataPath(), logger); export const elasticsearch = new ElasticsearchService(logger).setup({ connectionCheckInterval: duration(Infinity), elasticsearch: { 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 6987b779d5d45..571b564f90329 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 @@ -644,6 +644,11 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` > } + buttonElement="button" className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" data-test-subj="collapsibleNavGroup-recentlyViewed" + element="div" id="generated-id" initialIsOpen={true} isLoading={false} @@ -685,28 +692,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` + + +
} + buttonElement="button" className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" data-test-subj="collapsibleNavGroup-kibana" + element="div" id="generated-id" initialIsOpen={true} isLoading={false} @@ -941,28 +977,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` + + +
} + buttonElement="button" className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" data-test-subj="collapsibleNavGroup-observability" + element="div" id="generated-id" initialIsOpen={true} isLoading={false} @@ -1233,28 +1298,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` + + +
} + buttonElement="button" className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" data-test-subj="collapsibleNavGroup-securitySolution" + element="div" id="generated-id" initialIsOpen={true} isLoading={false} @@ -1486,28 +1580,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` + + +
} + buttonElement="button" className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" data-test-subj="collapsibleNavGroup-management" + element="div" id="generated-id" initialIsOpen={true} isLoading={false} @@ -1700,28 +1823,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` + + +
{ diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 20757463737fc..2bbb4703ecd19 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -480,6 +480,7 @@ export class DocLinksService { troubleshooting: `${FLEET_DOCS}fleet-troubleshooting.html`, elasticAgent: `${FLEET_DOCS}elastic-agent-installation.html`, datastreams: `${FLEET_DOCS}data-streams.html`, + datastreamsILM: `${FLEET_DOCS}data-streams.html#data-streams-ilm`, datastreamsNamingScheme: `${FLEET_DOCS}data-streams.html#data-streams-naming-scheme`, installElasticAgent: `${FLEET_DOCS}install-fleet-managed-elastic-agent.html`, upgradeElasticAgent: `${FLEET_DOCS}upgrade-elastic-agent.html`, @@ -734,6 +735,7 @@ export interface DocLinksStart { readonly snapshotRestore: Record; readonly ingest: Record; readonly fleet: Readonly<{ + datastreamsILM: string; guide: string; fleetServer: string; fleetServerAddFleetServer: string; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 353e5aa4607e4..cf0b526aa9fd9 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -5,13 +5,11 @@ ```ts import { Action } from 'history'; -import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; import Boom from '@hapi/boom'; -import { ConfigDeprecationProvider } from '@kbn/config'; import { ConfigPath } from '@kbn/config'; import { DetailedPeerCertificate } from 'tls'; import { EnvironmentMode } from '@kbn/config'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiBreadcrumb } from '@elastic/eui'; import { EuiButtonEmptyProps } from '@elastic/eui'; import { EuiConfirmModalProps } from '@elastic/eui'; @@ -21,7 +19,7 @@ import { History } from 'history'; import { Href } from 'history'; import { IconType } from '@elastic/eui'; import { IncomingHttpHeaders } from 'http'; -import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import { Location } from 'history'; import { LocationDescriptorObject } from 'history'; import { Logger } from '@kbn/logging'; @@ -39,9 +37,9 @@ import { RecursiveReadonly } from '@kbn/utility-types'; import { Request } from '@hapi/hapi'; import * as Rx from 'rxjs'; import { SchemaTypeError } from '@kbn/config-schema'; -import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; +import { TransportRequestOptions } from '@elastic/elasticsearch'; +import { TransportRequestParams } from '@elastic/elasticsearch'; +import { TransportResult } from '@elastic/elasticsearch'; import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; import { UiCounterMetricType } from '@kbn/analytics'; @@ -698,6 +696,7 @@ export interface DocLinksStart { readonly snapshotRestore: Record; readonly ingest: Record; readonly fleet: Readonly<{ + datastreamsILM: string; guide: string; fleetServer: string; fleetServerAddFleetServer: string; diff --git a/src/core/server/core_usage_data/core_usage_data_service.test.ts b/src/core/server/core_usage_data/core_usage_data_service.test.ts index 3c05069d3cd07..209aece3f5719 100644 --- a/src/core/server/core_usage_data/core_usage_data_service.test.ts +++ b/src/core/server/core_usage_data/core_usage_data_service.test.ts @@ -17,7 +17,6 @@ import { mockCoreContext } from '../core_context.mock'; import { config as RawElasticsearchConfig } from '../elasticsearch/elasticsearch_config'; import { config as RawHttpConfig } from '../http/http_config'; import { config as RawLoggingConfig } from '../logging/logging_config'; -import { config as RawKibanaConfig } from '../kibana_config'; import { savedObjectsConfig as RawSavedObjectsConfig } from '../saved_objects/saved_objects_config'; import { httpServiceMock } from '../http/http_service.mock'; import { metricsServiceMock } from '../metrics/metrics_service.mock'; @@ -40,8 +39,6 @@ describe('CoreUsageDataService', () => { return new BehaviorSubject(RawLoggingConfig.schema.validate({})); } else if (path === 'savedObjects') { return new BehaviorSubject(RawSavedObjectsConfig.schema.validate({})); - } else if (path === 'kibana') { - return new BehaviorSubject(RawKibanaConfig.schema.validate({})); } return new BehaviorSubject({}); }; diff --git a/src/core/server/core_usage_data/core_usage_data_service.ts b/src/core/server/core_usage_data/core_usage_data_service.ts index 72b70824d305d..2e76bc08658a2 100644 --- a/src/core/server/core_usage_data/core_usage_data_service.ts +++ b/src/core/server/core_usage_data/core_usage_data_service.ts @@ -17,7 +17,7 @@ import { AggregationsFiltersAggregate, AggregationsFiltersBucketItem, SearchTotalHits, -} from '@elastic/elasticsearch/api/types'; +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { CoreContext } from '../core_context'; import { ElasticsearchConfigType } from '../elasticsearch/elasticsearch_config'; import { HttpConfigType, InternalHttpServiceSetup } from '../http'; @@ -33,7 +33,6 @@ import type { } from './types'; import { isConfigured } from './is_configured'; import { ElasticsearchServiceStart } from '../elasticsearch'; -import { KibanaConfigType } from '../kibana_config'; import { coreUsageStatsType } from './core_usage_stats'; import { LEGACY_URL_ALIAS_TYPE } from '../saved_objects/object_types'; import { CORE_USAGE_STATS_TYPE } from './constants'; @@ -56,6 +55,8 @@ export interface StartDeps { exposedConfigsToUsage: ExposedConfigsToUsage; } +const kibanaIndex = '.kibana'; + /** * Because users can configure their Saved Object to any arbitrary index name, * we need to map customized index names back to a "standard" index name. @@ -74,19 +75,6 @@ const kibanaOrTaskManagerIndex = (index: string, kibanaConfigIndex: string) => { return index === kibanaConfigIndex ? '.kibana' : '.kibana_task_manager'; }; -/** - * This is incredibly hacky... The config service doesn't allow you to determine - * whether or not a config value has been changed from the default value, and the - * default value is defined in legacy code. - * - * This will be going away in 8.0, so please look away for a few months - * - * @param index The `kibana.index` setting from the `kibana.yml` - */ -const isCustomIndex = (index: string) => { - return index !== '.kibana'; -}; - export class CoreUsageDataService implements CoreService { @@ -98,7 +86,6 @@ export class CoreUsageDataService private soConfig?: SavedObjectsConfigType; private stop$: Subject; private opsMetrics?: OpsMetrics; - private kibanaConfig?: KibanaConfigType; private coreUsageStatsClient?: CoreUsageStatsClient; private deprecatedConfigPaths: ChangedDeprecatedPaths = { set: [], unset: [] }; private incrementUsageCounter: CoreIncrementUsageCounter = () => {}; // Initially set to noop @@ -133,8 +120,8 @@ export class CoreUsageDataService .getTypeRegistry() .getAllTypes() .reduce((acc, type) => { - const index = type.indexPattern ?? this.kibanaConfig!.index; - return index != null ? acc.add(index) : acc; + const index = type.indexPattern ?? kibanaIndex; + return acc.add(index); }, new Set()) .values() ).map((index) => { @@ -150,7 +137,7 @@ export class CoreUsageDataService .then(({ body }) => { const stats = body[0]; return { - alias: kibanaOrTaskManagerIndex(index, this.kibanaConfig!.index), + alias: kibanaOrTaskManagerIndex(index, kibanaIndex), docsCount: stats['docs.count'] ? parseInt(stats['docs.count'], 10) : 0, docsDeleted: stats['docs.deleted'] ? parseInt(stats['docs.deleted'], 10) : 0, storeSizeBytes: stats['store.size'] ? parseInt(stats['store.size'], 10) : 0, @@ -167,7 +154,7 @@ export class CoreUsageDataService // Note: this agg can be changed to use `savedObjectsRepository.find` in the future after `filters` is supported. // See src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts for supported aggregations. const { body: resp } = await elasticsearch.client.asInternalUser.search({ - index: this.kibanaConfig!.index, + index: kibanaIndex, body: { track_total_hits: true, query: { match: { type: LEGACY_URL_ALIAS_TYPE } }, @@ -313,7 +300,7 @@ export class CoreUsageDataService }, savedObjects: { - customIndex: isCustomIndex(this.kibanaConfig!.index), + customIndex: false, maxImportPayloadBytes: this.soConfig.maxImportPayloadBytes.getValueInBytes(), maxImportExportSize: this.soConfig.maxImportExportSize, }, @@ -472,13 +459,6 @@ export class CoreUsageDataService this.soConfig = config; }); - this.configService - .atPath('kibana') - .pipe(takeUntil(this.stop$)) - .subscribe((config) => { - this.kibanaConfig = config; - }); - changedDeprecatedConfigPath$ .pipe(takeUntil(this.stop$)) .subscribe((deprecatedConfigPaths) => (this.deprecatedConfigPaths = deprecatedConfigPaths)); diff --git a/src/core/server/elasticsearch/client/client_config.test.ts b/src/core/server/elasticsearch/client/client_config.test.ts index af8e2d64cb6a2..8158b7d116c4b 100644 --- a/src/core/server/elasticsearch/client/client_config.test.ts +++ b/src/core/server/elasticsearch/client/client_config.test.ts @@ -328,10 +328,10 @@ describe('parseClientOptions', () => { }); }); - describe('ssl config', () => { - it('does not generate ssl option is ssl config is not set', () => { - expect(parseClientOptions(createConfig({}), false).ssl).toBeUndefined(); - expect(parseClientOptions(createConfig({}), true).ssl).toBeUndefined(); + describe('tls config', () => { + it('does not generate tls option is ssl config is not set', () => { + expect(parseClientOptions(createConfig({}), false).tls).toBeUndefined(); + expect(parseClientOptions(createConfig({}), true).tls).toBeUndefined(); }); it('handles the `certificateAuthorities` option', () => { @@ -341,7 +341,7 @@ describe('parseClientOptions', () => { ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] }, }), false - ).ssl!.ca + ).tls!.ca ).toEqual(['content-of-ca-path']); expect( parseClientOptions( @@ -349,7 +349,7 @@ describe('parseClientOptions', () => { ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] }, }), true - ).ssl!.ca + ).tls!.ca ).toEqual(['content-of-ca-path']); }); @@ -363,7 +363,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -380,7 +380,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -398,7 +398,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -416,7 +416,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: unknown"`); }); it('throws for undefined values', () => { @@ -429,7 +429,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: undefined"`); }); }); @@ -446,7 +446,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -466,7 +466,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -487,7 +487,7 @@ describe('parseClientOptions', () => { }, }), false - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -511,7 +511,7 @@ describe('parseClientOptions', () => { }, }), true - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, @@ -531,7 +531,7 @@ describe('parseClientOptions', () => { }, }), true - ).ssl + ).tls ).toMatchInlineSnapshot(` Object { "ca": undefined, diff --git a/src/core/server/elasticsearch/client/client_config.ts b/src/core/server/elasticsearch/client/client_config.ts index 24c48012346da..1cb81fd0a417a 100644 --- a/src/core/server/elasticsearch/client/client_config.ts +++ b/src/core/server/elasticsearch/client/client_config.ts @@ -9,7 +9,7 @@ import { ConnectionOptions as TlsConnectionOptions } from 'tls'; import { URL } from 'url'; import { Duration } from 'moment'; -import { ClientOptions, NodeOptions } from '@elastic/elasticsearch'; +import type { ClientOptions } from '@elastic/elasticsearch/lib/client'; import { ElasticsearchConfig } from '../elasticsearch_config'; import { DEFAULT_HEADERS } from '../default_headers'; @@ -93,7 +93,7 @@ export function parseClientOptions( clientOptions.nodes = config.hosts.map((host) => convertHost(host)); if (config.ssl) { - clientOptions.ssl = generateSslConfig( + clientOptions.tls = generateSslConfig( config.ssl, scoped && !config.ssl.alwaysPresentCertificate ); @@ -141,7 +141,7 @@ const generateSslConfig = ( return ssl; }; -const convertHost = (host: string): NodeOptions => { +const convertHost = (host: string): { url: URL } => { const url = new URL(host); const isHTTPS = url.protocol === 'https:'; url.port = url.port || (isHTTPS ? '443' : '80'); diff --git a/src/core/server/elasticsearch/client/cluster_client.ts b/src/core/server/elasticsearch/client/cluster_client.ts index f81b651843013..1f3118c77aa0f 100644 --- a/src/core/server/elasticsearch/client/cluster_client.ts +++ b/src/core/server/elasticsearch/client/cluster_client.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Client } from '@elastic/elasticsearch'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import { Logger } from '../../logging'; import { GetAuthHeaders, Headers, isKibanaRequest, isRealRequest } from '../../http'; import { ensureRawRequest, filterHeaders } from '../../http/router'; @@ -52,8 +52,8 @@ export interface ICustomClusterClient extends IClusterClient { /** @internal **/ export class ClusterClient implements ICustomClusterClient { - public readonly asInternalUser: Client; - private readonly rootScopedClient: Client; + public readonly asInternalUser: KibanaClient; + private readonly rootScopedClient: KibanaClient; private readonly allowListHeaders: string[]; private isClosed = false; diff --git a/src/core/server/elasticsearch/client/configure_client.test.ts b/src/core/server/elasticsearch/client/configure_client.test.ts index 35fcb5819d015..7988e81045d17 100644 --- a/src/core/server/elasticsearch/client/configure_client.test.ts +++ b/src/core/server/elasticsearch/client/configure_client.test.ts @@ -9,13 +9,13 @@ import { Buffer } from 'buffer'; import { Readable } from 'stream'; -import { RequestEvent, errors } from '@elastic/elasticsearch'; -import type { Client } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; import type { TransportRequestOptions, TransportRequestParams, + DiagnosticResult, RequestBody, -} from '@elastic/elasticsearch/lib/Transport'; +} from '@elastic/elasticsearch'; import { parseClientOptionsMock, ClientMock } from './configure_client.test.mocks'; import { loggingSystemMock } from '../../logging/logging_system.mock'; @@ -36,7 +36,7 @@ const createFakeClient = () => { const client = new actualEs.Client({ nodes: ['http://localhost'], // Enforcing `nodes` because it's mandatory }); - jest.spyOn(client, 'on'); + jest.spyOn(client.diagnostic, 'on'); return client; }; @@ -54,7 +54,7 @@ const createApiResponse = ({ warnings?: string[]; params?: TransportRequestParams; requestOptions?: TransportRequestOptions; -}): RequestEvent => { +}): DiagnosticResult => { return { body, statusCode, @@ -70,14 +70,6 @@ const createApiResponse = ({ }; }; -function getProductCheckValue(client: Client) { - const tSymbol = Object.getOwnPropertySymbols(client.transport || client).filter( - (symbol) => symbol.description === 'product check' - )[0]; - // @ts-expect-error `tSymbol` is missing in the index signature of Transport - return (client.transport || client)[tSymbol]; -} - describe('configureClient', () => { let logger: ReturnType; let config: ElasticsearchClientConfig; @@ -124,26 +116,8 @@ describe('configureClient', () => { it('listens to client on `response` events', () => { const client = configureClient(config, { logger, type: 'test', scoped: false }); - expect(client.on).toHaveBeenCalledTimes(1); - expect(client.on).toHaveBeenCalledWith('response', expect.any(Function)); - }); - - describe('Product check', () => { - it('should not skip the product check for the unscoped client', () => { - const client = configureClient(config, { logger, type: 'test', scoped: false }); - expect(getProductCheckValue(client)).toBe(0); - }); - - it('should skip the product check for the scoped client', () => { - const client = configureClient(config, { logger, type: 'test', scoped: true }); - expect(getProductCheckValue(client)).toBe(2); - }); - - it('should skip the product check for the children of the scoped client', () => { - const client = configureClient(config, { logger, type: 'test', scoped: true }); - const asScoped = client.child({ headers: { 'x-custom-header': 'Custom value' } }); - expect(getProductCheckValue(asScoped)).toBe(2); - }); + expect(client.diagnostic.on).toHaveBeenCalledTimes(1); + expect(client.diagnostic.on).toHaveBeenCalledWith('response', expect.any(Function)); }); describe('Client logging', () => { @@ -176,7 +150,7 @@ describe('configureClient', () => { }, }); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ Array [ @@ -201,7 +175,7 @@ describe('configureClient', () => { }) ); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ Array [ @@ -228,7 +202,7 @@ describe('configureClient', () => { ) ); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ Array [ @@ -255,7 +229,7 @@ describe('configureClient', () => { ) ); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ Array [ @@ -273,7 +247,7 @@ describe('configureClient', () => { const response = createResponseWithBody(); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ Array [ @@ -298,7 +272,7 @@ describe('configureClient', () => { }, }); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -333,7 +307,7 @@ describe('configureClient', () => { }, }, }); - client.emit('response', new errors.ResponseError(response), response); + client.diagnostic.emit('response', new errors.ResponseError(response), response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -351,7 +325,7 @@ describe('configureClient', () => { const client = configureClient(createFakeConfig(), { logger, type: 'test', scoped: false }); const response = createApiResponse({ body: {} }); - client.emit('response', new errors.TimeoutError('message', response), response); + client.diagnostic.emit('response', new errors.TimeoutError('message', response), response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -381,7 +355,7 @@ describe('configureClient', () => { }, }, }); - client.emit('response', new errors.ResponseError(response), response); + client.diagnostic.emit('response', new errors.ResponseError(response), response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -397,7 +371,7 @@ describe('configureClient', () => { it('logs default error info when the error response body is empty', () => { const client = configureClient(createFakeConfig(), { logger, type: 'test', scoped: false }); - let response: RequestEvent = createApiResponse({ + let response: DiagnosticResult = createApiResponse({ statusCode: 400, headers: {}, params: { @@ -408,7 +382,7 @@ describe('configureClient', () => { error: {}, }, }); - client.emit('response', new errors.ResponseError(response), response); + client.diagnostic.emit('response', new errors.ResponseError(response), response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -431,7 +405,7 @@ describe('configureClient', () => { }, body: undefined, }); - client.emit('response', new errors.ResponseError(response), response); + client.diagnostic.emit('response', new errors.ResponseError(response), response); expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(` Array [ @@ -461,7 +435,7 @@ describe('configureClient', () => { error: {}, }, }); - client.emit('response', null, response); + client.diagnostic.emit('response', null, response); expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(` Object { @@ -487,7 +461,7 @@ describe('configureClient', () => { }, body: {} as any, }); - client.emit('response', new errors.ResponseError(response), response); + client.diagnostic.emit('response', new errors.ResponseError(response), response); expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(` Object { diff --git a/src/core/server/elasticsearch/client/configure_client.ts b/src/core/server/elasticsearch/client/configure_client.ts index 93c404593af3f..fc8a06660cc5e 100644 --- a/src/core/server/elasticsearch/client/configure_client.ts +++ b/src/core/server/elasticsearch/client/configure_client.ts @@ -8,14 +8,19 @@ import { Buffer } from 'buffer'; import { stringify } from 'querystring'; -import { ApiError, Client, RequestEvent, errors, Transport } from '@elastic/elasticsearch'; +import { Client, errors, Transport, HttpConnection } from '@elastic/elasticsearch'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import type { - RequestBody, TransportRequestParams, TransportRequestOptions, -} from '@elastic/elasticsearch/lib/Transport'; + TransportResult, + DiagnosticResult, + RequestBody, +} from '@elastic/elasticsearch'; + import { Logger } from '../../logging'; import { parseClientOptions, ElasticsearchClientConfig } from './client_config'; +import type { ElasticsearchErrorDetails } from './types'; const noop = () => undefined; @@ -32,30 +37,33 @@ export const configureClient = ( scoped?: boolean; getExecutionContext?: () => string | undefined; } -): Client => { +): KibanaClient => { const clientOptions = parseClientOptions(config, scoped); class KibanaTransport extends Transport { request(params: TransportRequestParams, options?: TransportRequestOptions) { - const opts = options || {}; + const opts: TransportRequestOptions = options || {}; const opaqueId = getExecutionContext(); if (opaqueId && !opts.opaqueId) { // rewrites headers['x-opaque-id'] if it presents opts.opaqueId = opaqueId; } - return super.request(params, opts); + // Enforce the client to return TransportResult. + // It's required for bwc with responses in 7.x version. + if (opts.meta === undefined) { + opts.meta = true; + } + return super.request(params, opts) as Promise>; } } - const client = new Client({ ...clientOptions, Transport: KibanaTransport }); + const client = new Client({ + ...clientOptions, + Transport: KibanaTransport, + Connection: HttpConnection, + }); addLogging(client, logger.get('query', type)); - // --------------------------------------------------------------------------------- // - // Hack to disable the "Product check" only in the scoped clients while we // - // come up with a better approach in https://github.com/elastic/kibana/issues/110675 // - if (scoped) skipProductCheck(client); - // --------------------------------------------------------------------------------- // - - return client; + return client as KibanaClient; }; const convertQueryString = (qs: string | Record | undefined): string => { @@ -76,9 +84,10 @@ function ensureString(body: RequestBody): string { * Returns a debug message from an Elasticsearch error in the following format: * [error type] error reason */ -export function getErrorMessage(error: ApiError): string { +export function getErrorMessage(error: errors.ElasticsearchClientError): string { if (error instanceof errors.ResponseError) { - return `[${error.meta.body?.error?.type}]: ${error.meta.body?.error?.reason ?? error.message}`; + const errorBody = error.meta.body as ElasticsearchErrorDetails; + return `[${errorBody?.error?.type}]: ${errorBody?.error?.reason ?? error.message}`; } return `[${error.name}]: ${error.message}`; } @@ -92,7 +101,7 @@ export function getErrorMessage(error: ApiError): string { * * so it could be copy-pasted into the Dev console */ -function getResponseMessage(event: RequestEvent): string { +function getResponseMessage(event: DiagnosticResult): string { const errorMeta = getRequestDebugMeta(event); const body = errorMeta.body ? `\n${errorMeta.body}` : ''; return `${errorMeta.statusCode}\n${errorMeta.method} ${errorMeta.url}${body}`; @@ -102,7 +111,7 @@ function getResponseMessage(event: RequestEvent): string { * Returns stringified debug information from an Elasticsearch request event * useful for logging in case of an unexpected failure. */ -export function getRequestDebugMeta(event: RequestEvent): { +export function getRequestDebugMeta(event: DiagnosticResult): { url: string; body: string; statusCode: number | null; @@ -115,12 +124,12 @@ export function getRequestDebugMeta(event: RequestEvent): { url: `${params.path}${querystring ? `?${querystring}` : ''}`, body: params.body ? `${ensureString(params.body)}` : '', method: params.method, - statusCode: event.statusCode, + statusCode: event.statusCode!, }; } const addLogging = (client: Client, logger: Logger) => { - client.on('response', (error, event) => { + client.diagnostic.on('response', (error, event) => { if (event) { const opaqueId = event.meta.request.options.opaqueId; const meta = opaqueId @@ -140,21 +149,3 @@ const addLogging = (client: Client, logger: Logger) => { } }); }; - -/** - * Hack to skip the Product Check performed by the Elasticsearch-js client. - * We noticed that the scoped clients are always performing this check because - * of the way we initialize the clients. We'll discuss changing this in the issue - * https://github.com/elastic/kibana/issues/110675. In the meanwhile, let's skip - * it for the scoped clients. - * - * The hack is copied from the test/utils in the elasticsearch-js repo - * (https://github.com/elastic/elasticsearch-js/blob/master/test/utils/index.js#L45-L56) - */ -function skipProductCheck(client: Client) { - const tSymbol = Object.getOwnPropertySymbols(client.transport || client).filter( - (symbol) => symbol.description === 'product check' - )[0]; - // @ts-expect-error `tSymbol` is missing in the index signature of Transport - (client.transport || client)[tSymbol] = 2; -} diff --git a/src/core/server/elasticsearch/client/errors.test.ts b/src/core/server/elasticsearch/client/errors.test.ts index a27a1fa794a97..59c4296d2bbb2 100644 --- a/src/core/server/elasticsearch/client/errors.test.ts +++ b/src/core/server/elasticsearch/client/errors.test.ts @@ -6,12 +6,8 @@ * Side Public License, v 1. */ -import { - ResponseError, - ConnectionError, - ConfigurationError, -} from '@elastic/elasticsearch/lib/errors'; -import { ApiResponse } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { isResponseError, isUnauthorizedError } from './errors'; const createApiResponseError = ({ @@ -22,7 +18,7 @@ const createApiResponseError = ({ statusCode?: number; headers?: Record; body?: Record; -} = {}): ApiResponse => { +} = {}): TransportResult => { return { body, statusCode, @@ -34,38 +30,42 @@ const createApiResponseError = ({ describe('isResponseError', () => { it('returns `true` when the input is a `ResponseError`', () => { - expect(isResponseError(new ResponseError(createApiResponseError()))).toBe(true); + expect(isResponseError(new errors.ResponseError(createApiResponseError()))).toBe(true); }); it('returns `false` when the input is not a `ResponseError`', () => { expect(isResponseError(new Error('foo'))).toBe(false); - expect(isResponseError(new ConnectionError('error', createApiResponseError()))).toBe(false); - expect(isResponseError(new ConfigurationError('foo'))).toBe(false); + expect(isResponseError(new errors.ConnectionError('error', createApiResponseError()))).toBe( + false + ); + expect(isResponseError(new errors.ConfigurationError('foo'))).toBe(false); }); }); describe('isUnauthorizedError', () => { it('returns true when the input is a `ResponseError` and statusCode === 401', () => { expect( - isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 401 }))) + isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 401 }))) ).toBe(true); }); it('returns false when the input is a `ResponseError` and statusCode !== 401', () => { expect( - isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 200 }))) + isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 200 }))) ).toBe(false); expect( - isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 403 }))) + isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 403 }))) ).toBe(false); expect( - isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 500 }))) + isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 500 }))) ).toBe(false); }); it('returns `false` when the input is not a `ResponseError`', () => { expect(isUnauthorizedError(new Error('foo'))).toBe(false); - expect(isUnauthorizedError(new ConnectionError('error', createApiResponseError()))).toBe(false); - expect(isUnauthorizedError(new ConfigurationError('foo'))).toBe(false); + expect(isUnauthorizedError(new errors.ConnectionError('error', createApiResponseError()))).toBe( + false + ); + expect(isUnauthorizedError(new errors.ConfigurationError('foo'))).toBe(false); }); }); diff --git a/src/core/server/elasticsearch/client/errors.ts b/src/core/server/elasticsearch/client/errors.ts index 356c2e370c471..21452af770ff4 100644 --- a/src/core/server/elasticsearch/client/errors.ts +++ b/src/core/server/elasticsearch/client/errors.ts @@ -6,14 +6,14 @@ * Side Public License, v 1. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; -export type UnauthorizedError = ResponseError & { +export type UnauthorizedError = errors.ResponseError & { statusCode: 401; }; -export function isResponseError(error: unknown): error is ResponseError { - return error instanceof ResponseError; +export function isResponseError(error: unknown): error is errors.ResponseError { + return error instanceof errors.ResponseError; } export function isUnauthorizedError(error: unknown): error is UnauthorizedError { diff --git a/src/core/server/elasticsearch/client/index.ts b/src/core/server/elasticsearch/client/index.ts index 29f8b85695190..2cf5a0229a489 100644 --- a/src/core/server/elasticsearch/client/index.ts +++ b/src/core/server/elasticsearch/client/index.ts @@ -14,6 +14,7 @@ export type { SearchResponse, GetResponse, DeleteDocumentResponse, + ElasticsearchErrorDetails, } from './types'; export { ScopedClusterClient } from './scoped_cluster_client'; export type { IScopedClusterClient } from './scoped_cluster_client'; diff --git a/src/core/server/elasticsearch/client/mocks.test.ts b/src/core/server/elasticsearch/client/mocks.test.ts index e3619e094c8cb..30b50e19f6c7e 100644 --- a/src/core/server/elasticsearch/client/mocks.test.ts +++ b/src/core/server/elasticsearch/client/mocks.test.ts @@ -39,9 +39,9 @@ describe('Mocked client', () => { }); it('used EventEmitter functions should be mocked', () => { - expectMocked(client.on); - expectMocked(client.off); - expectMocked(client.once); + expectMocked(client.diagnostic.on); + expectMocked(client.diagnostic.off); + expectMocked(client.diagnostic.once); }); it('`child` should be mocked and return a mocked Client', () => { diff --git a/src/core/server/elasticsearch/client/mocks.ts b/src/core/server/elasticsearch/client/mocks.ts index 7c4cde1ae424d..16eaf6c49a735 100644 --- a/src/core/server/elasticsearch/client/mocks.ts +++ b/src/core/server/elasticsearch/client/mocks.ts @@ -6,36 +6,33 @@ * Side Public License, v 1. */ -import type { Client, ApiResponse } from '@elastic/elasticsearch'; -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; +import type { TransportResult } from '@elastic/elasticsearch'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; +import type { PublicKeys } from '@kbn/utility-types'; import { ElasticsearchClient } from './types'; import { ICustomClusterClient } from './cluster_client'; -import { PRODUCT_RESPONSE_HEADER } from '../supported_server_response_check'; + +const omittedProps = [ + 'diagnostic', + 'name', + 'connectionPool', + 'transport', + 'serializer', + 'helpers', +] as Array>; + +// the product header expected in every response from es +const PRODUCT_RESPONSE_HEADER = 'x-elastic-product'; // use jest.requireActual() to prevent weird errors when people mock @elastic/elasticsearch const { Client: UnmockedClient } = jest.requireActual('@elastic/elasticsearch'); - -const createInternalClientMock = ( - res?: MockedTransportRequestPromise -): DeeplyMockedKeys => { +const createInternalClientMock = (res?: Promise): DeeplyMockedKeys => { // we mimic 'reflection' on a concrete instance of the client to generate the mocked functions. const client = new UnmockedClient({ - node: 'http://localhost', + node: 'http://127.0.0.1', }); - const omittedProps = [ - '_events', - '_eventsCount', - '_maxListeners', - 'constructor', - 'name', - 'serializer', - 'connectionPool', - 'transport', - 'helpers', - ]; - const getAllPropertyDescriptors = (obj: Record) => { const descriptors = Object.entries(Object.getOwnPropertyDescriptors(obj)); let prototype = Object.getPrototypeOf(obj); @@ -77,21 +74,21 @@ const createInternalClientMock = ( }; // `on`, `off`, and `once` are properties without a setter. - // We can't `client.on = jest.fn()` because the following error will be thrown: + // We can't `client.diagnostic.on = jest.fn()` because the following error will be thrown: // TypeError: Cannot set property on of # which has only a getter - mockGetter(client, 'on'); - mockGetter(client, 'off'); - mockGetter(client, 'once'); + mockGetter(client.diagnostic, 'on'); + mockGetter(client.diagnostic, 'off'); + mockGetter(client.diagnostic, 'once'); client.transport = { request: jest.fn(), }; - return client as DeeplyMockedKeys; + return client as DeeplyMockedKeys; }; export type ElasticsearchClientMock = DeeplyMockedKeys; -const createClientMock = (res?: MockedTransportRequestPromise): ElasticsearchClientMock => +const createClientMock = (res?: Promise): ElasticsearchClientMock => createInternalClientMock(res) as unknown as ElasticsearchClientMock; export interface ScopedClusterClientMock { @@ -139,31 +136,23 @@ const createCustomClusterClientMock = () => { return mock; }; -export type MockedTransportRequestPromise = TransportRequestPromise & { - abort: jest.MockedFunction<() => undefined>; -}; - const createSuccessTransportRequestPromise = ( body: T, { statusCode = 200 }: { statusCode?: number } = {}, headers: Record = { [PRODUCT_RESPONSE_HEADER]: 'Elasticsearch' } -): MockedTransportRequestPromise> => { +): Promise> => { const response = createApiResponse({ body, statusCode, headers }); - const promise = Promise.resolve(response); - (promise as MockedTransportRequestPromise>).abort = jest.fn(); - return promise as MockedTransportRequestPromise>; + return Promise.resolve(response) as Promise>; }; -const createErrorTransportRequestPromise = (err: any): MockedTransportRequestPromise => { - const promise = Promise.reject(err); - (promise as MockedTransportRequestPromise).abort = jest.fn(); - return promise as MockedTransportRequestPromise; +const createErrorTransportRequestPromise = (err: any): Promise> => { + return Promise.reject(err); }; function createApiResponse>( - opts: Partial> = {} -): ApiResponse { + opts: Partial> = {} +): TransportResult { return { body: {} as any, statusCode: 200, diff --git a/src/core/server/elasticsearch/client/types.ts b/src/core/server/elasticsearch/client/types.ts index f5a6fa1f0b1fd..e168a4a4a9c21 100644 --- a/src/core/server/elasticsearch/client/types.ts +++ b/src/core/server/elasticsearch/client/types.ts @@ -6,13 +6,12 @@ * Side Public License, v 1. */ -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import type { - ApiResponse, + TransportResult, TransportRequestOptions, TransportRequestParams, - TransportRequestPromise, -} from '@elastic/elasticsearch/lib/Transport'; +} from '@elastic/elasticsearch'; /** * Client used to query the elasticsearch cluster. @@ -21,13 +20,13 @@ import type { */ export type ElasticsearchClient = Omit< KibanaClient, - 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' + 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' | 'diagnostic' > & { transport: { - request( + request( params: TransportRequestParams, options?: TransportRequestOptions - ): TransportRequestPromise; + ): Promise>; }; }; @@ -133,3 +132,10 @@ export interface DeleteDocumentResponse { type: string; }; } + +/** + * @public + */ +export interface ElasticsearchErrorDetails { + error?: { type: string; reason?: string }; +} diff --git a/src/core/server/elasticsearch/index.ts b/src/core/server/elasticsearch/index.ts index 7f0620a03e5f4..cf7d8a0ce0de2 100644 --- a/src/core/server/elasticsearch/index.ts +++ b/src/core/server/elasticsearch/index.ts @@ -35,10 +35,6 @@ export type { ShardsResponse, GetResponse, DeleteDocumentResponse, + ElasticsearchErrorDetails, } from './client'; export { getRequestDebugMeta, getErrorMessage } from './client'; -export { - isSupportedEsServer, - isNotFoundFromUnsupportedServer, - PRODUCT_RESPONSE_HEADER, -} from './supported_server_response_check'; diff --git a/src/core/server/elasticsearch/integration_tests/client.test.ts b/src/core/server/elasticsearch/integration_tests/client.test.ts index f3c9cf27d3b29..05100564dac03 100644 --- a/src/core/server/elasticsearch/integration_tests/client.test.ts +++ b/src/core/server/elasticsearch/integration_tests/client.test.ts @@ -52,17 +52,6 @@ describe('elasticsearch clients', () => { ); expect(resp2.headers).not.toHaveProperty('warning'); }); - - it('returns deprecation warning when x-elastic-product-orign header is not set', async () => { - const resp = - await kibanaServer.coreStart.elasticsearch.client.asInternalUser.indices.getSettings( - { index: '.kibana' }, - { headers: { 'x-elastic-product-origin': null } } - ); - - expect(resp.headers).toHaveProperty('warning'); - expect(resp.headers!.warning).toMatch('system indices'); - }); }); function createFakeElasticsearchServer() { diff --git a/src/core/server/elasticsearch/is_scripting_enabled.test.ts b/src/core/server/elasticsearch/is_scripting_enabled.test.ts index 6dfb4b13edb9f..dd84c29818556 100644 --- a/src/core/server/elasticsearch/is_scripting_enabled.test.ts +++ b/src/core/server/elasticsearch/is_scripting_enabled.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchServiceMock } from './elasticsearch_service.mock'; import { isInlineScriptingEnabled } from './is_scripting_enabled'; diff --git a/src/core/server/elasticsearch/supported_server_response_check.test.ts b/src/core/server/elasticsearch/supported_server_response_check.test.ts deleted file mode 100644 index 589e947142fc3..0000000000000 --- a/src/core/server/elasticsearch/supported_server_response_check.test.ts +++ /dev/null @@ -1,41 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { isNotFoundFromUnsupportedServer } from './supported_server_response_check'; - -describe('#isNotFoundFromUnsupportedServer', () => { - it('returns true with not found response from unsupported server', () => { - const rawResponse = { - statusCode: 404, - headers: {}, - }; - - const result = isNotFoundFromUnsupportedServer(rawResponse); - expect(result).toBe(true); - }); - - it('returns false with not found response from supported server', async () => { - const rawResponse = { - statusCode: 404, - headers: { 'x-elastic-product': 'Elasticsearch' }, - }; - - const result = isNotFoundFromUnsupportedServer(rawResponse); - expect(result).toBe(false); - }); - - it('returns false when not a 404', async () => { - const rawResponse = { - statusCode: 200, - headers: { 'x-elastic-product': 'Elasticsearch' }, - }; - - const result = isNotFoundFromUnsupportedServer(rawResponse); - expect(result).toBe(false); - }); -}); diff --git a/src/core/server/elasticsearch/supported_server_response_check.ts b/src/core/server/elasticsearch/supported_server_response_check.ts deleted file mode 100644 index 85235d04caf5c..0000000000000 --- a/src/core/server/elasticsearch/supported_server_response_check.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -export const PRODUCT_RESPONSE_HEADER = 'x-elastic-product'; -/** - * Response headers check to determine if the response is from Elasticsearch - * @param headers Response headers - * @returns boolean - */ -// This check belongs to the elasticsearch service as a dedicated helper method. -export const isSupportedEsServer = (headers: Record | null) => { - return !!headers && headers[PRODUCT_RESPONSE_HEADER] === 'Elasticsearch'; -}; - -/** - * Check to ensure that a 404 response does not come from Elasticsearch - * - * WARNING: This is a hack to work around for 404 responses returned from a proxy. - * We're aiming to minimise the risk of data loss when consumers act on Not Found errors - * - * @param response response from elasticsearch client call - * @returns boolean 'true' if the status code is 404 and the Elasticsearch product header is missing/unexpected value - */ -export const isNotFoundFromUnsupportedServer = (args: { - statusCode: number | null; - headers: Record | null; -}): boolean => { - return args.statusCode === 404 && !isSupportedEsServer(args.headers); -}; diff --git a/src/core/server/elasticsearch/version_check/ensure_es_version.test.ts b/src/core/server/elasticsearch/version_check/ensure_es_version.test.ts index 70166704679fe..c9bb82d5da65c 100644 --- a/src/core/server/elasticsearch/version_check/ensure_es_version.test.ts +++ b/src/core/server/elasticsearch/version_check/ensure_es_version.test.ts @@ -139,6 +139,7 @@ describe('pollEsNodesVersion', () => { }); const nodeInfosSuccessOnce = (infos: NodesInfo) => { + // @ts-expect-error not full interface internalClient.nodes.info.mockImplementationOnce(() => createEsSuccess(infos)); }; const nodeInfosErrorOnce = (error: any) => { diff --git a/src/core/server/http/integration_tests/core_services.test.ts b/src/core/server/http/integration_tests/core_services.test.ts index 84eed0511cb23..4bf64a96cf773 100644 --- a/src/core/server/http/integration_tests/core_services.test.ts +++ b/src/core/server/http/integration_tests/core_services.test.ts @@ -8,7 +8,7 @@ import { MockElasticsearchClient } from './core_service.test.mocks'; import { elasticsearchClientMock } from '../../elasticsearch/client/mocks'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import * as kbnTestServer from '../../../test_helpers/kbn_server'; import { InternalElasticsearchServiceStart } from '../../elasticsearch'; @@ -205,7 +205,7 @@ describe('http service', () => { esClient.ping.mockImplementation(() => elasticsearchClientMock.createErrorTransportRequestPromise( - new ResponseError({ + new errors.ResponseError({ statusCode: 401, body: { error: { @@ -243,7 +243,7 @@ describe('http service', () => { esClient.ping.mockImplementation(() => elasticsearchClientMock.createErrorTransportRequestPromise( - new ResponseError({ + new errors.ResponseError({ statusCode: 401, body: { error: { @@ -279,7 +279,7 @@ describe('http service', () => { esClient.ping.mockImplementation(() => elasticsearchClientMock.createErrorTransportRequestPromise( - new ResponseError({ + new errors.ResponseError({ statusCode: 404, body: { error: { diff --git a/src/core/server/http/router/response_adapter.ts b/src/core/server/http/router/response_adapter.ts index b03449b2ae194..753c11d5f45ae 100644 --- a/src/core/server/http/router/response_adapter.ts +++ b/src/core/server/http/router/response_adapter.ts @@ -15,6 +15,7 @@ import Boom from '@hapi/boom'; import * as stream from 'stream'; import { isResponseError as isElasticsearchResponseError } from '../../elasticsearch/client/errors'; +import { ElasticsearchErrorDetails } from '../../elasticsearch'; import { HttpResponsePayload, @@ -154,7 +155,9 @@ function getErrorMessage(payload?: ResponseError): string { if (typeof payload === 'string') return payload; // for ES response errors include nested error reason message. it doesn't contain sensitive data. if (isElasticsearchResponseError(payload)) { - return `[${payload.message}]: ${payload.meta.body?.error?.reason}`; + return `[${payload.message}]: ${ + (payload.meta.body as ElasticsearchErrorDetails)?.error?.reason + }`; } return getErrorMessage(payload.message); diff --git a/src/core/server/http/router/router.ts b/src/core/server/http/router/router.ts index d2d8dfa2cc72f..be3b24d5d19a7 100644 --- a/src/core/server/http/router/router.ts +++ b/src/core/server/http/router/router.ts @@ -289,10 +289,10 @@ export class Router { const getAuthenticateHeaderValue = () => { - const header = Object.entries(e.headers).find( + const header = Object.entries(e.headers || {}).find( ([key]) => key.toLowerCase() === 'www-authenticate' ); - return header ? header[1] : 'Basic realm="Authorization Required"'; + return header ? (header[1] as string) : 'Basic realm="Authorization Required"'; }; return { body: e.message, diff --git a/src/core/server/index.ts b/src/core/server/index.ts index c92a91c96da95..bb91b9f9be98f 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -136,6 +136,7 @@ export type { GetResponse, DeleteDocumentResponse, ElasticsearchConfigPreboot, + ElasticsearchErrorDetails, } from './elasticsearch'; export type { IExternalUrlConfig, IExternalUrlPolicy } from './external_url'; diff --git a/src/core/server/kibana_config.test.ts b/src/core/server/kibana_config.test.ts deleted file mode 100644 index 72ddb3b65081b..0000000000000 --- a/src/core/server/kibana_config.test.ts +++ /dev/null @@ -1,42 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { config } from './kibana_config'; -import { getDeprecationsFor } from './config/test_utils'; - -const CONFIG_PATH = 'kibana'; - -const applyKibanaDeprecations = (settings: Record = {}) => - getDeprecationsFor({ - provider: config.deprecations!, - settings, - path: CONFIG_PATH, - }); - -it('set correct defaults ', () => { - const configValue = config.schema.validate({}); - expect(configValue).toMatchInlineSnapshot(` - Object { - "enabled": true, - "index": ".kibana", - } - `); -}); - -describe('deprecations', () => { - ['.foo', '.kibana'].forEach((index) => { - it('logs a warning if index is set', () => { - const { messages } = applyKibanaDeprecations({ index }); - expect(messages).toMatchInlineSnapshot(` - Array [ - "\\"kibana.index\\" is deprecated. Multitenancy by changing \\"kibana.index\\" will not be supported starting in 8.0. See https://ela.st/kbn-remove-legacy-multitenancy for more details", - ] - `); - }); - }); -}); diff --git a/src/core/server/kibana_config.ts b/src/core/server/kibana_config.ts deleted file mode 100644 index 859f25d7082f1..0000000000000 --- a/src/core/server/kibana_config.ts +++ /dev/null @@ -1,51 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import { schema, TypeOf } from '@kbn/config-schema'; -import { ConfigDeprecationProvider } from '@kbn/config'; - -export type KibanaConfigType = TypeOf; - -const deprecations: ConfigDeprecationProvider = () => [ - (settings, fromPath, addDeprecation) => { - const kibana = settings[fromPath]; - if (kibana?.index) { - addDeprecation({ - configPath: 'kibana.index', - title: i18n.translate('core.kibana.index.deprecationTitle', { - defaultMessage: `Setting "kibana.index" is deprecated`, - }), - message: i18n.translate('core.kibana.index.deprecationMessage', { - defaultMessage: `"kibana.index" is deprecated. Multitenancy by changing "kibana.index" will not be supported starting in 8.0. See https://ela.st/kbn-remove-legacy-multitenancy for more details`, - }), - documentationUrl: 'https://ela.st/kbn-remove-legacy-multitenancy', - correctiveActions: { - manualSteps: [ - i18n.translate('core.kibana.index.deprecationManualStep1', { - defaultMessage: `If you rely on this setting to achieve multitenancy you should use Spaces, cross-cluster replication, or cross-cluster search instead.`, - }), - i18n.translate('core.kibana.index.deprecationManualStep2', { - defaultMessage: `To migrate to Spaces, we encourage using saved object management to export your saved objects from a tenant into the default tenant in a space.`, - }), - ], - }, - }); - } - return settings; - }, -]; - -export const config = { - path: 'kibana', - schema: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - index: schema.string({ defaultValue: '.kibana' }), - }), - deprecations, -}; diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index 8b4dee45a8e72..a2787369bd534 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -65,9 +65,6 @@ type MockedPluginInitializerConfig = jest.Mocked[ export function pluginInitializerContextConfigMock(config: T) { const globalConfig: SharedGlobalConfig = { - kibana: { - index: '.kibana-tests', - }, elasticsearch: { shardTimeout: duration('30s'), requestTimeout: duration('30s'), diff --git a/src/core/server/plugins/legacy_config.test.ts b/src/core/server/plugins/legacy_config.test.ts index 2a980e38a4e19..af8cff843edf0 100644 --- a/src/core/server/plugins/legacy_config.test.ts +++ b/src/core/server/plugins/legacy_config.test.ts @@ -41,9 +41,6 @@ describe('Legacy config', () => { const legacyConfig = getGlobalConfig(configService); expect(legacyConfig).toStrictEqual({ - kibana: { - index: '.kibana', - }, elasticsearch: { shardTimeout: duration(30, 's'), requestTimeout: duration(30, 's'), @@ -62,9 +59,6 @@ describe('Legacy config', () => { const legacyConfig = await getGlobalConfig$(configService).pipe(take(1)).toPromise(); expect(legacyConfig).toStrictEqual({ - kibana: { - index: '.kibana', - }, elasticsearch: { shardTimeout: duration(30, 's'), requestTimeout: duration(30, 's'), diff --git a/src/core/server/plugins/legacy_config.ts b/src/core/server/plugins/legacy_config.ts index f7e22cb4b376a..9dc4afc37515a 100644 --- a/src/core/server/plugins/legacy_config.ts +++ b/src/core/server/plugins/legacy_config.ts @@ -13,7 +13,6 @@ import { pick, deepFreeze } from '@kbn/std'; import { IConfigService } from '@kbn/config'; import { SharedGlobalConfig, SharedGlobalConfigKeys } from './types'; -import { KibanaConfigType, config as kibanaConfig } from '../kibana_config'; import { ElasticsearchConfigType, config as elasticsearchConfig, @@ -21,18 +20,15 @@ import { import { SavedObjectsConfigType, savedObjectsConfig } from '../saved_objects/saved_objects_config'; const createGlobalConfig = ({ - kibana, elasticsearch, path, savedObjects, }: { - kibana: KibanaConfigType; elasticsearch: ElasticsearchConfigType; path: PathConfigType; savedObjects: SavedObjectsConfigType; }): SharedGlobalConfig => { return deepFreeze({ - kibana: pick(kibana, SharedGlobalConfigKeys.kibana), elasticsearch: pick(elasticsearch, SharedGlobalConfigKeys.elasticsearch), path: pick(path, SharedGlobalConfigKeys.path), savedObjects: pick(savedObjects, SharedGlobalConfigKeys.savedObjects), @@ -41,7 +37,6 @@ const createGlobalConfig = ({ export const getGlobalConfig = (configService: IConfigService): SharedGlobalConfig => { return createGlobalConfig({ - kibana: configService.atPathSync(kibanaConfig.path), elasticsearch: configService.atPathSync(elasticsearchConfig.path), path: configService.atPathSync(pathConfig.path), savedObjects: configService.atPathSync(savedObjectsConfig.path), @@ -50,15 +45,13 @@ export const getGlobalConfig = (configService: IConfigService): SharedGlobalConf export const getGlobalConfig$ = (configService: IConfigService): Observable => { return combineLatest([ - configService.atPath(kibanaConfig.path), configService.atPath(elasticsearchConfig.path), configService.atPath(pathConfig.path), configService.atPath(savedObjectsConfig.path), ]).pipe( map( - ([kibana, elasticsearch, path, savedObjects]) => + ([elasticsearch, path, savedObjects]) => createGlobalConfig({ - kibana, elasticsearch, path, savedObjects, diff --git a/src/core/server/plugins/plugin_context.test.ts b/src/core/server/plugins/plugin_context.test.ts index 00da0fa43c40f..867d4d978314b 100644 --- a/src/core/server/plugins/plugin_context.test.ts +++ b/src/core/server/plugins/plugin_context.test.ts @@ -124,9 +124,6 @@ describe('createPluginInitializerContext', () => { .pipe(first()) .toPromise(); expect(configObject).toStrictEqual({ - kibana: { - index: '.kibana', - }, elasticsearch: { shardTimeout: duration(30, 's'), requestTimeout: duration(30, 's'), diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index bdb4efde9b1fb..28382d62e4ba7 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -197,6 +197,7 @@ export function createPluginSetupContext( setClientFactoryProvider: deps.savedObjects.setClientFactoryProvider, addClientWrapper: deps.savedObjects.addClientWrapper, registerType: deps.savedObjects.registerType, + getKibanaIndex: deps.savedObjects.getKibanaIndex, }, status: { core$: deps.status.core$, diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index a2e460a3e3c67..1d0dc62864fc9 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -13,7 +13,6 @@ import { PathConfigType } from '@kbn/utils'; import { ConfigPath, EnvironmentMode, PackageInfo, ConfigDeprecationProvider } from '../config'; import { LoggerFactory } from '../logging'; -import { KibanaConfigType } from '../kibana_config'; import { ElasticsearchConfigType } from '../elasticsearch/elasticsearch_config'; import { SavedObjectsConfigType } from '../saved_objects/saved_objects_config'; import { CorePreboot, CoreSetup, CoreStart } from '..'; @@ -364,7 +363,6 @@ export interface AsyncPlugin< export const SharedGlobalConfigKeys = { // We can add more if really needed - kibana: ['index'] as const, elasticsearch: ['shardTimeout', 'requestTimeout', 'pingTimeout'] as const, path: ['data'] as const, savedObjects: ['maxImportPayloadBytes'] as const, @@ -374,7 +372,6 @@ export const SharedGlobalConfigKeys = { * @public */ export type SharedGlobalConfig = RecursiveReadonly<{ - kibana: Pick; elasticsearch: Pick; path: Pick; savedObjects: Pick; diff --git a/src/core/server/saved_objects/deprecations/deprecation_factory.ts b/src/core/server/saved_objects/deprecations/deprecation_factory.ts index 670b43bfa7c77..60ee1b0193362 100644 --- a/src/core/server/saved_objects/deprecations/deprecation_factory.ts +++ b/src/core/server/saved_objects/deprecations/deprecation_factory.ts @@ -9,13 +9,12 @@ import type { RegisterDeprecationsConfig } from '../../deprecations'; import type { ISavedObjectTypeRegistry } from '../saved_objects_type_registry'; import type { SavedObjectConfig } from '../saved_objects_config'; -import type { KibanaConfigType } from '../../kibana_config'; import { getUnknownTypesDeprecations } from './unknown_object_types'; interface GetDeprecationProviderOptions { typeRegistry: ISavedObjectTypeRegistry; savedObjectsConfig: SavedObjectConfig; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; } diff --git a/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts b/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts index 1f9ca741691d1..5b2687262ab36 100644 --- a/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts +++ b/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts @@ -8,11 +8,10 @@ import { getIndexForTypeMock } from './unknown_object_types.test.mocks'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { deleteUnknownTypeObjects, getUnknownTypesDeprecations } from './unknown_object_types'; import { typeRegistryMock } from '../saved_objects_type_registry.mock'; import { elasticsearchClientMock } from '../../elasticsearch/client/mocks'; -import type { KibanaConfigType } from '../../kibana_config'; import { SavedObjectsType } from 'kibana/server'; const createSearchResponse = (count: number): estypes.SearchResponse => { @@ -30,7 +29,7 @@ describe('unknown saved object types deprecation', () => { let typeRegistry: ReturnType; let esClient: ReturnType; - let kibanaConfig: KibanaConfigType; + const kibanaIndex = '.kibana'; beforeEach(() => { typeRegistry = typeRegistryMock.create(); @@ -41,11 +40,6 @@ describe('unknown saved object types deprecation', () => { { name: 'bar' }, ] as SavedObjectsType[]); getIndexForTypeMock.mockImplementation(({ type }: { type: string }) => `${type}-index`); - - kibanaConfig = { - index: '.kibana', - enabled: true, - }; }); afterEach(() => { @@ -63,7 +57,7 @@ describe('unknown saved object types deprecation', () => { await getUnknownTypesDeprecations({ esClient, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); @@ -89,7 +83,7 @@ describe('unknown saved object types deprecation', () => { const deprecations = await getUnknownTypesDeprecations({ esClient, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); @@ -104,7 +98,7 @@ describe('unknown saved object types deprecation', () => { const deprecations = await getUnknownTypesDeprecations({ esClient, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); @@ -132,7 +126,7 @@ describe('unknown saved object types deprecation', () => { await deleteUnknownTypeObjects({ esClient, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); diff --git a/src/core/server/saved_objects/deprecations/unknown_object_types.ts b/src/core/server/saved_objects/deprecations/unknown_object_types.ts index 8cd650bac8a2d..8815065984a27 100644 --- a/src/core/server/saved_objects/deprecations/unknown_object_types.ts +++ b/src/core/server/saved_objects/deprecations/unknown_object_types.ts @@ -6,19 +6,18 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import type { DeprecationsDetails } from '../../deprecations'; import { IScopedClusterClient } from '../../elasticsearch'; import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry'; import { SavedObjectsRawDocSource } from '../serialization'; -import type { KibanaConfigType } from '../../kibana_config'; import { getIndexForType } from '../service/lib'; interface UnknownTypesDeprecationOptions { typeRegistry: ISavedObjectTypeRegistry; esClient: IScopedClusterClient; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; } @@ -29,11 +28,11 @@ const getTargetIndices = ({ types, typeRegistry, kibanaVersion, - kibanaConfig, + kibanaIndex, }: { types: string[]; typeRegistry: ISavedObjectTypeRegistry; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; }) => { return [ @@ -43,7 +42,7 @@ const getTargetIndices = ({ type, typeRegistry, kibanaVersion, - defaultIndex: kibanaConfig.index, + defaultIndex: kibanaIndex, }) ) ), @@ -63,14 +62,14 @@ const getUnknownTypesQuery = (knownTypes: string[]): estypes.QueryDslQueryContai const getUnknownSavedObjects = async ({ typeRegistry, esClient, - kibanaConfig, + kibanaIndex, kibanaVersion, }: UnknownTypesDeprecationOptions) => { const knownTypes = getKnownTypes(typeRegistry); const targetIndices = getTargetIndices({ types: knownTypes, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); const query = getUnknownTypesQuery(knownTypes); @@ -133,21 +132,21 @@ export const getUnknownTypesDeprecations = async ( interface DeleteUnknownTypesOptions { typeRegistry: ISavedObjectTypeRegistry; esClient: IScopedClusterClient; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; } export const deleteUnknownTypeObjects = async ({ esClient, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }: DeleteUnknownTypesOptions) => { const knownTypes = getKnownTypes(typeRegistry); const targetIndices = getTargetIndices({ types: knownTypes, typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); const query = getUnknownTypesQuery(knownTypes); diff --git a/src/core/server/saved_objects/mappings/types.ts b/src/core/server/saved_objects/mappings/types.ts index e2ad2a91fd000..e225d0ff31022 100644 --- a/src/core/server/saved_objects/mappings/types.ts +++ b/src/core/server/saved_objects/mappings/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /** * Describe a saved object type mapping. * diff --git a/src/core/server/saved_objects/migrations/core/call_cluster.ts b/src/core/server/saved_objects/migrations/core/call_cluster.ts index d158bf7d131f5..156689c8d96f9 100644 --- a/src/core/server/saved_objects/migrations/core/call_cluster.ts +++ b/src/core/server/saved_objects/migrations/core/call_cluster.ts @@ -12,7 +12,7 @@ * funcationality contained here. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type AliasAction = | { diff --git a/src/core/server/saved_objects/migrations/core/elastic_index.test.ts b/src/core/server/saved_objects/migrations/core/elastic_index.test.ts index 15bd1d46b092b..2cdeb479f50f9 100644 --- a/src/core/server/saved_objects/migrations/core/elastic_index.test.ts +++ b/src/core/server/saved_objects/migrations/core/elastic_index.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import _ from 'lodash'; import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import * as Index from './elastic_index'; @@ -164,7 +164,7 @@ describe('ElasticIndex', () => { client.tasks.get.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ completed: true, - } as estypes.TaskGetResponse) + } as estypes.TasksGetResponse) ); const info = { @@ -248,7 +248,7 @@ describe('ElasticIndex', () => { reason: 'all shards failed', failed_shards: [], }, - } as estypes.TaskGetResponse) + } as estypes.TasksGetResponse) ); const info = { diff --git a/src/core/server/saved_objects/migrations/core/elastic_index.ts b/src/core/server/saved_objects/migrations/core/elastic_index.ts index dc98139ad513e..64df079897722 100644 --- a/src/core/server/saved_objects/migrations/core/elastic_index.ts +++ b/src/core/server/saved_objects/migrations/core/elastic_index.ts @@ -12,7 +12,7 @@ */ import _ from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { MigrationEsClient } from './migration_es_client'; import { IndexMapping } from '../../mappings'; import { SavedObjectsMigrationVersion } from '../../types'; diff --git a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts index 64d4fa3609e90..beb0c1d3651c6 100644 --- a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts @@ -7,7 +7,7 @@ */ import _ from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization'; import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; @@ -450,7 +450,7 @@ function withIndex( client.tasks.get.mockReturnValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ completed: true, - } as estypes.TaskGetResponse) + } as estypes.TasksGetResponse) ); client.search.mockReturnValue( elasticsearchClientMock.createSuccessTransportRequestPromise(searchResult(0) as any) diff --git a/src/core/server/saved_objects/migrations/core/migration_es_client.ts b/src/core/server/saved_objects/migrations/core/migration_es_client.ts index e8dc9c94b7861..243b724eb2a67 100644 --- a/src/core/server/saved_objects/migrations/core/migration_es_client.ts +++ b/src/core/server/saved_objects/migrations/core/migration_es_client.ts @@ -5,8 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import type { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; +import type { Client, TransportRequestOptions } from '@elastic/elasticsearch'; import { get } from 'lodash'; import { set } from '@elastic/safer-lodash-set'; @@ -58,7 +57,7 @@ export interface MigrationEsClient { } export function createMigrationEsClient( - client: ElasticsearchClient, + client: ElasticsearchClient | Client, log: Logger, delay?: number ): MigrationEsClient { @@ -69,7 +68,7 @@ export function createMigrationEsClient( throw new Error(`unknown ElasticsearchClient client method [${key}]`); } return await migrationRetryCallCluster( - () => fn.call(client, params, { maxRetries: 0, ...options }), + () => fn.call(client, params, { maxRetries: 0, meta: true, ...options }), log, delay ); diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts index c397559b52570..599b5dca0d904 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts @@ -7,7 +7,7 @@ */ import { take } from 'rxjs/operators'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { KibanaMigratorOptions, KibanaMigrator } from './kibana_migrator'; @@ -16,6 +16,7 @@ import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { SavedObjectsType } from '../../types'; import { DocumentMigrator } from '../core/document_migrator'; import { ByteSizeValue } from '@kbn/config-schema'; + jest.mock('../core/document_migrator', () => { return { // Create a mock for spying on the constructor @@ -251,7 +252,7 @@ const mockV2MigrationOptions = () => { error: undefined, failures: [], task: { description: 'task description' } as any, - } as estypes.TaskGetResponse) + } as estypes.TasksGetResponse) ); options.client.search = jest @@ -304,10 +305,7 @@ const mockOptions = () => { migrations: {}, }, ]), - kibanaConfig: { - enabled: true, - index: '.my-index', - } as KibanaMigratorOptions['kibanaConfig'], + kibanaIndex: '.my-index', soMigrationsConfig: { batchSize: 20, maxBatchSizeBytes: ByteSizeValue.parse('20mb'), diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts index d3755f8c7e666..a812339cef07e 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts @@ -13,7 +13,6 @@ import { BehaviorSubject } from 'rxjs'; import Semver from 'semver'; -import { KibanaConfigType } from '../../../kibana_config'; import { ElasticsearchClient } from '../../../elasticsearch'; import { Logger } from '../../../logging'; import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings'; @@ -35,7 +34,7 @@ export interface KibanaMigratorOptions { client: ElasticsearchClient; typeRegistry: ISavedObjectTypeRegistry; soMigrationsConfig: SavedObjectsMigrationConfigType; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; logger: Logger; migrationsRetryDelay?: number; @@ -55,7 +54,7 @@ export interface KibanaMigratorStatus { export class KibanaMigrator { private readonly client: ElasticsearchClient; private readonly documentMigrator: VersionedTransformer; - private readonly kibanaConfig: KibanaConfigType; + private readonly kibanaIndex: string; private readonly log: Logger; private readonly mappingProperties: SavedObjectsTypeMappingDefinitions; private readonly typeRegistry: ISavedObjectTypeRegistry; @@ -76,14 +75,14 @@ export class KibanaMigrator { constructor({ client, typeRegistry, - kibanaConfig, + kibanaIndex, soMigrationsConfig, kibanaVersion, logger, migrationsRetryDelay, }: KibanaMigratorOptions) { this.client = client; - this.kibanaConfig = kibanaConfig; + this.kibanaIndex = kibanaIndex; this.soMigrationsConfig = soMigrationsConfig; this.typeRegistry = typeRegistry; this.serializer = new SavedObjectsSerializer(this.typeRegistry); @@ -148,9 +147,8 @@ export class KibanaMigrator { } private runMigrationsInternal() { - const kibanaIndexName = this.kibanaConfig.index; const indexMap = createIndexMap({ - kibanaIndexName, + kibanaIndexName: this.kibanaIndex, indexMap: this.mappingProperties, registry: this.typeRegistry, }); diff --git a/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts b/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts index 9353ede9be6ac..f3ddc0c308970 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts @@ -8,7 +8,8 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { errors as esErrors, estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { errors as esErrors } from '@elastic/elasticsearch'; import { ElasticsearchClient } from '../../../elasticsearch'; import type { SavedObjectsRawDoc } from '../../serialization'; import { @@ -92,7 +93,7 @@ export const bulkOverwriteTransformedDocuments = .then((res) => { // Filter out version_conflict_engine_exception since these just mean // that another instance already updated these documents - const errors = (res.body.items ?? []) + const errors: estypes.ErrorCause[] = (res.body.items ?? []) .filter((item) => item.index?.error) .map((item) => item.index!.error!) .filter(({ type }) => type !== 'version_conflict_engine_exception'); diff --git a/src/core/server/saved_objects/migrationsv2/actions/calculate_exclude_filters.ts b/src/core/server/saved_objects/migrationsv2/actions/calculate_exclude_filters.ts index 9ba098d01870f..2b35e3b59e988 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/calculate_exclude_filters.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/calculate_exclude_filters.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { withTimeout } from '@kbn/std'; import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; diff --git a/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.ts b/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.ts index 3d9a51e3b1eba..168e3170d30bf 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.ts @@ -31,7 +31,7 @@ export const catchRetryableEsClientErrors = ( e instanceof EsErrors.ConnectionError || e instanceof EsErrors.TimeoutError || (e instanceof EsErrors.ResponseError && - (retryResponseStatuses.includes(e?.statusCode) || + (retryResponseStatuses.includes(e?.statusCode!) || // ES returns a 400 Bad Request when trying to close or delete an // index while snapshots are in progress. This should have been a 503 // so once https://github.com/elastic/elasticsearch/issues/65883 is diff --git a/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.test.ts b/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.test.ts index a52cb2a922968..8a99d28b40de1 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.test.ts @@ -8,7 +8,8 @@ import * as Either from 'fp-ts/lib/Either'; import { catchRetryableEsClientErrors } from './catch_retryable_es_client_errors'; -import { errors as EsErrors, estypes } from '@elastic/elasticsearch'; +import { errors as EsErrors } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { checkForUnknownDocs } from './check_for_unknown_docs'; diff --git a/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.ts b/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.ts index 1db47f0083467..cfeda0548b16a 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/check_for_unknown_docs.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SavedObjectsRawDocSource } from '../../serialization'; import { ElasticsearchClient } from '../../../elasticsearch'; import { diff --git a/src/core/server/saved_objects/migrationsv2/actions/create_index.ts b/src/core/server/saved_objects/migrationsv2/actions/create_index.ts index d5269233344c3..9fa8aebcd7dc1 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/create_index.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/create_index.ts @@ -9,7 +9,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; import { pipe } from 'fp-ts/lib/pipeable'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AcknowledgeResponse } from './index'; import { ElasticsearchClient } from '../../../elasticsearch'; import { IndexMapping } from '../../mappings'; @@ -100,7 +100,7 @@ export const createIndex = ({ * - acknowledged=true, shards_acknowledged=true, index creation complete */ return Either.right({ - acknowledged: res.body.acknowledged, + acknowledged: Boolean(res.body.acknowledged), shardsAcknowledged: res.body.shards_acknowledged, }); }) diff --git a/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts b/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts index 49b996bb118d8..4f560468bcb0c 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts @@ -5,23 +5,19 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -export interface EsErrorCause { - type: string; - reason: string; -} - -export const isWriteBlockException = ({ type, reason }: EsErrorCause): boolean => { +export const isWriteBlockException = ({ type, reason }: estypes.ErrorCause): boolean => { return ( type === 'cluster_block_exception' && reason.match(/index \[.+] blocked by: \[FORBIDDEN\/8\/.+ \(api\)\]/) !== null ); }; -export const isIncompatibleMappingException = ({ type }: EsErrorCause): boolean => { +export const isIncompatibleMappingException = ({ type }: estypes.ErrorCause): boolean => { return type === 'strict_dynamic_mapping_exception' || type === 'mapper_parsing_exception'; }; -export const isIndexNotFoundException = ({ type }: EsErrorCause): boolean => { +export const isIndexNotFoundException = ({ type }: estypes.ErrorCause): boolean => { return type === 'index_not_found_exception'; }; diff --git a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts index 0a5864dcefac2..3ca3a8505338b 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts @@ -38,7 +38,7 @@ import { } from '../../actions'; import * as Either from 'fp-ts/lib/Either'; import * as Option from 'fp-ts/lib/Option'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { DocumentsTransformFailed, DocumentsTransformSuccess } from '../../../migrations/core'; import { TaskEither } from 'fp-ts/lib/TaskEither'; import Path from 'path'; @@ -61,7 +61,7 @@ describe.skip('migration actions', () => { beforeAll(async () => { esServer = await startES(); - client = esServer.es.getClient(); + client = esServer.es.getKibanaEsClient(); // Create test fixture data: await createIndex({ @@ -281,7 +281,7 @@ describe.skip('migration actions', () => { index: 'red_then_yellow_index', body: { // Enable all shard allocation so that the index status turns yellow - settings: { routing: { allocation: { enable: 'all' } } }, + routing: { allocation: { enable: 'all' } }, }, }); @@ -351,7 +351,7 @@ describe.skip('migration actions', () => { index: 'clone_red_then_yellow_index', body: { // Enable all shard allocation so that the index status goes yellow - settings: { routing: { allocation: { enable: 'all' } } }, + routing: { allocation: { enable: 'all' } }, }, }); indexYellow = true; @@ -413,7 +413,7 @@ describe.skip('migration actions', () => { await expect(cloneIndexPromise).resolves.toMatchObject({ _tag: 'Left', left: { - error: expect.any(ResponseError), + error: expect.any(errors.ResponseError), message: expect.stringMatching(/\"timed_out\":true/), type: 'retryable_es_client_error', }, @@ -811,7 +811,7 @@ describe.skip('migration actions', () => { await expect(task()).resolves.toMatchObject({ _tag: 'Left', left: { - error: expect.any(ResponseError), + error: expect.any(errors.ResponseError), message: expect.stringMatching( /\[timeout_exception\] Timed out waiting for completion of \[org.elasticsearch.index.reindex.BulkByScrollTask/ ), @@ -1170,7 +1170,7 @@ describe.skip('migration actions', () => { await expect(task()).resolves.toMatchObject({ _tag: 'Left', left: { - error: expect.any(ResponseError), + error: expect.any(errors.ResponseError), message: expect.stringMatching( /\[timeout_exception\] Timed out waiting for completion of \[org.elasticsearch.index.reindex.BulkByScrollTask/ ), @@ -1445,7 +1445,7 @@ describe.skip('migration actions', () => { index: 'red_then_yellow_index', body: { // Disable all shard allocation so that the index status is red - settings: { routing: { allocation: { enable: 'all' } } }, + routing: { allocation: { enable: 'all' } }, }, }); indexYellow = true; diff --git a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/es_errors.test.ts b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/es_errors.test.ts index e259b375736d5..2473d8d3ae410 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/es_errors.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/es_errors.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '../../../../'; import { InternalCoreStart } from '../../../../internal_types'; import * as kbnTestServer from '../../../../../test_helpers/kbn_server'; @@ -100,7 +100,7 @@ describe('Elasticsearch Errors', () => { ], }); - const cause = res.body.items[0].index!.error!; + const cause = res.body.items[0].index!.error! as estypes.ErrorCause; expect(isWriteBlockException(cause)).toEqual(true); }); @@ -122,7 +122,7 @@ describe('Elasticsearch Errors', () => { ], }); - const cause = res.body.items[0].create!.error!; + const cause = res.body.items[0].create!.error! as estypes.ErrorCause; expect(isWriteBlockException(cause)).toEqual(true); }); diff --git a/src/core/server/saved_objects/migrationsv2/actions/read_with_pit.ts b/src/core/server/saved_objects/migrationsv2/actions/read_with_pit.ts index c8e7d61dce811..0902e206147d3 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/read_with_pit.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/read_with_pit.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '../../../elasticsearch'; import type { SavedObjectsRawDoc } from '../../serialization'; import { diff --git a/src/core/server/saved_objects/migrationsv2/actions/reindex.ts b/src/core/server/saved_objects/migrationsv2/actions/reindex.ts index 92134d2755ac3..e8e054c7a1780 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/reindex.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/reindex.ts @@ -9,7 +9,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as Option from 'fp-ts/lib/Option'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '../../../elasticsearch'; import { catchRetryableEsClientErrors, diff --git a/src/core/server/saved_objects/migrationsv2/actions/remove_write_block.ts b/src/core/server/saved_objects/migrationsv2/actions/remove_write_block.ts index 77445654d3cc3..cca9ea5e7598e 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/remove_write_block.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/remove_write_block.ts @@ -41,10 +41,8 @@ export const removeWriteBlock = // Don't change any existing settings preserve_existing: true, body: { - settings: { - blocks: { - write: false, - }, + blocks: { + write: false, }, }, }, diff --git a/src/core/server/saved_objects/migrationsv2/actions/search_for_outdated_documents.ts b/src/core/server/saved_objects/migrationsv2/actions/search_for_outdated_documents.ts index 5a6cb3a3d048d..5a92a7c6cc286 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/search_for_outdated_documents.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/search_for_outdated_documents.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '../../../elasticsearch'; import type { SavedObjectsRawDoc, SavedObjectsRawDocSource } from '../../serialization'; import { diff --git a/src/core/server/saved_objects/migrationsv2/actions/set_write_block.ts b/src/core/server/saved_objects/migrationsv2/actions/set_write_block.ts index db519d0246511..9c40e1b64fae0 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/set_write_block.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/set_write_block.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import type { ElasticsearchClientError } from '@elastic/elasticsearch/lib/errors'; import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; import { errors as EsErrors } from '@elastic/elasticsearch'; @@ -61,7 +60,7 @@ export const setWriteBlock = message: 'set_write_block_failed', }); }) - .catch((e: ElasticsearchClientError) => { + .catch((e: EsErrors.ElasticsearchClientError) => { if (e instanceof EsErrors.ResponseError) { if (e.body?.error?.type === 'index_not_found_exception') { return Either.left({ type: 'index_not_found_exception' as const, index }); diff --git a/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts b/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts index 212e1ad9c8c81..1a319d17dbce9 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts @@ -5,6 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as Option from 'fp-ts/lib/Option'; @@ -86,7 +87,7 @@ export const waitForTask = const failures = body.response?.failures ?? []; return Either.right({ completed: body.completed, - error: Option.fromNullable(body.error), + error: Option.fromNullable(body.error as estypes.ErrorCauseKeys), failures: failures.length > 0 ? Option.some(failures) : Option.none, description: body.task.description, }); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts index a4ce95a9e0584..479b1e78e1b72 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts @@ -55,7 +55,7 @@ describe('migration from 7.13 to 7.14+ with many failed action_tasks', () => { kibanaIndexName = '.kibana', taskManagerIndexName = '.kibana_task_manager' ): Promise<{ tasksCount: number; actionTaskParamsCount: number }> => { - const esClient: ElasticsearchClient = esServer.es.getClient(); + const esClient: ElasticsearchClient = esServer.es.getKibanaEsClient(); const actionTaskParamsResponse = await esClient.count({ index: kibanaIndexName, diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts index a04300ffea626..aea84cea22862 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts @@ -8,7 +8,7 @@ import Path from 'path'; import fs from 'fs/promises'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as kbnTestServer from '../../../../test_helpers/kbn_server'; import { Root } from '../../../root'; import JSON5 from 'json5'; @@ -114,7 +114,7 @@ describe('migration v2', () => { ); }); - const client: ElasticsearchClient = esServer.es.getClient(); + const client: ElasticsearchClient = esServer.es.getKibanaEsClient(); const { body: response } = await client.indices.getSettings({ index: targetIndex, }); @@ -178,7 +178,7 @@ describe('migration v2', () => { }); await root.start(); - const client: ElasticsearchClient = esServer.es.getClient(); + const client: ElasticsearchClient = esServer.es.getKibanaEsClient(); const spacesDocsMigrated = await fetchDocs(client, targetIndex, 'space'); expect(spacesDocsMigrated.map((s) => s.id)).toEqual( expect.arrayContaining([ diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts index de25c7b1c6412..e444a3b1a8bdb 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts @@ -95,7 +95,7 @@ describe('migration v2', () => { // wait a bit for the count to settle. await new Promise((resolve) => setTimeout(resolve, 5000)); - const esClient: ElasticsearchClient = esServer.es.getClient(); + const esClient: ElasticsearchClient = esServer.es.getKibanaEsClient(); // assert that the docs from the original index have been migrated rather than comparing a doc count after startup const originalDocs = await fetchDocuments(esClient, '.kibana_7.14.0_001'); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts index b47156e3a1e9e..d992193730a34 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts @@ -20,7 +20,8 @@ async function removeLogFile() { await fs.unlink(logFilePath).catch(() => void 0); } -describe('migration v2', () => { +// un-skip after https://github.com/elastic/kibana/issues/116111 +describe.skip('migration v2', () => { let esServer: kbnTestServer.TestElasticsearchUtils; let root: Root; let startES: () => Promise; diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts index c84f72b184261..4f3026c619d3c 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts @@ -133,7 +133,7 @@ describe('migration v2', () => { const pitId = logRecordWithPit.right.pitId; expect(pitId).toBeTruthy(); - const client = esServer.es.getClient(); + const client = esServer.es.getKibanaEsClient(); await expect( client.search({ body: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts index 6956e53ebc7fa..fabc9222b6858 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts @@ -179,7 +179,7 @@ describe('migration v2', () => { }); await root.start(); - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const migratedFooDocs = await fetchDocs(esClient, migratedIndex, 'foo'); expect(migratedFooDocs.length).toBe(2500); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts index ef92c823182d8..5d0d662a5360b 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts @@ -182,7 +182,7 @@ describe('migration v2', () => { await startWithDelay([rootA, rootB, rootC], 0); - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const migratedDocs = await fetchDocs(esClient, migratedIndex); expect(migratedDocs.length).toBe(5000); @@ -201,7 +201,7 @@ describe('migration v2', () => { await startWithDelay([rootA, rootB, rootC], 1); - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const migratedDocs = await fetchDocs(esClient, migratedIndex); expect(migratedDocs.length).toBe(5000); @@ -220,7 +220,7 @@ describe('migration v2', () => { await startWithDelay([rootA, rootB, rootC], 5); - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const migratedDocs = await fetchDocs(esClient, migratedIndex); expect(migratedDocs.length).toBe(5000); @@ -239,7 +239,7 @@ describe('migration v2', () => { await startWithDelay([rootA, rootB, rootC], 20); - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const migratedDocs = await fetchDocs(esClient, migratedIndex); expect(migratedDocs.length).toBe(5000); diff --git a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts index 338eecf151174..c53bd7bbc53dd 100644 --- a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts +++ b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts @@ -12,7 +12,7 @@ import { loggingSystemMock, elasticsearchServiceMock } from '../../mocks'; import { typeRegistryMock } from '../saved_objects_type_registry.mock'; import * as Either from 'fp-ts/lib/Either'; import * as Option from 'fp-ts/lib/Option'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { elasticsearchClientMock } from '../../elasticsearch/client/mocks'; import { LoggerAdapter } from '../../logging/logger_adapter'; import { AllControlStates, State } from './types'; @@ -193,7 +193,7 @@ describe('migrationsStateActionMachine', () => { logger: mockLogger.get(), model: transitionModel(['LEGACY_REINDEX', 'LEGACY_DELETE', 'FATAL']), next: () => { - throw new ResponseError( + throw new errors.ResponseError( elasticsearchClientMock.createApiResponse({ meta: { request: { options: {}, id: '', params: { method: 'POST', path: '/mock' } }, diff --git a/src/core/server/saved_objects/migrationsv2/model/model.ts b/src/core/server/saved_objects/migrationsv2/model/model.ts index 3c36c668f2d99..ff27045dd91ce 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.ts @@ -9,7 +9,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as Option from 'fp-ts/lib/Option'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AliasAction, isLeftTypeof } from '../actions'; import { AllActionStates, MigrationLog, State } from '../types'; import type { ResponseType } from '../next'; diff --git a/src/core/server/saved_objects/migrationsv2/types.ts b/src/core/server/saved_objects/migrationsv2/types.ts index 4f6419930c6cc..e68e04e5267cc 100644 --- a/src/core/server/saved_objects/migrationsv2/types.ts +++ b/src/core/server/saved_objects/migrationsv2/types.ts @@ -8,7 +8,7 @@ import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as Option from 'fp-ts/lib/Option'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ControlState } from './state_action_machine'; import { AliasAction } from './actions'; import { IndexMapping } from '../mappings'; diff --git a/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts b/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts index 2b6d64bef4f1a..97100980a37b3 100644 --- a/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts +++ b/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts @@ -9,16 +9,15 @@ import { IRouter } from '../../../http'; import { catchAndReturnBoomErrors } from '../utils'; import { deleteUnknownTypeObjects } from '../../deprecations'; -import { KibanaConfigType } from '../../../kibana_config'; interface RouteDependencies { - kibanaConfig: KibanaConfigType; + kibanaIndex: string; kibanaVersion: string; } export const registerDeleteUnknownTypesRoute = ( router: IRouter, - { kibanaConfig, kibanaVersion }: RouteDependencies + { kibanaIndex, kibanaVersion }: RouteDependencies ) => { router.post( { @@ -29,7 +28,7 @@ export const registerDeleteUnknownTypesRoute = ( await deleteUnknownTypeObjects({ esClient: context.core.elasticsearch.client, typeRegistry: context.core.savedObjects.typeRegistry, - kibanaConfig, + kibanaIndex, kibanaVersion, }); return res.ok({ diff --git a/src/core/server/saved_objects/routes/index.ts b/src/core/server/saved_objects/routes/index.ts index a85070867ae8f..41ad9ff24c30c 100644 --- a/src/core/server/saved_objects/routes/index.ts +++ b/src/core/server/saved_objects/routes/index.ts @@ -28,7 +28,6 @@ import { registerLegacyImportRoute } from './legacy_import_export/import'; import { registerLegacyExportRoute } from './legacy_import_export/export'; import { registerBulkResolveRoute } from './bulk_resolve'; import { registerDeleteUnknownTypesRoute } from './deprecations'; -import { KibanaConfigType } from '../../kibana_config'; export function registerRoutes({ http, @@ -37,7 +36,7 @@ export function registerRoutes({ config, migratorPromise, kibanaVersion, - kibanaConfig, + kibanaIndex, }: { http: InternalHttpServiceSetup; coreUsageData: InternalCoreUsageDataSetup; @@ -45,7 +44,7 @@ export function registerRoutes({ config: SavedObjectConfig; migratorPromise: Promise; kibanaVersion: string; - kibanaConfig: KibanaConfigType; + kibanaIndex: string; }) { const router = http.createRouter('/api/saved_objects/'); @@ -74,5 +73,5 @@ export function registerRoutes({ const internalRouter = http.createRouter('/internal/saved_objects/'); registerMigrateRoute(internalRouter, migratorPromise); - registerDeleteUnknownTypesRoute(internalRouter, { kibanaConfig, kibanaVersion }); + registerDeleteUnknownTypesRoute(internalRouter, { kibanaIndex, kibanaVersion }); } diff --git a/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts b/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts index 0c7fbdda89fbf..ef1c711536b00 100644 --- a/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts +++ b/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts @@ -12,17 +12,13 @@ import { registerDeleteUnknownTypesRoute } from '../deprecations'; import { elasticsearchServiceMock } from '../../../../../core/server/elasticsearch/elasticsearch_service.mock'; import { typeRegistryMock } from '../../saved_objects_type_registry.mock'; import { setupServer } from '../test_utils'; -import { KibanaConfigType } from '../../../kibana_config'; import { SavedObjectsType } from 'kibana/server'; type SetupServerReturn = UnwrapPromise>; describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () => { const kibanaVersion = '8.0.0'; - const kibanaConfig: KibanaConfigType = { - enabled: true, - index: '.kibana', - }; + const kibanaIndex = '.kibana'; let server: SetupServerReturn['server']; let httpSetup: SetupServerReturn['httpSetup']; @@ -45,7 +41,7 @@ describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () = const router = httpSetup.createRouter('/internal/saved_objects/'); registerDeleteUnknownTypesRoute(router, { kibanaVersion, - kibanaConfig, + kibanaIndex, }); await server.start(); diff --git a/src/core/server/saved_objects/saved_objects_service.mock.ts b/src/core/server/saved_objects/saved_objects_service.mock.ts index cd7310e226f63..fd04d917ebb9c 100644 --- a/src/core/server/saved_objects/saved_objects_service.mock.ts +++ b/src/core/server/saved_objects/saved_objects_service.mock.ts @@ -60,8 +60,11 @@ const createSetupContractMock = () => { setClientFactoryProvider: jest.fn(), addClientWrapper: jest.fn(), registerType: jest.fn(), + getKibanaIndex: jest.fn(), }; + setupContract.getKibanaIndex.mockReturnValue('.kibana'); + return setupContract; }; diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index 534718bd683b8..33d75c38f4369 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -23,7 +23,6 @@ import { InternalElasticsearchServiceStart, } from '../elasticsearch'; import { InternalDeprecationsServiceSetup } from '../deprecations'; -import { KibanaConfigType } from '../kibana_config'; import { SavedObjectsConfigType, SavedObjectsMigrationConfigType, @@ -47,6 +46,8 @@ import { calculateStatus$ } from './status'; import { registerCoreObjectTypes } from './object_types'; import { getSavedObjectsDeprecationsProvider } from './deprecations'; +const kibanaIndex = '.kibana'; + /** * Saved Objects is Kibana's data persistence mechanism allowing plugins to * use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods @@ -144,6 +145,11 @@ export interface SavedObjectsServiceSetup { * ``` */ registerType: (type: SavedObjectsType) => void; + + /** + * Returns the default index used for saved objects. + */ + getKibanaIndex: () => string; } /** @@ -302,14 +308,9 @@ export class SavedObjectsService .toPromise(); this.config = new SavedObjectConfig(savedObjectsConfig, savedObjectsMigrationConfig); - const kibanaConfig = await this.coreContext.configService - .atPath('kibana') - .pipe(first()) - .toPromise(); - deprecations.getRegistry('savedObjects').registerDeprecations( getSavedObjectsDeprecationsProvider({ - kibanaConfig, + kibanaIndex, savedObjectsConfig: this.config, kibanaVersion: this.coreContext.env.packageInfo.version, typeRegistry: this.typeRegistry, @@ -324,7 +325,7 @@ export class SavedObjectsService logger: this.logger, config: this.config, migratorPromise: this.migrator$.pipe(first()).toPromise(), - kibanaConfig, + kibanaIndex, kibanaVersion: this.coreContext.env.packageInfo.version, }); @@ -361,6 +362,7 @@ export class SavedObjectsService this.typeRegistry.registerType(type); }, getTypeRegistry: () => this.typeRegistry, + getKibanaIndex: () => kibanaIndex, }; } @@ -374,14 +376,9 @@ export class SavedObjectsService this.logger.debug('Starting SavedObjects service'); - const kibanaConfig = await this.coreContext.configService - .atPath('kibana') - .pipe(first()) - .toPromise(); const client = elasticsearch.client; const migrator = this.createMigrator( - kibanaConfig, this.config.migration, elasticsearch.client.asInternalUser, migrationsRetryDelay @@ -442,7 +439,7 @@ export class SavedObjectsService return SavedObjectsRepository.createRepository( migrator, this.typeRegistry, - kibanaConfig.index, + kibanaIndex, esClient, this.logger.get('repository'), includedHiddenTypes @@ -498,7 +495,6 @@ export class SavedObjectsService public async stop() {} private createMigrator( - kibanaConfig: KibanaConfigType, soMigrationsConfig: SavedObjectsMigrationConfigType, client: ElasticsearchClient, migrationsRetryDelay?: number @@ -508,7 +504,7 @@ export class SavedObjectsService logger: this.logger, kibanaVersion: this.coreContext.env.packageInfo.version, soMigrationsConfig, - kibanaConfig, + kibanaIndex, client, migrationsRetryDelay, }); diff --git a/src/core/server/saved_objects/service/lib/aggregations/validation.test.ts b/src/core/server/saved_objects/service/lib/aggregations/validation.test.ts index 53f1b5c9d78c5..0296dd25b56ee 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/validation.test.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/validation.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { validateAndConvertAggregations } from './validation'; type AggsMap = Record; diff --git a/src/core/server/saved_objects/service/lib/aggregations/validation.ts b/src/core/server/saved_objects/service/lib/aggregations/validation.ts index 5ef89f297a796..445d6b6a7ce22 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/validation.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/validation.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ObjectType } from '@kbn/config-schema'; import { isPlainObject } from 'lodash'; diff --git a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.mock.ts b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.mock.ts index cbd1ac4a8eb8f..382212cfbbd11 100644 --- a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.mock.ts +++ b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.mock.ts @@ -6,8 +6,17 @@ * Side Public License, v 1. */ +import type { findLegacyUrlAliases } from './find_legacy_url_aliases'; import type * as InternalUtils from './internal_utils'; +export const mockFindLegacyUrlAliases = jest.fn() as jest.MockedFunction< + typeof findLegacyUrlAliases +>; + +jest.mock('./find_legacy_url_aliases', () => { + return { findLegacyUrlAliases: mockFindLegacyUrlAliases }; +}); + export const mockRawDocExistsInNamespace = jest.fn() as jest.MockedFunction< typeof InternalUtils['rawDocExistsInNamespace'] >; diff --git a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.ts b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.ts index fe97208a6168d..bb13a03adb53b 100644 --- a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.ts +++ b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.test.ts @@ -6,26 +6,25 @@ * Side Public License, v 1. */ -import { mockRawDocExistsInNamespace } from './collect_multi_namespace_references.test.mock'; +import { + mockFindLegacyUrlAliases, + mockRawDocExistsInNamespace, +} from './collect_multi_namespace_references.test.mock'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import type { ElasticsearchClient } from 'src/core/server/elasticsearch'; -import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; -import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; +import type { ElasticsearchClient } from '../../../elasticsearch'; +import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { typeRegistryMock } from '../../saved_objects_type_registry.mock'; import { SavedObjectsSerializer } from '../../serialization'; -import type { +import { + ALIAS_SEARCH_PER_PAGE, CollectMultiNamespaceReferencesParams, SavedObjectsCollectMultiNamespaceReferencesObject, SavedObjectsCollectMultiNamespaceReferencesOptions, } from './collect_multi_namespace_references'; import { collectMultiNamespaceReferences } from './collect_multi_namespace_references'; -import { savedObjectsPointInTimeFinderMock } from './point_in_time_finder.mock'; -import { savedObjectsRepositoryMock } from './repository.mock'; -import { PointInTimeFinder } from './point_in_time_finder'; -import { ISavedObjectsRepository } from './repository'; -import { SavedObjectsErrorHelpers } from './errors'; +import type { CreatePointInTimeFinderFn } from './point_in_time_finder'; const SPACES = ['default', 'another-space']; const VERSION_PROPS = { _seq_no: 1, _primary_term: 1 }; @@ -36,17 +35,14 @@ const NON_MULTI_NAMESPACE_OBJ_TYPE = 'type-c'; const MULTI_NAMESPACE_HIDDEN_OBJ_TYPE = 'type-d'; beforeEach(() => { + mockFindLegacyUrlAliases.mockReset(); + mockFindLegacyUrlAliases.mockResolvedValue(new Map()); // return an empty map by default mockRawDocExistsInNamespace.mockReset(); mockRawDocExistsInNamespace.mockReturnValue(true); // return true by default }); describe('collectMultiNamespaceReferences', () => { let client: DeeplyMockedKeys; - let savedObjectsMock: jest.Mocked; - let createPointInTimeFinder: jest.MockedFunction< - CollectMultiNamespaceReferencesParams['createPointInTimeFinder'] - >; - let pointInTimeFinder: DeeplyMockedKeys; /** Sets up the type registry, saved objects client, etc. and return the full parameters object to be passed to `collectMultiNamespaceReferences` */ function setup( @@ -68,20 +64,6 @@ describe('collectMultiNamespaceReferences', () => { client = elasticsearchClientMock.createElasticsearchClient(); const serializer = new SavedObjectsSerializer(registry); - savedObjectsMock = savedObjectsRepositoryMock.create(); - savedObjectsMock.find.mockResolvedValue({ - pit_id: 'foo', - saved_objects: [], - // the rest of these fields don't matter but are included for type safety - total: 0, - page: 1, - per_page: 100, - }); - createPointInTimeFinder = jest.fn(); - createPointInTimeFinder.mockImplementation((params) => { - pointInTimeFinder = savedObjectsPointInTimeFinderMock.create({ savedObjectsMock })(params); - return pointInTimeFinder; - }); return { registry, allowedTypes: [ @@ -92,7 +74,7 @@ describe('collectMultiNamespaceReferences', () => { client, serializer, getIndexForType: (type: string) => `index-for-${type}`, - createPointInTimeFinder, + createPointInTimeFinder: jest.fn() as CreatePointInTimeFinderFn, objects, options, }; @@ -131,23 +113,6 @@ describe('collectMultiNamespaceReferences', () => { ); } - function mockFindResults(...results: LegacyUrlAlias[]) { - savedObjectsMock.find.mockResolvedValueOnce({ - pit_id: 'foo', - saved_objects: results.map((attributes) => ({ - id: 'doesnt-matter', - type: LEGACY_URL_ALIAS_TYPE, - attributes, - references: [], - score: 0, // doesn't matter - })), - // the rest of these fields don't matter but are included for type safety - total: 0, - page: 1, - per_page: 100, - }); - } - /** Asserts that mget is called for the given objects */ function expectMgetArgs( n: number, @@ -319,64 +284,32 @@ describe('collectMultiNamespaceReferences', () => { // obj3 is excluded from the results ]); }); - it(`handles 404 responses that don't come from Elasticsearch`, async () => { - const createEsUnavailableNotFoundError = () => { - return SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - }; - const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; - const params = setup([obj1]); - client.mget.mockReturnValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { docs: [] }, - { statusCode: 404 }, - {} - ) - ); - await expect(() => collectMultiNamespaceReferences(params)).rejects.toThrowError( - createEsUnavailableNotFoundError() - ); - }); describe('legacy URL aliases', () => { - it('uses the PointInTimeFinder to search for legacy URL aliases', async () => { + it('uses findLegacyUrlAliases to search for legacy URL aliases', async () => { const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; const obj2 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-2' }; const obj3 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-3' }; const params = setup([obj1, obj2], {}); mockMgetResults({ found: true, references: [obj3] }, { found: true, references: [] }); // results for obj1 and obj2 mockMgetResults({ found: true, references: [] }); // results for obj3 - mockFindResults( - // mock search results for four aliases for obj1, and none for obj2 or obj3 - ...[1, 2, 3, 4].map((i) => ({ - sourceId: obj1.id, - targetId: 'doesnt-matter', - targetType: obj1.type, - targetNamespace: `space-${i}`, - })) + mockFindLegacyUrlAliases.mockResolvedValue( + new Map([ + [`${obj1.type}:${obj1.id}`, new Set(['space-1', 'space-2', 'space-3', 'space-4'])], + // the result map does not contain keys for obj2 or obj3 because we did not find any aliases for those objects + ]) ); const result = await collectMultiNamespaceReferences(params); expect(client.mget).toHaveBeenCalledTimes(2); expectMgetArgs(1, obj1, obj2); expectMgetArgs(2, obj3); // obj3 is retrieved in a second cluster call - expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); - const kueryFilterArgs = createPointInTimeFinder.mock.calls[0][0].filter.arguments; - expect(kueryFilterArgs).toHaveLength(2); - const typeAndIdFilters = kueryFilterArgs[1].arguments; - expect(typeAndIdFilters).toHaveLength(3); - [obj1, obj2, obj3].forEach(({ type, id }, i) => { - const typeAndIdFilter = typeAndIdFilters[i].arguments; - expect(typeAndIdFilter).toEqual([ - expect.objectContaining({ - arguments: expect.arrayContaining([{ type: 'literal', value: type }]), - }), - expect.objectContaining({ - arguments: expect.arrayContaining([{ type: 'literal', value: id }]), - }), - ]); - }); - expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); + expect(mockFindLegacyUrlAliases).toHaveBeenCalledTimes(1); + expect(mockFindLegacyUrlAliases).toHaveBeenCalledWith( + expect.anything(), + [obj1, obj2, obj3], + ALIAS_SEARCH_PER_PAGE + ); expect(result.objects).toEqual([ { ...obj1, @@ -389,74 +322,32 @@ describe('collectMultiNamespaceReferences', () => { ]); }); - it('does not create a PointInTimeFinder if no objects are passed in', async () => { - const params = setup([]); - - await collectMultiNamespaceReferences(params); - expect(params.createPointInTimeFinder).not.toHaveBeenCalled(); - }); - - it('does not search for objects that have an empty spaces array (the object does not exist, or we are not sure)', async () => { + it('omits objects that have an empty spaces array (the object does not exist, or we are not sure)', async () => { const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; const obj2 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-2' }; const params = setup([obj1, obj2]); mockMgetResults({ found: true }, { found: false }); // results for obj1 and obj2 await collectMultiNamespaceReferences(params); - expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); - - const kueryFilterArgs = createPointInTimeFinder.mock.calls[0][0].filter.arguments; - expect(kueryFilterArgs).toHaveLength(2); - const typeAndIdFilters = kueryFilterArgs[1].arguments; - expect(typeAndIdFilters).toHaveLength(1); - const typeAndIdFilter = typeAndIdFilters[0].arguments; - expect(typeAndIdFilter).toEqual([ - expect.objectContaining({ - arguments: expect.arrayContaining([{ type: 'literal', value: obj1.type }]), - }), - expect.objectContaining({ - arguments: expect.arrayContaining([{ type: 'literal', value: obj1.id }]), - }), - ]); - expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); - }); - - it('does not search at all if all objects that have an empty spaces array (the object does not exist, or we are not sure)', async () => { - const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; - const params = setup([obj1]); - mockMgetResults({ found: false }); // results for obj1 - - await collectMultiNamespaceReferences(params); - expect(params.createPointInTimeFinder).not.toHaveBeenCalled(); - }); - - it('handles PointInTimeFinder.find errors', async () => { - const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; - const params = setup([obj1]); - mockMgetResults({ found: true }); // results for obj1 - savedObjectsMock.find.mockRejectedValue(new Error('Oh no!')); - - await expect(() => collectMultiNamespaceReferences(params)).rejects.toThrow( - 'Failed to retrieve legacy URL aliases: Oh no!' + expect(mockFindLegacyUrlAliases).toHaveBeenCalledTimes(1); + expect(mockFindLegacyUrlAliases).toHaveBeenCalledWith( + expect.anything(), + [obj1], + ALIAS_SEARCH_PER_PAGE ); - expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); // we still close the point-in-time, even though the search failed }); - it('handles PointInTimeFinder.close errors', async () => { + it('handles findLegacyUrlAliases errors', async () => { const obj1 = { type: MULTI_NAMESPACE_OBJ_TYPE_1, id: 'id-1' }; const params = setup([obj1]); mockMgetResults({ found: true }); // results for obj1 - savedObjectsMock.closePointInTime.mockRejectedValue(new Error('Oh no!')); + mockFindLegacyUrlAliases.mockRejectedValue( + new Error('Failed to retrieve legacy URL aliases: Oh no!') + ); await expect(() => collectMultiNamespaceReferences(params)).rejects.toThrow( 'Failed to retrieve legacy URL aliases: Oh no!' ); - expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); - expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); }); }); }); diff --git a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.ts b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.ts index 7acbaaea1f5d7..87bb5017aab95 100644 --- a/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.ts +++ b/src/core/server/saved_objects/service/lib/collect_multi_namespace_references.ts @@ -6,19 +6,18 @@ * Side Public License, v 1. */ -import * as esKuery from '@kbn/es-query'; -import { isNotFoundFromUnsupportedServer } from '../../../elasticsearch'; -import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; import type { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import type { SavedObjectsSerializer } from '../../serialization'; import type { SavedObject, SavedObjectsBaseOptions } from '../../types'; -import { SavedObjectsErrorHelpers } from './errors'; +import { findLegacyUrlAliases } from './find_legacy_url_aliases'; import { getRootFields } from './included_fields'; -import { getSavedObjectFromSource, rawDocExistsInNamespace } from './internal_utils'; -import type { - ISavedObjectsPointInTimeFinder, - SavedObjectsCreatePointInTimeFinderOptions, -} from './point_in_time_finder'; +import { + getObjectKey, + getSavedObjectFromSource, + parseObjectKey, + rawDocExistsInNamespace, +} from './internal_utils'; +import type { CreatePointInTimeFinderFn } from './point_in_time_finder'; import type { RepositoryEsClient } from './repository_es_client'; /** @@ -30,8 +29,10 @@ const MAX_REFERENCE_GRAPH_DEPTH = 20; * How many aliases to search for per page. This is smaller than the PointInTimeFinder's default of 1000. We specify 100 for the page count * because this is a relatively unimportant operation, and we want to avoid blocking the Elasticsearch thread pool for longer than * necessary. + * + * @internal */ -const ALIAS_SEARCH_PER_PAGE = 100; +export const ALIAS_SEARCH_PER_PAGE = 100; /** * An object to collect references for. It must be a multi-namespace type (in other words, the object type must be registered with the @@ -108,9 +109,7 @@ export interface CollectMultiNamespaceReferencesParams { client: RepositoryEsClient; serializer: SavedObjectsSerializer; getIndexForType: (type: string) => string; - createPointInTimeFinder: ( - findOptions: SavedObjectsCreatePointInTimeFinderOptions - ) => ISavedObjectsPointInTimeFinder; + createPointInTimeFinder: CreatePointInTimeFinderFn; objects: SavedObjectsCollectMultiNamespaceReferencesObject[]; options?: SavedObjectsCollectMultiNamespaceReferencesOptions; } @@ -118,6 +117,8 @@ export interface CollectMultiNamespaceReferencesParams { /** * Gets all references and transitive references of the given objects. Ignores any object and/or reference that is not a multi-namespace * type. + * + * @internal */ export async function collectMultiNamespaceReferences( params: CollectMultiNamespaceReferencesParams @@ -132,18 +133,25 @@ export async function collectMultiNamespaceReferences( inboundReferencesMap.entries() ).map(([referenceKey, referenceVal]) => { const inboundReferences = Array.from(referenceVal.entries()).map(([objectKey, name]) => { - const { type, id } = parseKey(objectKey); + const { type, id } = parseObjectKey(objectKey); return { type, id, name }; }); - const { type, id } = parseKey(referenceKey); + const { type, id } = parseObjectKey(referenceKey); const object = objectMap.get(referenceKey); const spaces = object?.namespaces ?? []; return { type, id, spaces, inboundReferences, ...(object === null && { isMissing: true }) }; }); - const aliasesMap = await checkLegacyUrlAliases(createPointInTimeFinder, objectsWithContext); + const objectsToFindAliasesFor = objectsWithContext + .filter(({ spaces }) => spaces.length !== 0) + .map(({ type, id }) => ({ type, id })); + const aliasesMap = await findLegacyUrlAliases( + createPointInTimeFinder, + objectsToFindAliasesFor, + ALIAS_SEARCH_PER_PAGE + ); const results = objectsWithContext.map((obj) => { - const key = getKey(obj); + const key = getObjectKey(obj); const val = aliasesMap.get(key); const spacesWithMatchingAliases = val && Array.from(val); return { ...obj, spacesWithMatchingAliases }; @@ -169,7 +177,7 @@ async function getObjectsAndReferences({ const { namespace, purpose } = options; const inboundReferencesMap = objects.reduce( // Add the input objects to the references map so they are returned with the results, even if they have no inbound references - (acc, cur) => acc.set(getKey(cur), new Map()), + (acc, cur) => acc.set(getObjectKey(cur), new Map()), new Map>() ); const objectMap = new Map(); @@ -199,20 +207,11 @@ async function getObjectsAndReferences({ { body: { docs: makeBulkGetDocs(bulkGetObjects) } }, { ignore: [404] } ); - // exit early if we can't verify a 404 response is from Elasticsearch - if ( - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } const newObjectsToGet = new Set(); for (let i = 0; i < bulkGetObjects.length; i++) { // For every element in bulkGetObjects, there should be a matching element in bulkGetResponse.body.docs const { type, id } = bulkGetObjects[i]; - const objectKey = getKey({ type, id }); + const objectKey = getObjectKey({ type, id }); const doc = bulkGetResponse.body.docs[i]; // @ts-expect-error MultiGetHit._source is optional if (!doc.found || !rawDocExistsInNamespace(registry, doc, namespace)) { @@ -226,7 +225,7 @@ async function getObjectsAndReferences({ if (!validObjectTypesFilter(reference)) { continue; } - const referenceKey = getKey(reference); + const referenceKey = getObjectKey(reference); const referenceVal = inboundReferencesMap.get(referenceKey) ?? new Map(); if (!referenceVal.has(objectKey)) { inboundReferencesMap.set(referenceKey, referenceVal.set(objectKey, reference.name)); @@ -236,84 +235,9 @@ async function getObjectsAndReferences({ } } } - bulkGetObjects = Array.from(newObjectsToGet).map((key) => parseKey(key)); + bulkGetObjects = Array.from(newObjectsToGet).map((key) => parseObjectKey(key)); count++; } return { objectMap, inboundReferencesMap }; } - -/** - * Fetches all legacy URL aliases that match the given objects, returning a map of the matching aliases and what space(s) they exist in. - */ -async function checkLegacyUrlAliases( - createPointInTimeFinder: ( - findOptions: SavedObjectsCreatePointInTimeFinderOptions - ) => ISavedObjectsPointInTimeFinder, - objects: SavedObjectReferenceWithContext[] -) { - const filteredObjects = objects.filter(({ spaces }) => spaces.length !== 0); - if (!filteredObjects.length) { - return new Map>(); - } - const filter = createAliasKueryFilter(filteredObjects); - const finder = createPointInTimeFinder({ - type: LEGACY_URL_ALIAS_TYPE, - perPage: ALIAS_SEARCH_PER_PAGE, - filter, - }); - const aliasesMap = new Map>(); - let error: Error | undefined; - try { - for await (const { saved_objects: savedObjects } of finder.find()) { - for (const alias of savedObjects) { - const { sourceId, targetType, targetNamespace } = alias.attributes; - const key = getKey({ type: targetType, id: sourceId }); - const val = aliasesMap.get(key) ?? new Set(); - val.add(targetNamespace); - aliasesMap.set(key, val); - } - } - } catch (e) { - error = e; - } - - try { - await finder.close(); - } catch (e) { - if (!error) { - error = e; - } - } - - if (error) { - throw new Error(`Failed to retrieve legacy URL aliases: ${error.message}`); - } - return aliasesMap; -} - -function createAliasKueryFilter(objects: SavedObjectReferenceWithContext[]) { - const { buildNode } = esKuery.nodeTypes.function; - const kueryNodes = objects.reduce((acc, { type, id }) => { - const match1 = buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.targetType`, type); - const match2 = buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.sourceId`, id); - acc.push(buildNode('and', [match1, match2])); - return acc; - }, []); - return buildNode('and', [ - buildNode('not', buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.disabled`, true)), // ignore aliases that have been disabled - buildNode('or', kueryNodes), - ]); -} - -/** Takes an object with a `type` and `id` field and returns a key string */ -function getKey({ type, id }: { type: string; id: string }) { - return `${type}:${id}`; -} - -/** Parses a 'type:id' key string and returns an object with a `type` field and an `id` field */ -function parseKey(key: string) { - const type = key.slice(0, key.indexOf(':')); - const id = key.slice(type.length + 1); - return { type, id }; -} diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts index 4e187e85f81a7..e7dd355910362 100644 --- a/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts +++ b/src/core/server/saved_objects/service/lib/decorate_es_error.test.ts @@ -53,6 +53,16 @@ describe('savedObjectsClient/decorateEsError', () => { expect(SavedObjectsErrorHelpers.isEsUnavailableError(error)).toBe(true); }); + it('makes ProductNotSupportedError a SavedObjectsClient/EsUnavailable error', () => { + const error = new esErrors.ProductNotSupportedError( + 'reason', + elasticsearchClientMock.createApiResponse() + ); + expect(SavedObjectsErrorHelpers.isEsUnavailableError(error)).toBe(false); + expect(decorateEsError(error)).toBe(error); + expect(SavedObjectsErrorHelpers.isEsUnavailableError(error)).toBe(true); + }); + it('makes Conflict a SavedObjectsClient/Conflict error', () => { const error = new esErrors.ResponseError( elasticsearchClientMock.createApiResponse({ statusCode: 409 }) @@ -109,18 +119,6 @@ describe('savedObjectsClient/decorateEsError', () => { expect(SavedObjectsErrorHelpers.isNotFoundError(genericError)).toBe(true); }); - it('makes NotFound errors generic NotFoundEsUnavailableError errors when response is from unsupported server', () => { - const error = new esErrors.ResponseError( - // explicitly override the headers - elasticsearchClientMock.createApiResponse({ statusCode: 404, headers: {} }) - ); - expect(SavedObjectsErrorHelpers.isNotFoundError(error)).toBe(false); - const genericError = decorateEsError(error); - expect(genericError).not.toBe(error); - expect(SavedObjectsErrorHelpers.isNotFoundError(genericError)).toBe(false); - expect(SavedObjectsErrorHelpers.isEsUnavailableError(genericError)).toBe(true); - }); - it('if saved objects index does not exist makes NotFound a SavedObjectsClient/generalError', () => { const error = new esErrors.ResponseError( elasticsearchClientMock.createApiResponse({ diff --git a/src/core/server/saved_objects/service/lib/decorate_es_error.ts b/src/core/server/saved_objects/service/lib/decorate_es_error.ts index 016268ccdf9f4..d8734b141bd9b 100644 --- a/src/core/server/saved_objects/service/lib/decorate_es_error.ts +++ b/src/core/server/saved_objects/service/lib/decorate_es_error.ts @@ -8,19 +8,20 @@ import { errors as esErrors } from '@elastic/elasticsearch'; import { get } from 'lodash'; -import { isSupportedEsServer } from '../../../elasticsearch'; +import { ElasticsearchErrorDetails } from '../../../elasticsearch'; const responseErrors = { - isServiceUnavailable: (statusCode: number) => statusCode === 503, - isConflict: (statusCode: number) => statusCode === 409, - isNotAuthorized: (statusCode: number) => statusCode === 401, - isForbidden: (statusCode: number) => statusCode === 403, - isRequestEntityTooLarge: (statusCode: number) => statusCode === 413, - isNotFound: (statusCode: number) => statusCode === 404, - isBadRequest: (statusCode: number) => statusCode === 400, - isTooManyRequests: (statusCode: number) => statusCode === 429, + isServiceUnavailable: (statusCode?: number) => statusCode === 503, + isConflict: (statusCode?: number) => statusCode === 409, + isNotAuthorized: (statusCode?: number) => statusCode === 401, + isForbidden: (statusCode?: number) => statusCode === 403, + isRequestEntityTooLarge: (statusCode?: number) => statusCode === 413, + isNotFound: (statusCode?: number) => statusCode === 404, + isBadRequest: (statusCode?: number) => statusCode === 400, + isTooManyRequests: (statusCode?: number) => statusCode === 429, }; -const { ConnectionError, NoLivingConnectionsError, TimeoutError } = esErrors; +const { ConnectionError, NoLivingConnectionsError, TimeoutError, ProductNotSupportedError } = + esErrors; const SCRIPT_CONTEXT_DISABLED_REGEX = /(?:cannot execute scripts using \[)([a-z]*)(?:\] context)/; const INLINE_SCRIPTS_DISABLED_MESSAGE = 'cannot execute [inline] scripts'; @@ -30,6 +31,7 @@ type EsErrors = | esErrors.ConnectionError | esErrors.NoLivingConnectionsError | esErrors.TimeoutError + | esErrors.ProductNotSupportedError | esErrors.ResponseError; export function decorateEsError(error: EsErrors) { @@ -42,6 +44,7 @@ export function decorateEsError(error: EsErrors) { error instanceof ConnectionError || error instanceof NoLivingConnectionsError || error instanceof TimeoutError || + error instanceof ProductNotSupportedError || responseErrors.isServiceUnavailable(error.statusCode) ) { return SavedObjectsErrorHelpers.decorateEsUnavailableError(error, reason); @@ -64,17 +67,12 @@ export function decorateEsError(error: EsErrors) { } if (responseErrors.isNotFound(error.statusCode)) { - const match = error?.meta?.body?.error?.reason?.match( + const match = (error?.meta?.body as ElasticsearchErrorDetails)?.error?.reason?.match( /no such index \[(.+)\] and \[require_alias\] request flag is \[true\] and \[.+\] is not an alias/ ); - if (match?.length > 0) { + if (match && match.length > 0) { return SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError(error, match[1]); } - // Throw EsUnavailable error if the 404 is not from elasticsearch - // Needed here to verify Product support for any non-ignored 404 responses from calls to ES - if (!isSupportedEsServer(error?.meta?.headers)) { - return SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } return SavedObjectsErrorHelpers.createGenericNotFoundError(); } diff --git a/src/core/server/saved_objects/service/lib/errors.test.ts b/src/core/server/saved_objects/service/lib/errors.test.ts index 3bea693429254..a366dce626ec2 100644 --- a/src/core/server/saved_objects/service/lib/errors.test.ts +++ b/src/core/server/saved_objects/service/lib/errors.test.ts @@ -439,45 +439,4 @@ describe('savedObjectsClient/errorTypes', () => { }); }); }); - - describe('NotFoundEsUnavailableError', () => { - it('makes an error identifiable as an EsUnavailable error', () => { - const error = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('foo', 'bar'); - expect(SavedObjectsErrorHelpers.isEsUnavailableError(error)).toBe(true); - }); - - it('returns a boom error', () => { - const error = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('foo', 'bar'); - expect(error).toHaveProperty('isBoom', true); - }); - - it('decorates the error message with the saved object that was not found', () => { - const error = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('foo', 'bar'); - expect(error.output.payload).toHaveProperty( - 'message', - 'x-elastic-product not present or not recognized: Saved object [foo/bar] not found' - ); - }); - - describe('error.output', () => { - it('specifies the saved object that was not found', () => { - const error = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError( - 'foo', - 'bar' - ); - expect(error.output.payload).toHaveProperty( - 'message', - 'x-elastic-product not present or not recognized: Saved object [foo/bar] not found' - ); - }); - - it('sets statusCode to 503', () => { - const error = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError( - 'foo', - 'bar' - ); - expect(error.output).toHaveProperty('statusCode', 503); - }); - }); - }); }); diff --git a/src/core/server/saved_objects/service/lib/errors.ts b/src/core/server/saved_objects/service/lib/errors.ts index 7412e744f19e7..581145c7c09d1 100644 --- a/src/core/server/saved_objects/service/lib/errors.ts +++ b/src/core/server/saved_objects/service/lib/errors.ts @@ -202,16 +202,4 @@ export class SavedObjectsErrorHelpers { public static isGeneralError(error: Error | DecoratedError) { return isSavedObjectsClientError(error) && error[code] === CODE_GENERAL_ERROR; } - - public static createGenericNotFoundEsUnavailableError( - // type and id not available in all operations (e.g. mget) - type: string | null = null, - id: string | null = null - ) { - const notFoundError = this.createGenericNotFoundError(type, id); - return this.decorateEsUnavailableError( - new Error(`${notFoundError.message}`), - `x-elastic-product not present or not recognized` - ); - } } diff --git a/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.test.ts b/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.test.ts new file mode 100644 index 0000000000000..134ea26d53b7d --- /dev/null +++ b/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.test.ts @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; + +import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; +import { findLegacyUrlAliases } from './find_legacy_url_aliases'; +import type { CreatePointInTimeFinderFn, PointInTimeFinder } from './point_in_time_finder'; +import { savedObjectsPointInTimeFinderMock } from './point_in_time_finder.mock'; +import type { ISavedObjectsRepository } from './repository'; +import { savedObjectsRepositoryMock } from './repository.mock'; + +describe('findLegacyUrlAliases', () => { + let savedObjectsMock: jest.Mocked; + let pointInTimeFinder: DeeplyMockedKeys; + let createPointInTimeFinder: jest.MockedFunction; + + beforeEach(() => { + savedObjectsMock = savedObjectsRepositoryMock.create(); + savedObjectsMock.find.mockResolvedValue({ + pit_id: 'foo', + saved_objects: [], + // the rest of these fields don't matter but are included for type safety + total: 0, + page: 1, + per_page: 100, + }); + pointInTimeFinder = savedObjectsPointInTimeFinderMock.create({ savedObjectsMock })(); // PIT finder mock uses the actual implementation, but it doesn't need to be created with real params because the SOR is mocked too + createPointInTimeFinder = jest.fn().mockReturnValue(pointInTimeFinder); + }); + + function mockFindResults(...results: LegacyUrlAlias[]) { + savedObjectsMock.find.mockResolvedValueOnce({ + pit_id: 'foo', + saved_objects: results.map((attributes) => ({ + id: 'doesnt-matter', + type: LEGACY_URL_ALIAS_TYPE, + attributes, + references: [], + score: 0, // doesn't matter + })), + // the rest of these fields don't matter but are included for type safety + total: 0, + page: 1, + per_page: 100, + }); + } + + const obj1 = { type: 'obj-type', id: 'id-1' }; + const obj2 = { type: 'obj-type', id: 'id-2' }; + const obj3 = { type: 'obj-type', id: 'id-3' }; + + it('uses the PointInTimeFinder to search for legacy URL aliases', async () => { + mockFindResults( + // mock search results for four aliases for obj1, and none for obj2 or obj3 + ...[1, 2, 3, 4].map((i) => ({ + sourceId: obj1.id, + targetId: 'doesnt-matter', + targetType: obj1.type, + targetNamespace: `space-${i}`, + })) + ); + + const objects = [obj1, obj2, obj3]; + const result = await findLegacyUrlAliases(createPointInTimeFinder, objects); + expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); + expect(createPointInTimeFinder).toHaveBeenCalledWith({ + type: LEGACY_URL_ALIAS_TYPE, + filter: expect.any(Object), // assertions are below + }); + const kueryFilterArgs = createPointInTimeFinder.mock.calls[0][0].filter.arguments; + expect(kueryFilterArgs).toHaveLength(2); + const typeAndIdFilters = kueryFilterArgs[1].arguments; + expect(typeAndIdFilters).toHaveLength(3); + [obj1, obj2, obj3].forEach(({ type, id }, i) => { + const typeAndIdFilter = typeAndIdFilters[i].arguments; + expect(typeAndIdFilter).toEqual([ + expect.objectContaining({ + arguments: expect.arrayContaining([{ type: 'literal', value: type }]), + }), + expect.objectContaining({ + arguments: expect.arrayContaining([{ type: 'literal', value: id }]), + }), + ]); + }); + expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); + expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); + expect(result).toEqual( + new Map([ + [`${obj1.type}:${obj1.id}`, new Set(['space-1', 'space-2', 'space-3', 'space-4'])], + // the result map does not contain keys for obj2 or obj3 because we did not find any aliases for those objects + ]) + ); + }); + + it('allows perPage to be set', async () => { + const objects = [obj1, obj2, obj3]; + await findLegacyUrlAliases(createPointInTimeFinder, objects, 999); + expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); + expect(createPointInTimeFinder).toHaveBeenCalledWith({ + type: LEGACY_URL_ALIAS_TYPE, + perPage: 999, + filter: expect.any(Object), + }); + }); + + it('does not create a PointInTimeFinder if no objects are passed in', async () => { + await findLegacyUrlAliases(createPointInTimeFinder, []); + expect(createPointInTimeFinder).not.toHaveBeenCalled(); + }); + + it('handles PointInTimeFinder.find errors', async () => { + savedObjectsMock.find.mockRejectedValue(new Error('Oh no!')); + + const objects = [obj1, obj2, obj3]; + await expect(() => findLegacyUrlAliases(createPointInTimeFinder, objects)).rejects.toThrow( + 'Failed to retrieve legacy URL aliases: Oh no!' + ); + expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); + expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); + expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); // we still close the point-in-time, even though the search failed + }); + + it('handles PointInTimeFinder.close errors', async () => { + pointInTimeFinder.close.mockRejectedValue(new Error('Oh no!')); + + const objects = [obj1, obj2, obj3]; + await expect(() => findLegacyUrlAliases(createPointInTimeFinder, objects)).rejects.toThrow( + 'Failed to retrieve legacy URL aliases: Oh no!' + ); + expect(createPointInTimeFinder).toHaveBeenCalledTimes(1); + expect(pointInTimeFinder.find).toHaveBeenCalledTimes(1); + expect(pointInTimeFinder.close).toHaveBeenCalledTimes(2); + }); +}); diff --git a/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.ts b/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.ts new file mode 100644 index 0000000000000..aac022fc32098 --- /dev/null +++ b/src/core/server/saved_objects/service/lib/find_legacy_url_aliases.ts @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as esKuery from '@kbn/es-query'; +import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; +import { getObjectKey } from './internal_utils'; +import type { CreatePointInTimeFinderFn } from './point_in_time_finder'; + +interface FindLegacyUrlAliasesObject { + type: string; + id: string; +} + +/** + * Fetches all legacy URL aliases that match the given objects, returning a map of the matching aliases and what space(s) they exist in. + * + * @internal + */ +export async function findLegacyUrlAliases( + createPointInTimeFinder: CreatePointInTimeFinderFn, + objects: FindLegacyUrlAliasesObject[], + perPage?: number +) { + if (!objects.length) { + return new Map>(); + } + + const filter = createAliasKueryFilter(objects); + const finder = createPointInTimeFinder({ + type: LEGACY_URL_ALIAS_TYPE, + perPage, + filter, + }); + const aliasesMap = new Map>(); + let error: Error | undefined; + try { + for await (const { saved_objects: savedObjects } of finder.find()) { + for (const alias of savedObjects) { + const { sourceId, targetType, targetNamespace } = alias.attributes; + const key = getObjectKey({ type: targetType, id: sourceId }); + const val = aliasesMap.get(key) ?? new Set(); + val.add(targetNamespace); + aliasesMap.set(key, val); + } + } + } catch (e) { + error = e; + } + + try { + await finder.close(); + } catch (e) { + if (!error) { + error = e; + } + } + + if (error) { + throw new Error(`Failed to retrieve legacy URL aliases: ${error.message}`); + } + return aliasesMap; +} + +function createAliasKueryFilter(objects: Array<{ type: string; id: string }>) { + const { buildNode } = esKuery.nodeTypes.function; + const kueryNodes = objects.reduce((acc, { type, id }) => { + const match1 = buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.targetType`, type); + const match2 = buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.sourceId`, id); + acc.push(buildNode('and', [match1, match2])); + return acc; + }, []); + return buildNode('and', [ + buildNode('not', buildNode('is', `${LEGACY_URL_ALIAS_TYPE}.attributes.disabled`, true)), // ignore aliases that have been disabled + buildNode('or', kueryNodes), + ]); +} diff --git a/src/core/server/saved_objects/service/lib/integration_tests/repository_with_proxy.test.ts b/src/core/server/saved_objects/service/lib/integration_tests/repository_with_proxy.test.ts index 925b23a64f03e..b767b28c90608 100644 --- a/src/core/server/saved_objects/service/lib/integration_tests/repository_with_proxy.test.ts +++ b/src/core/server/saved_objects/service/lib/integration_tests/repository_with_proxy.test.ts @@ -289,17 +289,11 @@ describe('404s from proxies', () => { let repository: ISavedObjectsRepository; const myTypeDocs: SavedObject[] = []; - const genericNotFoundEsUnavailableError = (err: any, type?: string, id?: string) => { + const SavedObjectsClientEsUnavailable = (err: any) => { expect(err?.output?.statusCode).toBe(503); - if (type && id) { - expect(err?.output?.payload?.message).toBe( - `x-elastic-product not present or not recognized: Saved object [${type}/${id}] not found` - ); - } else { - expect(err?.output?.payload?.message).toBe( - `x-elastic-product not present or not recognized: Not Found` - ); - } + expect(err?.output?.payload?.message).toBe( + `The client noticed that the server is not Elasticsearch and we do not support this unknown product.` + ); }; beforeAll(async () => { @@ -341,7 +335,7 @@ describe('404s from proxies', () => { } catch (err) { myError = err; } - expect(genericNotFoundEsUnavailableError(myError, 'my_type', 'myTypeId1')); + expect(SavedObjectsClientEsUnavailable(myError)); }); it('returns an EsUnavailable error on `update` requests that are interrupted', async () => { @@ -354,7 +348,7 @@ describe('404s from proxies', () => { } catch (err) { updateError = err; } - expect(genericNotFoundEsUnavailableError(updateError)); + expect(SavedObjectsClientEsUnavailable(updateError)); }); it('returns an EsUnavailable error on `bulkCreate` requests with a 404 proxy response and wrong product header', async () => { @@ -383,7 +377,7 @@ describe('404s from proxies', () => { } catch (err) { bulkCreateError = err; } - expect(genericNotFoundEsUnavailableError(bulkCreateError)); + expect(SavedObjectsClientEsUnavailable(bulkCreateError)); }); it('returns an EsUnavailable error on `find` requests with a 404 proxy response and wrong product header', async () => { @@ -394,7 +388,7 @@ describe('404s from proxies', () => { } catch (err) { findErr = err; } - expect(genericNotFoundEsUnavailableError(findErr)); + expect(SavedObjectsClientEsUnavailable(findErr)); expect(findErr?.output?.payload?.error).toBe('Service Unavailable'); }); @@ -405,7 +399,7 @@ describe('404s from proxies', () => { } catch (err) { deleteErr = err; } - expect(genericNotFoundEsUnavailableError(deleteErr, 'my_type', 'myTypeId1')); + expect(SavedObjectsClientEsUnavailable(deleteErr)); }); it('returns an EsUnavailable error on `bulkResolve` requests with a 404 proxy response and wrong product header for an exact match', async () => { @@ -417,7 +411,7 @@ describe('404s from proxies', () => { } catch (err) { testBulkResolveErr = err; } - expect(genericNotFoundEsUnavailableError(testBulkResolveErr)); + expect(SavedObjectsClientEsUnavailable(testBulkResolveErr)); }); it('returns an EsUnavailable error on `resolve` requests with a 404 proxy response and wrong product header for an exact match', async () => { @@ -428,7 +422,7 @@ describe('404s from proxies', () => { } catch (err) { testResolveErr = err; } - expect(genericNotFoundEsUnavailableError(testResolveErr)); + expect(SavedObjectsClientEsUnavailable(testResolveErr)); }); it('returns an EsUnavailable error on `bulkGet` requests with a 404 proxy response and wrong product header', async () => { @@ -440,7 +434,7 @@ describe('404s from proxies', () => { } catch (err) { bulkGetError = err; } - expect(genericNotFoundEsUnavailableError(bulkGetError)); + expect(SavedObjectsClientEsUnavailable(bulkGetError)); }); it('returns an EsUnavailable error on `openPointInTimeForType` requests with a 404 proxy response and wrong product header', async () => { @@ -451,7 +445,7 @@ describe('404s from proxies', () => { } catch (err) { openPitErr = err; } - expect(genericNotFoundEsUnavailableError(openPitErr)); + expect(SavedObjectsClientEsUnavailable(openPitErr)); }); it('returns an EsUnavailable error on `checkConflicts` requests with a 404 proxy response and wrong product header', async () => { @@ -468,7 +462,7 @@ describe('404s from proxies', () => { } catch (err) { checkConflictsErr = err; } - expect(genericNotFoundEsUnavailableError(checkConflictsErr)); + expect(SavedObjectsClientEsUnavailable(checkConflictsErr)); }); it('returns an EsUnavailable error on `deleteByNamespace` requests with a 404 proxy response and wrong product header', async () => { @@ -479,7 +473,7 @@ describe('404s from proxies', () => { } catch (err) { deleteByNamespaceErr = err; } - expect(genericNotFoundEsUnavailableError(deleteByNamespaceErr)); + expect(SavedObjectsClientEsUnavailable(deleteByNamespaceErr)); }); }); }); diff --git a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.mock.ts b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.mock.ts index fbd774f1c10d5..513add01cdd83 100644 --- a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.mock.ts +++ b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.mock.ts @@ -7,7 +7,6 @@ */ import type * as InternalUtils from './internal_utils'; -import type { isNotFoundFromUnsupportedServer } from '../../../elasticsearch'; export const mockGetSavedObjectFromSource = jest.fn() as jest.MockedFunction< typeof InternalUtils['getSavedObjectFromSource'] @@ -24,14 +23,3 @@ jest.mock('./internal_utils', () => { rawDocExistsInNamespace: mockRawDocExistsInNamespace, }; }); - -export const mockIsNotFoundFromUnsupportedServer = jest.fn() as jest.MockedFunction< - typeof isNotFoundFromUnsupportedServer ->; -jest.mock('../../../elasticsearch', () => { - const actual = jest.requireActual('../../../elasticsearch'); - return { - ...actual, - isNotFoundFromUnsupportedServer: mockIsNotFoundFromUnsupportedServer, - }; -}); diff --git a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts index 5403e146509ae..4120b077a8981 100644 --- a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts +++ b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts @@ -9,7 +9,6 @@ import { mockGetSavedObjectFromSource, mockRawDocExistsInNamespace, - mockIsNotFoundFromUnsupportedServer, } from './internal_bulk_resolve.test.mock'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; @@ -35,8 +34,6 @@ beforeEach(() => { ); mockRawDocExistsInNamespace.mockReset(); mockRawDocExistsInNamespace.mockReturnValue(true); // return true by default - mockIsNotFoundFromUnsupportedServer.mockReset(); - mockIsNotFoundFromUnsupportedServer.mockReturnValue(false); }); describe('internalBulkResolve', () => { @@ -173,24 +170,6 @@ describe('internalBulkResolve', () => { return { saved_object: `mock-obj-for-${id}`, outcome: 'conflict', alias_target_id }; } - it('throws if mget call results in non-ES-originated 404 error', async () => { - const objects = [{ type: OBJ_TYPE, id: '1' }]; - const params = setup(objects, { namespace: 'space-x' }); - mockBulkResults( - { found: false } // fetch alias for obj 1 - ); - mockMgetResults( - { found: false } // fetch obj 1 (actual result body doesn't matter, just needs statusCode and headers) - ); - mockIsNotFoundFromUnsupportedServer.mockReturnValue(true); - - await expect(() => internalBulkResolve(params)).rejects.toThrow( - SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError() - ); - expect(client.bulk).toHaveBeenCalledTimes(1); - expect(client.mget).toHaveBeenCalledTimes(1); - }); - it('returns an empty array if no object args are passed in', async () => { const params = setup([], { namespace: 'space-x' }); diff --git a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.ts b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.ts index f53a85a9a03ef..19f774fb068b6 100644 --- a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.ts +++ b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.ts @@ -6,14 +6,13 @@ * Side Public License, v 1. */ -import type { MgetHit } from '@elastic/elasticsearch/api/types'; +import type { MgetHit } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { CORE_USAGE_STATS_ID, CORE_USAGE_STATS_TYPE, REPOSITORY_RESOLVE_OUTCOME_STATS, } from '../../../core_usage_data'; -import { isNotFoundFromUnsupportedServer } from '../../../elasticsearch'; import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; import type { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import type { SavedObjectsRawDocSource, SavedObjectsSerializer } from '../../serialization'; @@ -141,16 +140,6 @@ export async function internalBulkResolve( { ignore: [404] } ) : undefined; - // exit early if a 404 isn't from elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } let getResponseIndex = 0; let aliasTargetIndex = 0; diff --git a/src/core/server/saved_objects/service/lib/internal_utils.test.ts b/src/core/server/saved_objects/service/lib/internal_utils.test.ts index 1a94e22d61f86..710303ab33359 100644 --- a/src/core/server/saved_objects/service/lib/internal_utils.test.ts +++ b/src/core/server/saved_objects/service/lib/internal_utils.test.ts @@ -12,8 +12,10 @@ import { encodeHitVersion } from '../../version'; import { getBulkOperationError, getCurrentTime, + getObjectKey, getSavedObjectFromSource, normalizeNamespace, + parseObjectKey, rawDocExistsInNamespace, rawDocExistsInNamespaces, } from './internal_utils'; @@ -359,3 +361,19 @@ describe('#getCurrentTime', () => { expect(getCurrentTime()).toEqual('2021-09-10T21:00:00.000Z'); }); }); + +describe('#getObjectKey', () => { + it('returns the expected key string', () => { + expect(getObjectKey({ type: 'foo', id: 'bar' })).toEqual('foo:bar'); + }); +}); + +describe('#parseObjectKey', () => { + it('returns the expected object', () => { + expect(parseObjectKey('foo:bar')).toEqual({ type: 'foo', id: 'bar' }); + }); + + it('throws error when input is malformed', () => { + expect(() => parseObjectKey('foobar')).toThrowError('Malformed object key'); + }); +}); diff --git a/src/core/server/saved_objects/service/lib/internal_utils.ts b/src/core/server/saved_objects/service/lib/internal_utils.ts index b480000f1b3da..abedcf53c781f 100644 --- a/src/core/server/saved_objects/service/lib/internal_utils.ts +++ b/src/core/server/saved_objects/service/lib/internal_utils.ts @@ -15,7 +15,7 @@ import { SavedObjectsErrorHelpers } from './errors'; import { ALL_NAMESPACES_STRING, SavedObjectsUtils } from './utils'; /** - * Discriminated union (TypeScript approximation of an algebraic data type); this design pattern used for internal repository operations. + * Discriminated union (TypeScript approximation of an algebraic data type); this design pattern is used for internal repository operations. * @internal */ export type Either = Left | Right; @@ -242,3 +242,26 @@ export function normalizeNamespace(namespace?: string) { export function getCurrentTime() { return new Date(Date.now()).toISOString(); } + +/** + * Takes an object with a `type` and `id` field and returns a key string. + * + * @internal + */ +export function getObjectKey({ type, id }: { type: string; id: string }) { + return `${type}:${id}`; +} + +/** + * Parses a 'type:id' key string and returns an object with a `type` field and an `id` field. + * + * @internal + */ +export function parseObjectKey(key: string) { + const type = key.slice(0, key.indexOf(':')); + const id = key.slice(type.length + 1); + if (!type || !id) { + throw new Error('Malformed object key (should be "type:id")'); + } + return { type, id }; +} diff --git a/src/core/server/saved_objects/service/lib/point_in_time_finder.ts b/src/core/server/saved_objects/service/lib/point_in_time_finder.ts index 9faf5e85085ed..5c630d1416cc3 100644 --- a/src/core/server/saved_objects/service/lib/point_in_time_finder.ts +++ b/src/core/server/saved_objects/service/lib/point_in_time_finder.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Logger } from '../../../logging'; import type { SavedObjectsFindOptions, SavedObjectsClientContract } from '../../types'; import type { SavedObjectsFindResponse } from '../'; @@ -38,6 +38,13 @@ export interface PointInTimeFinderDependencies logger: Logger; } +/** + * @internal + */ +export type CreatePointInTimeFinderFn = ( + findOptions: SavedObjectsCreatePointInTimeFinderOptions +) => ISavedObjectsPointInTimeFinder; + /** @public */ export interface ISavedObjectsPointInTimeFinder { /** diff --git a/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.mock.ts b/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.mock.ts new file mode 100644 index 0000000000000..e774a178abd49 --- /dev/null +++ b/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.mock.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { findLegacyUrlAliases } from './find_legacy_url_aliases'; +import type * as InternalUtils from './internal_utils'; + +export const mockFindLegacyUrlAliases = jest.fn() as jest.MockedFunction< + typeof findLegacyUrlAliases +>; + +jest.mock('./find_legacy_url_aliases', () => { + return { findLegacyUrlAliases: mockFindLegacyUrlAliases }; +}); + +export const mockRawDocExistsInNamespaces = jest.fn() as jest.MockedFunction< + typeof InternalUtils['rawDocExistsInNamespaces'] +>; + +jest.mock('./internal_utils', () => { + const actual = jest.requireActual('./internal_utils'); + return { + ...actual, + rawDocExistsInNamespaces: mockRawDocExistsInNamespaces, + }; +}); diff --git a/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.ts b/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.ts new file mode 100644 index 0000000000000..8d7cfd25ac885 --- /dev/null +++ b/src/core/server/saved_objects/service/lib/preflight_check_for_create.test.ts @@ -0,0 +1,246 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + mockFindLegacyUrlAliases, + mockRawDocExistsInNamespaces, +} from './preflight_check_for_create.test.mock'; + +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; + +import type { ElasticsearchClient } from '../../../elasticsearch'; +import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; +import { LEGACY_URL_ALIAS_TYPE } from '../../object_types'; +import { typeRegistryMock } from '../../saved_objects_type_registry.mock'; +import { SavedObjectsSerializer } from '../../serialization'; +import type { CreatePointInTimeFinderFn } from './point_in_time_finder'; +import { + ALIAS_SEARCH_PER_PAGE, + PreflightCheckForCreateObject, + PreflightCheckForCreateParams, +} from './preflight_check_for_create'; +import { preflightCheckForCreate } from './preflight_check_for_create'; + +beforeEach(() => { + mockFindLegacyUrlAliases.mockReset(); + mockFindLegacyUrlAliases.mockResolvedValue(new Map()); // return an empty map by default + mockRawDocExistsInNamespaces.mockReset(); + mockRawDocExistsInNamespaces.mockReturnValue(true); // return true by default +}); + +describe('preflightCheckForCreate', () => { + let client: DeeplyMockedKeys; + + function setup(...objects: PreflightCheckForCreateObject[]): PreflightCheckForCreateParams { + const registry = typeRegistryMock.create(); + client = elasticsearchClientMock.createElasticsearchClient(); + const serializer = new SavedObjectsSerializer(registry); + return { + registry, + client, + serializer, + getIndexForType: (type: string) => `index-for-${type}`, + createPointInTimeFinder: jest.fn() as CreatePointInTimeFinderFn, + objects, + }; + } + + /** Mocks the saved objects client so it returns the expected results */ + function mockMgetResults( + ...results: Array<{ + found: boolean; + disabled?: boolean; // only used for alias results + }> + ) { + // instead of just mocking the response, we need to mock the implementation so we can correctly set the _id in the response docs + client.mget.mockImplementation((params, _options) => { + return elasticsearchClientMock.createSuccessTransportRequestPromise({ + docs: results.map(({ found, disabled }, i) => { + return found + ? { + // @ts-expect-error + _id: params!.body!.docs![i]._id as string, // needed for mockRawDocExistsInNamespaces mock implementation and existingDocument assertions + _index: 'doesnt-matter', + _source: { + ...(disabled !== undefined && { [LEGACY_URL_ALIAS_TYPE]: { disabled } }), + }, + found: true, + } + : { + _id: 'doesnt-matter', + _index: 'doesnt-matter', + found: false, + }; + }), + }); + }); + } + + /** Asserts that mget is called for the given raw object IDs */ + function expectMgetArgs(...rawObjectIds: string[]) { + const docs = rawObjectIds.map((_id) => expect.objectContaining({ _id })); + expect(client.mget).toHaveBeenCalledWith({ body: { docs } }, expect.anything()); + } + + /** Asserts that findLegacyUrlAliases is called for the given objects */ + function expectFindArgs(...objects: Array<{ type: string; id: string }>) { + expect(mockFindLegacyUrlAliases).toHaveBeenCalledWith( + expect.anything(), + objects.map(({ type, id }) => ({ type, id })), + ALIAS_SEARCH_PER_PAGE + ); + } + + it(`doesn't call mget if no object args are passed in`, async () => { + const params = setup(); + + await preflightCheckForCreate(params); + expectFindArgs(); // it *does* call findLegacyUrlAliases, but it's intentional beause that module handles an empty object array gracefully + expect(client.mget).not.toHaveBeenCalled(); + }); + + it(`uses find instead of mget when exceeding the alias threshold`, async () => { + const fourSpaces = ['a', 'b', 'c', 'd']; + const obj1 = { type: 'obj-type', id: 'id-1', overwrite: false, namespaces: ['a'] }; // mget aliases + const obj2 = { type: 'obj-type', id: 'id-2', overwrite: false, namespaces: ['*'] }; // find aliases because it exists in all spaces + const obj3 = { type: 'obj-type', id: 'id-3', overwrite: false, namespaces: ['a', 'b', 'c'] }; // mget aliases + const obj4 = { type: 'obj-type', id: 'id-4', overwrite: false, namespaces: fourSpaces }; // find aliases because it exists in 4 spaces (the threshold is 3) + const params = setup(obj1, obj2, obj3, obj4); + mockMgetResults(...new Array(8).fill({ found: false })); + await preflightCheckForCreate(params); + + expectFindArgs(obj2, obj4); + expectMgetArgs( + `${obj1.type}:${obj1.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj1.type}:${obj1.id}`, + `${obj2.type}:${obj2.id}`, + // we already searched for aliases for obj2 above, so we don't do it again during mget + `${obj3.type}:${obj3.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj3.type}:${obj3.id}`, + `${LEGACY_URL_ALIAS_TYPE}:b:${obj3.type}:${obj3.id}`, + `${LEGACY_URL_ALIAS_TYPE}:c:${obj3.type}:${obj3.id}`, + `${obj4.type}:${obj4.id}` + // we already searched for aliases for obj4 above, so we don't do it again during mget + ); + }); + + it(`returns mix of success and error results`, async () => { + const fourSpaces = ['a', 'b', 'c', 'd']; + const obj1 = { type: 'obj-type', id: 'id-1', overwrite: false, namespaces: ['*'] }; // success: find aliases, object not found + const obj2 = { type: 'obj-type', id: 'id-2', overwrite: true, namespaces: fourSpaces }; // success: find aliases, object found + const obj3 = { type: 'obj-type', id: 'id-3', overwrite: false, namespaces: ['a'] }; // success: mget aliases, object not found + const obj4 = { type: 'obj-type', id: 'id-4', overwrite: true, namespaces: ['a'] }; // success: mget aliases, object found + const obj5 = { type: 'obj-type', id: 'id-5', overwrite: true, namespaces: ['*'] }; // error: find aliases, alias conflict (1) + const obj6 = { type: 'obj-type', id: 'id-6', overwrite: true, namespaces: fourSpaces }; // error: find aliases, alias conflict (2) + const obj7 = { type: 'obj-type', id: 'id-7', overwrite: true, namespaces: ['a'] }; // error: mget aliases, alias conflict + const obj8 = { type: 'obj-type', id: 'id-8', overwrite: true, namespaces: fourSpaces }; // error: find aliases, unresolvable conflict + const obj9 = { type: 'obj-type', id: 'id-9', overwrite: true, namespaces: ['a'] }; // error: mget aliases, unresolvable conflict + const obj10 = { type: 'obj-type', id: 'id-10', overwrite: false, namespaces: fourSpaces }; // error: find aliases, regular conflict + const obj11 = { type: 'obj-type', id: 'id-11', overwrite: false, namespaces: ['a'] }; // error: mget aliases, regular conflict + + const params = setup(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11); + mockFindLegacyUrlAliases.mockResolvedValue( + new Map([ + // did not find aliases for obj1 + [`${obj2.type}:${obj2.id}`, new Set(['e'])], // found an alias for obj2, but it is not in the requested spaces, no problem + [`${obj5.type}:${obj5.id}`, new Set(['e'])], // found an alias for obj5, and obj5 should be created in all spaces -> this causes an alias conflict + [`${obj6.type}:${obj6.id}`, new Set(['b'])], // found an alias for obj6, and obj6 should be created in the same space -> this causes an alias conflict + // did not find aliases for obj8 or obj10 + ]) + ); + mockMgetResults( + { found: false }, // did not find obj1 + { found: true }, // found obj2, but it has overwrite enabled, no problem + { found: false }, // did not find obj3 + { found: false }, // did not find obj3 alias in "a" + { found: true }, // found obj4 + { found: true, disabled: true }, // found obj4 alias in "a", but it is disabled, no problem + // we do not mget obj5 or obj6 because they had alias conflicts from the earlier find operation + { found: true }, // found obj7, but it has overwrite enabled, no problem + { found: true, disabled: false }, // found obj7 alias in "a" -> this causes an alias conflict + { found: true }, // found obj8 + // we do not mget aliases for obj8 because we used find for those + { found: true }, // found obj9 + { found: false }, // did not find obj9 alias in "a" + { found: true }, // found obj10 -> this causes a regular conflict + // we do not mget aliases for obj10 because we used find for those + { found: true }, // found obj11 -> this causes a regular conflict + { found: false } // did not find obj11 alias in "a" + ); + mockRawDocExistsInNamespaces.mockImplementation((_registry, { _id }, _namespaces) => { + return _id !== `${obj8.type}:${obj8.id}` && _id !== `${obj9.type}:${obj9.id}`; // only obj8 and obj9 exist outside of the given spaces + }); + const result = await preflightCheckForCreate(params); + + expectFindArgs(obj1, obj2, obj5, obj6, obj8, obj10); + expectMgetArgs( + `${obj1.type}:${obj1.id}`, + // we already searched for aliases for obj1 above, so we don't do it again during mget + `${obj2.type}:${obj2.id}`, + // we already searched for aliases for obj2 above, so we don't do it again during mget + `${obj3.type}:${obj3.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj3.type}:${obj3.id}`, + `${obj4.type}:${obj4.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj4.type}:${obj4.id}`, + // we do not mget obj5 or obj6 because they had alias conflicts from the earlier find operation + `${obj7.type}:${obj7.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj7.type}:${obj7.id}`, + `${obj8.type}:${obj8.id}`, + // we already searched for aliases for obj8 above, so we don't do it again during mget + `${obj9.type}:${obj9.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj9.type}:${obj9.id}`, + `${obj10.type}:${obj10.id}`, + // we already searched for aliases for obj10 above, so we don't do it again during mget + `${obj11.type}:${obj11.id}`, + `${LEGACY_URL_ALIAS_TYPE}:a:${obj9.type}:${obj11.id}` + ); + expect(result).toEqual([ + // Success results: obj2 and obj4 include the existingDocument field because those objects were found + { type: obj1.type, id: obj1.id }, + { + type: obj2.type, + id: obj2.id, + existingDocument: expect.objectContaining({ _id: `${obj2.type}:${obj2.id}` }), + }, + { type: obj3.type, id: obj3.id }, + { + type: obj4.type, + id: obj4.id, + existingDocument: expect.objectContaining({ _id: `${obj4.type}:${obj4.id}` }), + }, + // Error results + { + type: obj5.type, + id: obj5.id, + error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['e'] } }, + }, + { + type: obj6.type, + id: obj6.id, + error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['b'] } }, + }, + { + type: obj7.type, + id: obj7.id, + error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['a'] } }, + }, + { + type: obj8.type, + id: obj8.id, + error: { type: 'unresolvableConflict', metadata: { isNotOverwritable: true } }, + }, + { + type: obj9.type, + id: obj9.id, + error: { type: 'unresolvableConflict', metadata: { isNotOverwritable: true } }, + }, + { type: obj10.type, id: obj10.id, error: { type: 'conflict' } }, + { type: obj11.type, id: obj11.id, error: { type: 'conflict' } }, + ]); + }); +}); diff --git a/src/core/server/saved_objects/service/lib/preflight_check_for_create.ts b/src/core/server/saved_objects/service/lib/preflight_check_for_create.ts new file mode 100644 index 0000000000000..6788cd8aa3abf --- /dev/null +++ b/src/core/server/saved_objects/service/lib/preflight_check_for_create.ts @@ -0,0 +1,285 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { LegacyUrlAlias, LEGACY_URL_ALIAS_TYPE } from '../../object_types'; +import type { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; +import type { + SavedObjectsRawDoc, + SavedObjectsRawDocSource, + SavedObjectsSerializer, +} from '../../serialization'; +import { findLegacyUrlAliases } from './find_legacy_url_aliases'; +import { Either, rawDocExistsInNamespaces } from './internal_utils'; +import { getObjectKey, isLeft, isRight } from './internal_utils'; +import type { CreatePointInTimeFinderFn } from './point_in_time_finder'; +import type { RepositoryEsClient } from './repository_es_client'; +import { ALL_NAMESPACES_STRING } from './utils'; + +/** + * If the object will be created in this many spaces (or "*" all current and future spaces), we use find to fetch all aliases. + * If the object does not exceed this threshold, we use mget to fetch aliases instead. + * This threshold is a bit arbitrary, but it is intended to optimize so we don't make expensive PIT/find operations unless it is necessary. + */ +const FIND_ALIASES_THRESHOLD = 3; + +/** + * How many aliases to search for per page. This is 1000 because consumers are relatively important operations and we could potentially be + * paging through many thousands of results. + * + * @internal + */ +export const ALIAS_SEARCH_PER_PAGE = 1000; + +export interface PreflightCheckForCreateObject { + /** The type of the object. */ + type: string; + /** The ID of the object. */ + id: string; + /** The namespaces that the consumer intends to create this object in. */ + namespaces: string[]; + /** Whether or not the object should be overwritten if it would encounter a regular conflict. */ + overwrite?: boolean; +} + +export interface PreflightCheckForCreateParams { + registry: ISavedObjectTypeRegistry; + client: RepositoryEsClient; + serializer: SavedObjectsSerializer; + getIndexForType: (type: string) => string; + createPointInTimeFinder: CreatePointInTimeFinderFn; + objects: PreflightCheckForCreateObject[]; +} + +export interface PreflightCheckForCreateResult { + /** The type of the object. */ + type: string; + /** The ID of the object. */ + id: string; + /** Only included if we did not encounter an error _and_ the object was found. */ + existingDocument?: SavedObjectsRawDoc; + /** Only included if we encountered an error. */ + error?: { + type: 'aliasConflict' | 'unresolvableConflict' | 'conflict'; + metadata?: { + spacesWithConflictingAliases?: string[]; + isNotOverwritable?: boolean; + }; + }; +} + +interface ParsedObject { + type: string; + id: string; + overwrite: boolean; + spaces: Set; +} + +/** + * Conducts pre-flight checks before object creation. Consumers should only check eligible objects (multi-namespace types). + * For each object that the consumer intends to create, we check for three potential error cases in all applicable spaces: + * + * 1. 'aliasConflict' - there is already an alias that points to a different object. + * 2. 'unresolvableConflict' - this object already exists in a different space and it cannot be overwritten with the given parameters. + * 3. 'conflict' - this object already exists (and the given options include `overwrite=false`). + * + * Objects can be created in 1-N spaces, and for each object+space combination we need to check if a legacy URL alias exists. This function + * attempts to optimize by defining an "alias threshold"; if we need to check for more aliases than that threshold, instead of attempting to + * bulk-get each one, we find (search for) them. This is intended to strike an acceptable balance of performance, and is necessary when + * creating objects in "*" (all current and future spaces) because we don't want to attempt to enumerate all spaces here. + * + * @param objects The objects that the consumer intends to create. + * + * @internal + */ +export async function preflightCheckForCreate(params: PreflightCheckForCreateParams) { + const { registry, client, serializer, getIndexForType, createPointInTimeFinder, objects } = + params; + + // Step 1: for each object, check if it is over the potential alias threshold; if so, attempt to search for aliases that may be affected. + // The result is a discriminated union: the left side is 'aliasConflict' errors, and the right side is objects/aliases to bulk-get. + const aliasConflictsOrObjectsToGet = await optionallyFindAliases( + createPointInTimeFinder, + objects + ); + + // Step 2: bulk-get all objects and aliases. + const objectsAndAliasesToBulkGet = aliasConflictsOrObjectsToGet + .filter(isRight) + .map(({ value }) => value); + const { bulkGetResponse, aliasSpaces } = await bulkGetObjectsAndAliases( + client, + serializer, + getIndexForType, + objectsAndAliasesToBulkGet + ); + + // Step 3: process all of the find and bulk-get results, and return appropriate results to the consumer. + let getResponseIndex = 0; + let aliasSpacesIndex = 0; + const results: PreflightCheckForCreateResult[] = []; + for (const either of aliasConflictsOrObjectsToGet) { + if (isLeft(either)) { + const { type, id, spacesWithConflictingAliases } = either.value; + const error = { + type: 'aliasConflict' as const, + metadata: { spacesWithConflictingAliases }, + }; + results.push({ type, id, error }); + } else { + const { type, id, spaces, overwrite, checkAliases } = either.value; + const objectDoc = bulkGetResponse?.body.docs[getResponseIndex++]!; + + if (checkAliases) { + const spacesWithConflictingAliases: string[] = []; + for (let i = 0; i < spaces.size; i++) { + const aliasDoc = bulkGetResponse?.body.docs[getResponseIndex++]; + const index = aliasSpacesIndex++; // increment whether the alias was found or not + if (aliasDoc?.found) { + const legacyUrlAlias: LegacyUrlAlias | undefined = + aliasDoc._source![LEGACY_URL_ALIAS_TYPE]; // if the 'disabled' field is not present, the source will be empty + if (!legacyUrlAlias?.disabled) { + // the alias was found, so the space we checked in has a conflicting alias + // in case the space in the alias's raw ID does not match the space in its sourceSpace field, prefer the former + spacesWithConflictingAliases.push(aliasSpaces[index]); + } + } + } + if (spacesWithConflictingAliases.length) { + const error = { + type: 'aliasConflict' as const, + metadata: { spacesWithConflictingAliases }, + }; + results.push({ type, id, error }); + continue; + } + } + + let existingDocument: PreflightCheckForCreateResult['existingDocument']; + if (objectDoc.found) { + // @ts-expect-error MultiGetHit._source is optional + if (!rawDocExistsInNamespaces(registry, objectDoc, [...spaces])) { + const error = { + type: 'unresolvableConflict' as const, + metadata: { isNotOverwritable: true }, + }; + results.push({ type, id, error }); + continue; + } else if (!overwrite) { + const error = { type: 'conflict' as const }; + results.push({ type, id, error }); + continue; + } + existingDocument = objectDoc as SavedObjectsRawDoc; + } + results.push({ type, id, existingDocument }); + } + } + return results; +} + +async function optionallyFindAliases( + createPointInTimeFinder: CreatePointInTimeFinderFn, + objects: PreflightCheckForCreateObject[] +) { + // Make a discriminated union based on the spaces the objects should be created in (Left=mget aliases, Right=find aliases) + const objectsToGetOrObjectsToFind = objects.map>((object) => { + const { type, id, namespaces, overwrite = false } = object; + const spaces = new Set(namespaces); + const tag = + spaces.size > FIND_ALIASES_THRESHOLD || spaces.has(ALL_NAMESPACES_STRING) ? 'Right' : 'Left'; + return { tag, value: { type, id, overwrite, spaces } }; + }); + + const objectsToFind = objectsToGetOrObjectsToFind + .filter(isRight) + .map(({ value: { type, id } }) => ({ type, id })); + const aliasMap = await findLegacyUrlAliases( + createPointInTimeFinder, + objectsToFind, + ALIAS_SEARCH_PER_PAGE + ); + + // Make another discriminated union based on the find results (Left=error, Right=mget objects/aliases) + const result = objectsToGetOrObjectsToFind.map< + Either< + ParsedObject & { spacesWithConflictingAliases: string[] }, + ParsedObject & { checkAliases: boolean } + > + >((either) => { + let checkAliases = true; + if (isRight(either)) { + const { type, id, spaces } = either.value; + const key = getObjectKey({ type, id }); + const spacesWithMatchingAliases = aliasMap.get(key); + if (spacesWithMatchingAliases) { + let spacesWithConflictingAliases: string[] = []; + if (spaces.has(ALL_NAMESPACES_STRING)) { + spacesWithConflictingAliases = [...spacesWithMatchingAliases]; + } else { + spacesWithConflictingAliases = intersection(spaces, spacesWithMatchingAliases); + } + if (spacesWithConflictingAliases.length) { + // we found one or more conflicting aliases, this is an error result + return { tag: 'Left', value: { ...either.value, spacesWithConflictingAliases } }; + } + } + // we checked for aliases but did not detect any conflicts; make sure we don't check for aliases again during mget + checkAliases = false; + } + return { tag: 'Right', value: { ...either.value, checkAliases } }; + }); + + return result; +} + +async function bulkGetObjectsAndAliases( + client: RepositoryEsClient, + serializer: SavedObjectsSerializer, + getIndexForType: (type: string) => string, + objectsAndAliasesToBulkGet: Array +) { + const docsToBulkGet: Array<{ _id: string; _index: string; _source: string[] }> = []; + const aliasSpaces: string[] = []; + for (const { type, id, spaces, checkAliases } of objectsAndAliasesToBulkGet) { + docsToBulkGet.push({ + _id: serializer.generateRawId(undefined, type, id), // namespace is intentionally undefined because multi-namespace objects don't have a namespace in their raw ID + _index: getIndexForType(type), + _source: ['type', 'namespaces'], + }); + if (checkAliases) { + for (const space of spaces) { + const rawAliasId = serializer.generateRawLegacyUrlAliasId(space, type, id); + docsToBulkGet.push({ + _id: rawAliasId, + _index: getIndexForType(LEGACY_URL_ALIAS_TYPE), + _source: [`${LEGACY_URL_ALIAS_TYPE}.disabled`], + }); + aliasSpaces.push(space); + } + } + } + + const bulkGetResponse = docsToBulkGet.length + ? await client.mget( + { body: { docs: docsToBulkGet } }, + { ignore: [404] } + ) + : undefined; + + return { bulkGetResponse, aliasSpaces }; +} + +function intersection(a: Set, b: Set) { + const result: T[] = []; + for (const x of a) { + if (b.has(x)) { + result.push(x); + } + } + return result; +} diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index 985d609f2da59..51ec81503956a 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -13,6 +13,7 @@ import { mockInternalBulkResolve, mockUpdateObjectsSpaces, mockGetCurrentTime, + mockPreflightCheckForCreate, } from './repository.test.mock'; import { SavedObjectsRepository } from './repository'; @@ -46,8 +47,6 @@ const createGenericNotFoundError = (...args) => SavedObjectsErrorHelpers.createGenericNotFoundError(...args).output.payload; const createUnsupportedTypeError = (...args) => SavedObjectsErrorHelpers.createUnsupportedTypeError(...args).output.payload; -const createGenericNotFoundEsUnavailableError = (...args) => - SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(...args).output.payload; describe('SavedObjectsRepository', () => { let client; @@ -316,6 +315,13 @@ describe('SavedObjectsRepository', () => { }); describe('#bulkCreate', () => { + beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return objects.map(({ type, id }) => ({ type, id })); // respond with no errors by default + }); + }); + const obj1 = { type: 'config', id: '6.0.0-alpha1', @@ -352,21 +358,11 @@ describe('SavedObjectsRepository', () => { }; const bulkCreateSuccess = async (objects, options) => { - const multiNamespaceObjects = objects.filter( - ({ type, id }) => registry.isMultiNamespace(type) && id - ); - if (multiNamespaceObjects?.length) { - const response = getMockMgetResponse(multiNamespaceObjects, options?.namespace); - client.mget.mockResolvedValue( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); - } const response = getMockBulkCreateResponse(objects, options?.namespace); client.bulk.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(response) ); const result = await savedObjectsRepository.bulkCreate(objects, options); - expect(client.mget).toHaveBeenCalledTimes(multiNamespaceObjects?.length ? 1 : 0); return result; }; @@ -420,15 +416,23 @@ describe('SavedObjectsRepository', () => { expect(client.bulk).toHaveBeenCalledTimes(1); }); - it(`should use the ES mget action before bulk action for any types that are multi-namespace, when id is defined`, async () => { + it(`should use the preflightCheckForCreate action before bulk action for any types that are multi-namespace, when id is defined`, async () => { const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; await bulkCreateSuccess(objects); expect(client.bulk).toHaveBeenCalledTimes(1); - expect(client.mget).toHaveBeenCalledTimes(1); - const docs = [ - expect.objectContaining({ _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${obj2.id}` }), - ]; - expect(client.mget.mock.calls[0][0].body).toEqual({ docs }); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { + type: MULTI_NAMESPACE_ISOLATED_TYPE, + id: obj2.id, + overwrite: false, + namespaces: ['default'], + }, + ], + }) + ); }); it(`should use the ES create method if ID is undefined and overwrite=true`, async () => { @@ -520,16 +524,25 @@ describe('SavedObjectsRepository', () => { it(`adds namespaces to request body for any types that are multi-namespace`, async () => { const test = async (namespace) => { const objects = [obj1, obj2].map((x) => ({ ...x, type: MULTI_NAMESPACE_ISOLATED_TYPE })); - const namespaces = [namespace ?? 'default']; + const [o1, o2] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + { type: o1.type, id: o1.id }, // first object does not have an existing document to overwrite + { + type: o2.type, + id: o2.id, + existingDocument: { _source: { namespaces: ['*'] } }, // second object does have an existing document to overwrite + }, + ]); await bulkCreateSuccess(objects, { namespace, overwrite: true }); - const expected = expect.objectContaining({ namespaces }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; + const expected1 = expect.objectContaining({ namespaces: [namespace ?? 'default'] }); + const expected2 = expect.objectContaining({ namespaces: ['*'] }); + const body = [expect.any(Object), expected1, expect.any(Object), expected2]; expect(client.bulk).toHaveBeenCalledWith( expect.objectContaining({ body }), expect.anything() ); client.bulk.mockClear(); - client.mget.mockClear(); + mockPreflightCheckForCreate.mockReset(); }; await test(undefined); await test(namespace); @@ -544,25 +557,46 @@ describe('SavedObjectsRepository', () => { { ...obj1, type: MULTI_NAMESPACE_ISOLATED_TYPE, initialNamespaces: [ns2] }, { ...obj1, type: MULTI_NAMESPACE_TYPE, initialNamespaces: [ns2, ns3] }, ]; + const [o1, o2, o3] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + // first object does not get passed in to preflightCheckForCreate at all + { type: o2.type, id: o2.id }, // second object does not have an existing document to overwrite + { + type: o3.type, + id: o3.id, + existingDocument: { + _source: { namespaces: [namespace ?? 'default', 'something-else'] }, // third object does have an existing document to overwrite + }, + }, + ]); await bulkCreateSuccess(objects, { namespace, overwrite: true }); const body = [ - { index: expect.objectContaining({ _id: `${ns2}:dashboard:${obj1.id}` }) }, + { index: expect.objectContaining({ _id: `${ns2}:dashboard:${o1.id}` }) }, expect.objectContaining({ namespace: ns2 }), { index: expect.objectContaining({ - _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${obj1.id}`, + _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${o2.id}`, }), }, expect.objectContaining({ namespaces: [ns2] }), - { index: expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${obj1.id}` }) }, + { index: expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${o3.id}` }) }, expect.objectContaining({ namespaces: [ns2, ns3] }), ]; + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + // assert that the initialNamespaces fields were passed into preflightCheckForCreate instead of the current namespace + { type: o2.type, id: o2.id, overwrite: true, namespaces: o2.initialNamespaces }, + { type: o3.type, id: o3.id, overwrite: true, namespaces: o3.initialNamespaces }, + ], + }) + ); expect(client.bulk).toHaveBeenCalledWith( expect.objectContaining({ body }), expect.anything() ); client.bulk.mockClear(); - client.mget.mockClear(); + mockPreflightCheckForCreate.mockReset(); }; await test(undefined); await test(namespace); @@ -581,7 +615,6 @@ describe('SavedObjectsRepository', () => { expect.anything() ); client.bulk.mockClear(); - client.mget.mockClear(); }; await test(undefined); await test(namespace); @@ -690,29 +723,6 @@ describe('SavedObjectsRepository', () => { }); }; - const unsupportedProductBulkCreateMgetError = async (objects, options) => { - const multiNamespaceObjects = objects.filter( - ({ type, id }) => registry.isMultiNamespace(type) && id - ); - if (multiNamespaceObjects?.length) { - const response = getMockMgetResponse(multiNamespaceObjects, options?.namespace); - client.mget.mockResolvedValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...response }, - { statusCode: 404 }, - {} - ) - ); - } - const response = getMockBulkCreateResponse(objects, options?.namespace); - client.bulk.mockResolvedValue( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); - await expect(savedObjectsRepository.bulkCreate(objects, options)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError() - ); - }; - it(`throws when options.namespace is '*'`, async () => { await expect( savedObjectsRepository.bulkCreate([obj3], { namespace: ALL_NAMESPACES_STRING }) @@ -773,94 +783,60 @@ describe('SavedObjectsRepository', () => { await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); }); - it(`returns error when there is a conflict with an existing multi-namespace saved object (get)`, async () => { - const obj = { ...obj3, type: MULTI_NAMESPACE_ISOLATED_TYPE }; - const response1 = { - status: 200, - docs: [ - { - found: true, - _source: { - type: obj.type, - namespaces: ['bar-namespace'], - }, - }, - ], - }; - client.mget.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response1) - ); - const response2 = getMockBulkCreateResponse([obj1, obj2]); + it(`returns error when there is a conflict from preflightCheckForCreate`, async () => { + const objects = [ + // only the second, third, and fourth objects are passed to preflightCheckForCreate and result in errors + obj1, + { ...obj1, type: MULTI_NAMESPACE_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_TYPE }, + { ...obj3, type: MULTI_NAMESPACE_TYPE }, + obj2, + ]; + const [o1, o2, o3, o4, o5] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + // first and last objects do not get passed in to preflightCheckForCreate at all + { type: o2.type, id: o2.id, error: { type: 'conflict' } }, + { + type: o3.type, + id: o3.id, + error: { type: 'unresolvableConflict', metadata: { isNotOverwritable: true } }, + }, + { + type: o4.type, + id: o4.id, + error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['foo'] } }, + }, + ]); + const bulkResponse = getMockBulkCreateResponse([o1, o5]); client.bulk.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response2) + elasticsearchClientMock.createSuccessTransportRequestPromise(bulkResponse) ); const options = { overwrite: true }; - const result = await savedObjectsRepository.bulkCreate([obj1, obj, obj2], options); - expect(client.bulk).toHaveBeenCalled(); - expect(client.mget).toHaveBeenCalled(); - - const body1 = { docs: [expect.objectContaining({ _id: `${obj.type}:${obj.id}` })] }; - expect(client.mget).toHaveBeenCalledWith( - expect.objectContaining({ body: body1 }), - expect.anything() - ); - const body2 = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body: body2 }), - expect.anything() - ); - const expectedError = expectErrorConflict(obj, { metadata: { isNotOverwritable: true } }); - expect(result).toEqual({ - saved_objects: [expectSuccess(obj1), expectedError, expectSuccess(obj2)], - }); - }); - - it(`returns error when there is an unresolvable conflict with an existing multi-namespace saved object when using initialNamespaces (get)`, async () => { - const obj = { - ...obj3, - type: MULTI_NAMESPACE_TYPE, - initialNamespaces: ['foo-namespace', 'default'], - }; - const response1 = { - status: 200, - docs: [ - { - found: true, - _source: { - type: obj.type, - namespaces: ['bar-namespace'], - }, - }, - ], - }; - client.mget.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response1) - ); - const response2 = getMockBulkCreateResponse([obj1, obj2]); - client.bulk.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response2) + const result = await savedObjectsRepository.bulkCreate(objects, options); + expect(mockPreflightCheckForCreate).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { type: o2.type, id: o2.id, overwrite: true, namespaces: ['default'] }, + { type: o3.type, id: o3.id, overwrite: true, namespaces: ['default'] }, + { type: o4.type, id: o4.id, overwrite: true, namespaces: ['default'] }, + ], + }) ); - - const options = { overwrite: true }; - const result = await savedObjectsRepository.bulkCreate([obj1, obj, obj2], options); - expect(client.bulk).toHaveBeenCalled(); - expect(client.mget).toHaveBeenCalled(); - - const body1 = { docs: [expect.objectContaining({ _id: `${obj.type}:${obj.id}` })] }; - expect(client.mget).toHaveBeenCalledWith( - expect.objectContaining({ body: body1 }), - expect.anything() - ); - const body2 = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body: body2 }), + expect.objectContaining({ body: [...expectObjArgs(o1), ...expectObjArgs(o5)] }), expect.anything() ); - const expectedError = expectErrorConflict(obj, { metadata: { isNotOverwritable: true } }); expect(result).toEqual({ - saved_objects: [expectSuccess(obj1), expectedError, expectSuccess(obj2)], + saved_objects: [ + expectSuccess(o1), + expectErrorConflict(o2), + expectErrorConflict(o3, { metadata: { isNotOverwritable: true } }), + expectErrorConflict(o4, { metadata: { spacesWithConflictingAliases: ['foo'] } }), + expectSuccess(o5), + ], }); }); @@ -868,13 +844,6 @@ describe('SavedObjectsRepository', () => { const expectedErrorResult = { type: obj3.type, id: obj3.id, error: 'Oh no, a bulk error!' }; await bulkCreateError(obj3, true, expectedErrorResult); }); - - it(`throws when ES mget action returns 404 with missing Elasticsearch header`, async () => { - const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; - await unsupportedProductBulkCreateMgetError(objects); - expect(client.mget).toHaveBeenCalledTimes(1); - expect(client.bulk).toHaveBeenCalledTimes(0); - }); }); describe('migration', () => { @@ -1136,21 +1105,6 @@ describe('SavedObjectsRepository', () => { }); }; - const unsupportedProductBulkGetMgetError = async (objects, options) => { - const response = getMockMgetResponse(objects, options?.namespace); - client.mget.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...response }, - { statusCode: 404 }, - {} - ) - ); - await expect(bulkGet(objects, options)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError() - ); - expect(client.mget).toHaveBeenCalledTimes(1); - }; - it(`throws when options.namespace is '*'`, async () => { const obj = { type: 'dashboard', id: 'three' }; await expect( @@ -1218,12 +1172,6 @@ describe('SavedObjectsRepository', () => { }; await bulkGetError(obj, true, expectErrorNotFound(obj)); }); - - it(`throws when ES mget action responds with a 404 and a missing Elasticsearch product header`, async () => { - const getId = (type, id) => `${type}:${id}`; - await unsupportedProductBulkGetMgetError([obj1, obj2]); // returns 404 without required product header - _expectClientCallArgs([obj1, obj2], { getId }); - }); }); describe('returns', () => { @@ -1681,34 +1629,6 @@ describe('SavedObjectsRepository', () => { saved_objects: [expectSuccess(obj1), expectErrorNotFound(_obj), expectSuccess(obj2)], }); }; - const unsupportedProductBulkUpdateMgetError = async (objects, options, includeOriginId) => { - const multiNamespaceObjects = objects.filter(({ type }) => registry.isMultiNamespace(type)); - if (multiNamespaceObjects?.length) { - const response = getMockMgetResponse(multiNamespaceObjects, options?.namespace); - client.mget.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...response }, - { statusCode: 404 }, - {} - ) - ); - } - const response = getMockBulkUpdateResponse(objects, options?.namespace, includeOriginId); - client.bulk.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); - - await expect(savedObjectsRepository.bulkUpdate(objects, options)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError() - ); - expect(client.mget).toHaveBeenCalledTimes(multiNamespaceObjects?.length ? 1 : 0); - }; - - it(`throws when ES mget action responds with a 404 and a missing Elasticsearch product header`, async () => { - const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; - await unsupportedProductBulkUpdateMgetError(objects); - expect(client.mget).toHaveBeenCalledTimes(1); - }); it(`throws when options.namespace is '*'`, async () => { await expect( @@ -1910,24 +1830,6 @@ describe('SavedObjectsRepository', () => { savedObjectsRepository.checkConflicts([obj1], { namespace: ALL_NAMESPACES_STRING }) ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); }); - - it(`throws when not found responses aren't from Elasticsearch`, async () => { - const checkConflictsMgetError = async (objects, options) => { - const response = getMockMgetResponse(objects, options?.namespace); - client.mget.mockResolvedValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...response }, - { statusCode: 404 }, - {} - ) - ); - await expect(checkConflicts(objects, options)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError() - ); - expect(client.mget).toHaveBeenCalledTimes(1); - }; - await checkConflictsMgetError([obj1, obj2], { namespace: 'default' }); - }); }); describe('returns', () => { @@ -1978,6 +1880,10 @@ describe('SavedObjectsRepository', () => { describe('#create', () => { beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return objects.map(({ type, id }) => ({ type, id })); // respond with no errors by default + }); client.create.mockImplementation((params) => elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: params.id, @@ -2001,27 +1907,26 @@ describe('SavedObjectsRepository', () => { const createSuccess = async (type, attributes, options) => { const result = await savedObjectsRepository.create(type, attributes, options); - expect(client.get).toHaveBeenCalledTimes( - registry.isMultiNamespace(type) && options.overwrite ? 1 : 0 - ); return result; }; describe('client calls', () => { - it(`should use the ES index action if overwrite=true`, async () => { + it(`should use the ES index action if ID is not defined and overwrite=true`, async () => { await createSuccess(type, attributes, { overwrite: true }); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); expect(client.index).toHaveBeenCalled(); }); - it(`should use the ES create action if overwrite=false`, async () => { + it(`should use the ES create action if ID is not defined and overwrite=false`, async () => { await createSuccess(type, attributes); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); expect(client.create).toHaveBeenCalled(); }); it(`should use the ES index with version if ID and version are defined and overwrite=true`, async () => { await createSuccess(type, attributes, { id, overwrite: true, version: mockVersion }); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); expect(client.index).toHaveBeenCalled(); - expect(client.index.mock.calls[0][0]).toMatchObject({ if_seq_no: mockVersionProps._seq_no, if_primary_term: mockVersionProps._primary_term, @@ -2030,12 +1935,33 @@ describe('SavedObjectsRepository', () => { it(`should use the ES create action if ID is defined and overwrite=false`, async () => { await createSuccess(type, attributes, { id }); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.create).toHaveBeenCalled(); + }); + + it(`should use the preflightCheckForCreate action then create action if type is multi-namespace, ID is defined, and overwrite=false`, async () => { + await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id }); + expect(mockPreflightCheckForCreate).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { type: MULTI_NAMESPACE_TYPE, id, overwrite: false, namespaces: ['default'] }, + ], + }) + ); expect(client.create).toHaveBeenCalled(); }); - it(`should use the ES get action then index action if type is multi-namespace, ID is defined, and overwrite=true`, async () => { + it(`should use the preflightCheckForCreate action then index action if type is multi-namespace, ID is defined, and overwrite=true`, async () => { await createSuccess(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { id, overwrite: true }); - expect(client.get).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { type: MULTI_NAMESPACE_ISOLATED_TYPE, id, overwrite: true, namespaces: ['default'] }, + ], + }) + ); expect(client.index).toHaveBeenCalled(); }); @@ -2155,36 +2081,103 @@ describe('SavedObjectsRepository', () => { }); it(`doesn't prepend namespace to the id and adds namespaces to body when using multi-namespace type`, async () => { - await createSuccess(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { id, namespace }); + // first object does not have an existing document to overwrite + await createSuccess(MULTI_NAMESPACE_TYPE, attributes, { id, namespace }); + mockPreflightCheckForCreate.mockResolvedValueOnce([ + { + type: MULTI_NAMESPACE_TYPE, + id, + existingDocument: { _source: { namespaces: ['*'] } }, // second object does have an existing document to overwrite + }, + ]); + await createSuccess(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { + id, + namespace, + overwrite: true, + }); + + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(2); + expect(mockPreflightCheckForCreate).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + objects: [ + { type: MULTI_NAMESPACE_TYPE, id, overwrite: false, namespaces: [namespace] }, + ], + }) + ); + expect(mockPreflightCheckForCreate).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + objects: [ + { type: MULTI_NAMESPACE_ISOLATED_TYPE, id, overwrite: true, namespaces: [namespace] }, + ], + }) + ); + + expect(client.create).toHaveBeenCalledTimes(1); expect(client.create).toHaveBeenCalledWith( expect.objectContaining({ - id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`, + id: `${MULTI_NAMESPACE_TYPE}:${id}`, body: expect.objectContaining({ namespaces: [namespace] }), }), expect.anything() ); + expect(client.index).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ + id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`, + body: expect.objectContaining({ namespaces: ['*'] }), + }), + expect.anything() + ); }); it(`adds initialNamespaces instead of namespace`, async () => { const ns2 = 'bar-namespace'; const ns3 = 'baz-namespace'; + // first object does not get passed in to preflightCheckForCreate at all await savedObjectsRepository.create('dashboard', attributes, { id, namespace, initialNamespaces: [ns2], }); - await savedObjectsRepository.create(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { + // second object does not have an existing document to overwrite + await savedObjectsRepository.create(MULTI_NAMESPACE_TYPE, attributes, { id, namespace, - initialNamespaces: [ns2], + initialNamespaces: [ns2, ns3], }); - await savedObjectsRepository.create(MULTI_NAMESPACE_TYPE, attributes, { + mockPreflightCheckForCreate.mockResolvedValueOnce([ + { + type: MULTI_NAMESPACE_ISOLATED_TYPE, + id, + existingDocument: { _source: { namespaces: ['something-else'] } }, // third object does have an existing document to overwrite + }, + ]); + await savedObjectsRepository.create(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { id, namespace, - initialNamespaces: [ns2, ns3], + initialNamespaces: [ns2], + overwrite: true, }); - expect(client.create).toHaveBeenCalledTimes(3); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(2); + expect(mockPreflightCheckForCreate).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + objects: [{ type: MULTI_NAMESPACE_TYPE, id, overwrite: false, namespaces: [ns2, ns3] }], + }) + ); + expect(mockPreflightCheckForCreate).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + objects: [ + { type: MULTI_NAMESPACE_ISOLATED_TYPE, id, overwrite: true, namespaces: [ns2] }, + ], + }) + ); + + expect(client.create).toHaveBeenCalledTimes(2); expect(client.create).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -2196,16 +2189,16 @@ describe('SavedObjectsRepository', () => { expect(client.create).toHaveBeenNthCalledWith( 2, expect.objectContaining({ - id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`, - body: expect.objectContaining({ namespaces: [ns2] }), + id: `${MULTI_NAMESPACE_TYPE}:${id}`, + body: expect.objectContaining({ namespaces: [ns2, ns3] }), }), expect.anything() ); - expect(client.create).toHaveBeenNthCalledWith( - 3, + expect(client.index).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledWith( expect.objectContaining({ - id: `${MULTI_NAMESPACE_TYPE}:${id}`, - body: expect.objectContaining({ namespaces: [ns2, ns3] }), + id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`, + body: expect.objectContaining({ namespaces: [ns2] }), }), expect.anything() ); @@ -2299,14 +2292,10 @@ describe('SavedObjectsRepository', () => { expect(client.create).not.toHaveBeenCalled(); }); - it(`throws when there is a conflict with an existing multi-namespace saved object (get)`, async () => { - const response = getMockGetResponse( - { type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, - 'bar-namespace' - ); - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); + it(`throws when there is a conflict from preflightCheckForCreate`, async () => { + mockPreflightCheckForCreate.mockResolvedValueOnce([ + { type: MULTI_NAMESPACE_ISOLATED_TYPE, id, error: { type: 'unresolvableConflict' } }, // error type and metadata dont matter + ]); await expect( savedObjectsRepository.create(MULTI_NAMESPACE_ISOLATED_TYPE, attributes, { id, @@ -2314,23 +2303,7 @@ describe('SavedObjectsRepository', () => { namespace, }) ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_ISOLATED_TYPE, id)); - expect(client.get).toHaveBeenCalled(); - }); - - it(`throws when there is an unresolvable conflict with an existing multi-namespace saved object when using initialNamespaces (get)`, async () => { - const response = getMockGetResponse({ type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, namespace); - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); - await expect( - savedObjectsRepository.create(MULTI_NAMESPACE_TYPE, attributes, { - id, - overwrite: true, - initialNamespaces: ['bar-ns', 'dolly-ns'], - namespace, - }) - ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_TYPE, id)); - expect(client.get).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalled(); }); it.todo(`throws when automatic index creation fails`); @@ -2515,11 +2488,6 @@ describe('SavedObjectsRepository', () => { createGenericNotFoundError(type, id) ); }; - const expectNotFoundEsUnavailableError = async (type, id) => { - await expect(savedObjectsRepository.delete(type, id)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError(type, id) - ); - }; it(`throws when options.namespace is '*'`, async () => { await expect( @@ -2553,24 +2521,6 @@ describe('SavedObjectsRepository', () => { expect(client.get).toHaveBeenCalledTimes(1); }); - it(`throws when ES is unable to find the document during get with missing Elasticsearch header`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { found: false }, - { statusCode: 404 }, - {} - ) - ); - await expectNotFoundEsUnavailableError(MULTI_NAMESPACE_ISOLATED_TYPE, id); - }); - - it(`throws when ES is unable to find the index during get with missing Elasticsearch header`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }, {}) - ); - await expectNotFoundEsUnavailableError(MULTI_NAMESPACE_ISOLATED_TYPE, id); - }); - it(`throws when the type is multi-namespace and the document exists, but not in this namespace`, async () => { const response = getMockGetResponse({ type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, namespace); client.get.mockResolvedValueOnce( @@ -2885,22 +2835,6 @@ describe('SavedObjectsRepository', () => { savedObjectsRepository.removeReferencesTo(type, id, defaultOptions) ).rejects.toThrowError(createConflictError(type, id)); }); - - it(`throws on 404 with missing Elasticsearch header`, async () => { - client.updateByQuery.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { - updated: updatedCount, - }, - { statusCode: 404 }, - {} - ) - ); - await expect( - savedObjectsRepository.removeReferencesTo(type, id, defaultOptions) - ).rejects.toThrowError(createGenericNotFoundEsUnavailableError(type, id)); - expect(client.updateByQuery).toHaveBeenCalledTimes(1); - }); }); }); @@ -3077,21 +3011,6 @@ describe('SavedObjectsRepository', () => { }); describe('errors', () => { - const findNotSupportedServerError = async (options, namespace) => { - const expectedSearchResults = generateSearchResults(namespace); - client.search.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...expectedSearchResults }, - { statusCode: 404 }, - {} - ) - ); - await expect(savedObjectsRepository.find(options)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError() - ); - expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1); - expect(client.search).toHaveBeenCalledTimes(1); - }; it(`throws when type is not defined`, async () => { await expect(savedObjectsRepository.find({})).rejects.toThrowError( 'options.type must be a string or an array of strings' @@ -3172,11 +3091,6 @@ describe('SavedObjectsRepository', () => { expect(getSearchDslNS.getSearchDsl).not.toHaveBeenCalled(); expect(client.search).not.toHaveBeenCalled(); }); - - it(`throws when ES is unable to find with missing Elasticsearch`, async () => { - await findNotSupportedServerError({ type }); - expect(client.search).toHaveBeenCalledTimes(1); - }); }); describe('returns', () => { @@ -3548,11 +3462,6 @@ describe('SavedObjectsRepository', () => { createGenericNotFoundError(type, id) ); }; - const expectNotFoundEsUnavailableError = async (type, id) => { - await expect(savedObjectsRepository.get(type, id)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError(type, id) - ); - }; it(`throws when options.namespace is '*'`, async () => { await expect( @@ -3596,19 +3505,6 @@ describe('SavedObjectsRepository', () => { }); expect(client.get).toHaveBeenCalledTimes(1); }); - - it(`throws when ES does not return the correct header when finding the document during get`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { found: false }, - { statusCode: 404 }, - {} - ) - ); - await expectNotFoundEsUnavailableError(type, id); - - expect(client.get).toHaveBeenCalledTimes(1); - }); }); describe('returns', () => { @@ -3689,10 +3585,12 @@ describe('SavedObjectsRepository', () => { const namespace = 'foo-namespace'; const originId = 'some-origin-id'; - const incrementCounterSuccess = async (type, id, fields, options) => { + const incrementCounterSuccess = async (type, id, fields, options, internalOptions = {}) => { + const { mockGetResponseValue } = internalOptions; const isMultiNamespace = registry.isMultiNamespace(type); if (isMultiNamespace) { - const response = getMockGetResponse({ type, id }, options?.namespace); + const response = + mockGetResponseValue ?? getMockGetResponse({ type, id }, options?.namespace); client.get.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise(response) ); @@ -3724,9 +3622,18 @@ describe('SavedObjectsRepository', () => { return result; }; + beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return objects.map(({ type, id }) => ({ type, id })); // respond with no errors by default + }); + }); + describe('client calls', () => { it(`should use the ES update action if type is not multi-namespace`, async () => { await incrementCounterSuccess(type, id, counterFields, { namespace }); + expect(client.get).not.toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); expect(client.update).toHaveBeenCalledTimes(1); }); @@ -3735,6 +3642,20 @@ describe('SavedObjectsRepository', () => { namespace, }); expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.update).toHaveBeenCalledTimes(1); + }); + + it(`should check for alias conflicts if a new multi-namespace object would be created`, async () => { + await incrementCounterSuccess( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + counterFields, + { namespace }, + { mockGetResponseValue: { found: false } } + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); expect(client.update).toHaveBeenCalledTimes(1); }); @@ -3903,6 +3824,43 @@ describe('SavedObjectsRepository', () => { ) ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_ISOLATED_TYPE, id)); expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.update).not.toHaveBeenCalled(); + }); + + it(`throws when there is an alias conflict from preflightCheckForCreate`, async () => { + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ found: false }) + ); + mockPreflightCheckForCreate.mockResolvedValue([{ error: { type: 'aliasConflict' } }]); + await expect( + savedObjectsRepository.incrementCounter( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + counterFields, + { namespace } + ) + ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_ISOLATED_TYPE, id)); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.update).not.toHaveBeenCalled(); + }); + + it(`does not throw when there is a different error from preflightCheckForCreate`, async () => { + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ found: false }) + ); + mockPreflightCheckForCreate.mockResolvedValue([{ error: { type: 'something-else' } }]); + await incrementCounterSuccess( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + counterFields, + { namespace }, + { mockGetResponseValue: { found: false } } + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.update).toHaveBeenCalledTimes(1); }); }); @@ -4048,9 +4006,11 @@ describe('SavedObjectsRepository', () => { ); }; - const updateSuccess = async (type, id, attributes, options, includeOriginId) => { + const updateSuccess = async (type, id, attributes, options, internalOptions = {}) => { + const { mockGetResponseValue, includeOriginId } = internalOptions; if (registry.isMultiNamespace(type)) { - const mockGetResponse = getMockGetResponse({ type, id }, options?.namespace); + const mockGetResponse = + mockGetResponseValue ?? getMockGetResponse({ type, id }, options?.namespace); client.get.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise( { ...mockGetResponse }, @@ -4064,15 +4024,38 @@ describe('SavedObjectsRepository', () => { return result; }; + beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return objects.map(({ type, id }) => ({ type, id })); // respond with no errors by default + }); + }); + describe('client calls', () => { + it(`should use the ES update action when type is not multi-namespace`, async () => { + await updateSuccess(type, id, attributes); + expect(client.get).not.toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.update).toHaveBeenCalledTimes(1); + }); + it(`should use the ES get action then update action when type is multi-namespace`, async () => { await updateSuccess(MULTI_NAMESPACE_ISOLATED_TYPE, id, attributes); expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); expect(client.update).toHaveBeenCalledTimes(1); }); - it(`should use the ES update action when type is not multi-namespace`, async () => { - await updateSuccess(type, id, attributes); + it(`should check for alias conflicts if a new multi-namespace object would be created`, async () => { + await updateSuccess( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { upsert: true }, + { mockGetResponseValue: { found: false } } + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); expect(client.update).toHaveBeenCalledTimes(1); }); @@ -4279,11 +4262,6 @@ describe('SavedObjectsRepository', () => { createGenericNotFoundError(type, id) ); }; - const expectNotFoundEsUnavailableError = async (type, id) => { - await expect(savedObjectsRepository.update(type, id)).rejects.toThrowError( - createGenericNotFoundEsUnavailableError(type, id) - ); - }; it(`throws when options.namespace is '*'`, async () => { await expect( @@ -4317,35 +4295,42 @@ describe('SavedObjectsRepository', () => { expect(client.get).toHaveBeenCalledTimes(1); }); - it(`throws when ES is unable to find the document during get with missing Elasticsearch header`, async () => { + it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => { + const response = getMockGetResponse({ type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, namespace); client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { found: false }, - { statusCode: 404 }, - {} - ) + elasticsearchClientMock.createSuccessTransportRequestPromise(response) ); - await expectNotFoundEsUnavailableError(MULTI_NAMESPACE_ISOLATED_TYPE, id); + await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id, { + namespace: 'bar-namespace', + }); expect(client.get).toHaveBeenCalledTimes(1); }); - it(`throws when ES is unable to find the index during get with missing Elasticsearch header`, async () => { + it(`throws when there is an alias conflict from preflightCheckForCreate`, async () => { client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }, {}) + elasticsearchClientMock.createSuccessTransportRequestPromise({ found: false }) ); - await expectNotFoundEsUnavailableError(MULTI_NAMESPACE_ISOLATED_TYPE, id); + mockPreflightCheckForCreate.mockResolvedValue([{ error: { type: 'aliasConflict' } }]); + await expect( + savedObjectsRepository.update(MULTI_NAMESPACE_ISOLATED_TYPE, id, {}, { upsert: true }) + ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_ISOLATED_TYPE, id)); expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.update).not.toHaveBeenCalled(); }); - it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => { - const response = getMockGetResponse({ type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, namespace); - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) + it(`does not throw when there is a different error from preflightCheckForCreate`, async () => { + mockPreflightCheckForCreate.mockResolvedValue([{ error: { type: 'something-else' } }]); + await updateSuccess( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { upsert: true }, + { mockGetResponseValue: { found: false } } ); - await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id, { - namespace: 'bar-namespace', - }); expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.update).toHaveBeenCalledTimes(1); }); it(`throws when ES is unable to find the document during update`, async () => { @@ -4395,7 +4380,7 @@ describe('SavedObjectsRepository', () => { }); it(`includes originId property if present in cluster call response`, async () => { - const result = await updateSuccess(type, id, attributes, {}, true); + const result = await updateSuccess(type, id, attributes, {}, { includeOriginId: true }); expect(result).toMatchObject({ originId }); }); }); @@ -4458,21 +4443,6 @@ describe('SavedObjectsRepository', () => { ); }; - const unsupportedProductExpectNotFoundError = async (type, options) => { - const results = generateResults(); - client.openPointInTime.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { ...results }, - { statusCode: 404 }, - {} - ) - ); - await expect( - savedObjectsRepository.openPointInTimeForType(type, options) - ).rejects.toThrowError(createGenericNotFoundEsUnavailableError()); - expect(client.openPointInTime).toHaveBeenCalledTimes(1); - }; - it(`throws when ES is unable to find the index`, async () => { client.openPointInTime.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) @@ -4491,11 +4461,6 @@ describe('SavedObjectsRepository', () => { await test(HIDDEN_TYPE); await test(['unknownType', HIDDEN_TYPE]); }); - - it(`throws on 404 with missing Elasticsearch product header`, async () => { - await unsupportedProductExpectNotFoundError(type); - expect(client.openPointInTime).toHaveBeenCalledTimes(1); - }); }); describe('returns', () => { diff --git a/src/core/server/saved_objects/service/lib/repository.test.mock.ts b/src/core/server/saved_objects/service/lib/repository.test.mock.ts index d9a611226f8b5..88eb13e3ca46b 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.mock.ts +++ b/src/core/server/saved_objects/service/lib/repository.test.mock.ts @@ -9,6 +9,7 @@ import type { collectMultiNamespaceReferences } from './collect_multi_namespace_references'; import type { internalBulkResolve } from './internal_bulk_resolve'; import type * as InternalUtils from './internal_utils'; +import type { preflightCheckForCreate } from './preflight_check_for_create'; import type { updateObjectsSpaces } from './update_objects_spaces'; export const mockCollectMultiNamespaceReferences = jest.fn() as jest.MockedFunction< @@ -41,6 +42,14 @@ jest.mock('./internal_utils', () => { }; }); +export const mockPreflightCheckForCreate = jest.fn() as jest.MockedFunction< + typeof preflightCheckForCreate +>; + +jest.mock('./preflight_check_for_create', () => ({ + preflightCheckForCreate: mockPreflightCheckForCreate, +})); + export const mockUpdateObjectsSpaces = jest.fn() as jest.MockedFunction; jest.mock('./update_objects_spaces', () => ({ diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 6798f411d87a9..383801e790c76 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -7,10 +7,9 @@ */ import { omit, isObject } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as esKuery from '@kbn/es-query'; import type { ElasticsearchClient } from '../../../elasticsearch/'; -import { isSupportedEsServer, isNotFoundFromUnsupportedServer } from '../../../elasticsearch'; import type { Logger } from '../../../logging'; import { getRootPropertiesObjects, IndexMapping } from '../../mappings'; import { @@ -97,6 +96,10 @@ import { SavedObjectsUpdateObjectsSpacesOptions, } from './update_objects_spaces'; import { getIndexForType } from './get_index_for_type'; +import { + preflightCheckForCreate, + PreflightCheckForCreateObject, +} from './preflight_check_for_create'; // BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient. @@ -325,19 +328,23 @@ export class SavedObjectsRepository { ? normalizeNamespace(initialNamespaces[0]) : namespace; } else if (this._registry.isMultiNamespace(type)) { - if (id && overwrite) { + if (options.id) { // we will overwrite a multi-namespace saved object if it exists; if that happens, ensure we preserve its included namespaces // note: this check throws an error if the object is found but does not exist in this namespace - const preflightResult = await this.preflightCheckNamespaces({ - type, - id, - namespace, - initialNamespaces, + const namespaceString = SavedObjectsUtils.namespaceIdToString(namespace); + const [{ error, existingDocument }] = await preflightCheckForCreate({ + registry: this._registry, + client: this.client, + serializer: this._serializer, + getIndexForType: this.getIndexForType.bind(this), + createPointInTimeFinder: this.createPointInTimeFinder.bind(this), + objects: [{ type, id, overwrite, namespaces: initialNamespaces ?? [namespaceString] }], }); - if (preflightResult.checkResult === 'found_outside_namespace') { + if (error) { throw SavedObjectsErrorHelpers.createConflictError(type, id); } - savedObjectNamespaces = preflightResult.savedObjectNamespaces; + savedObjectNamespaces = + initialNamespaces || getSavedObjectNamespaces(namespace, existingDocument); } else { savedObjectNamespaces = initialNamespaces || getSavedObjectNamespaces(namespace); } @@ -366,15 +373,11 @@ export class SavedObjectsRepository { require_alias: true, }; - const { body, statusCode, headers } = + const { body } = id && overwrite ? await this.client.index(requestParams) : await this.client.create(requestParams); - // throw if we can't verify a 404 response is from Elasticsearch - if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(id, type); - } return this._rawToSavedObject({ ...raw, ...body, @@ -398,169 +401,149 @@ export class SavedObjectsRepository { const namespace = normalizeNamespace(options.namespace); const time = getCurrentTime(); - let bulkGetRequestIndexCounter = 0; - const expectedResults: Array, Record>> = objects.map( - (object) => { - const { type, id, initialNamespaces } = object; - let error: DecoratedError | undefined; - if (!this._allowedTypes.includes(type)) { - error = SavedObjectsErrorHelpers.createUnsupportedTypeError(type); - } else { - try { - this.validateInitialNamespaces(type, initialNamespaces); - } catch (e) { - error = e; - } - } - - if (error) { - return { - tag: 'Left', - value: { id, type, error: errorContent(error) }, - }; + let preflightCheckIndexCounter = 0; + const expectedResults = objects.map< + Either< + { type: string; id?: string; error: Payload }, + { + method: 'index' | 'create'; + object: SavedObjectsBulkCreateObject & { id: string }; + preflightCheckIndex?: number; } - - const method = id && overwrite ? 'index' : 'create'; - const requiresNamespacesCheck = id && this._registry.isMultiNamespace(type); - - if (id == null) { - object.id = SavedObjectsUtils.generateId(); + > + >((object) => { + const { type, id, initialNamespaces } = object; + let error: DecoratedError | undefined; + if (!this._allowedTypes.includes(type)) { + error = SavedObjectsErrorHelpers.createUnsupportedTypeError(type); + } else { + try { + this.validateInitialNamespaces(type, initialNamespaces); + } catch (e) { + error = e; } + } + if (error) { return { - tag: 'Right', - value: { - method, - object, - ...(requiresNamespacesCheck && { esRequestIndex: bulkGetRequestIndexCounter++ }), - }, + tag: 'Left', + value: { id, type, error: errorContent(error) }, }; } - ); - const bulkGetDocs = expectedResults + const method = id && overwrite ? 'index' : 'create'; + const requiresNamespacesCheck = id && this._registry.isMultiNamespace(type); + + return { + tag: 'Right', + value: { + method, + object: { ...object, id: object.id || SavedObjectsUtils.generateId() }, + ...(requiresNamespacesCheck && { preflightCheckIndex: preflightCheckIndexCounter++ }), + }, + }; + }); + + const namespaceString = SavedObjectsUtils.namespaceIdToString(namespace); + const preflightCheckObjects = expectedResults .filter(isRight) - .filter(({ value }) => value.esRequestIndex !== undefined) - .map( - ({ - value: { - object: { type, id }, - }, - }) => ({ - _id: this._serializer.generateRawId(namespace, type, id), - _index: this.getIndexForType(type), - _source: ['type', 'namespaces'], - }) - ); - const bulkGetResponse = bulkGetDocs.length - ? await this.client.mget( - { - body: { - docs: bulkGetDocs, - }, - }, - { ignore: [404] } - ) - : undefined; - // throw if we can't verify a 404 response is from Elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } + .filter(({ value }) => value.preflightCheckIndex !== undefined) + .map(({ value }) => { + const { type, id, initialNamespaces } = value.object; + const namespaces = initialNamespaces ?? [namespaceString]; + return { type, id, overwrite, namespaces }; + }); + const preflightCheckResponse = await preflightCheckForCreate({ + registry: this._registry, + client: this.client, + serializer: this._serializer, + getIndexForType: this.getIndexForType.bind(this), + createPointInTimeFinder: this.createPointInTimeFinder.bind(this), + objects: preflightCheckObjects, + }); + let bulkRequestIndexCounter = 0; const bulkCreateParams: object[] = []; - const expectedBulkResults: Array, Record>> = - expectedResults.map((expectedBulkGetResult) => { - if (isLeft(expectedBulkGetResult)) { - return expectedBulkGetResult; - } + const expectedBulkResults = expectedResults.map< + Either< + { type: string; id?: string; error: Payload }, + { esRequestIndex: number; requestedId: string; rawMigratedDoc: SavedObjectsRawDoc } + > + >((expectedBulkGetResult) => { + if (isLeft(expectedBulkGetResult)) { + return expectedBulkGetResult; + } - let savedObjectNamespace: string | undefined; - let savedObjectNamespaces: string[] | undefined; - let versionProperties; - const { - esRequestIndex, - object: { initialNamespaces, version, ...object }, - method, - } = expectedBulkGetResult.value; - if (esRequestIndex !== undefined) { - const indexFound = bulkGetResponse?.statusCode !== 404; - const actualResult = indexFound ? bulkGetResponse?.body.docs[esRequestIndex] : undefined; - const docFound = indexFound && actualResult?.found === true; - if ( - docFound && - !this.rawDocExistsInNamespaces( - // @ts-expect-error MultiGetHit._source is optional - actualResult!, - initialNamespaces ?? [SavedObjectsUtils.namespaceIdToString(namespace)] - ) - ) { - const { id, type } = object; - return { - tag: 'Left', - value: { - id, - type, - error: { - ...errorContent(SavedObjectsErrorHelpers.createConflictError(type, id)), - metadata: { isNotOverwritable: true }, - }, + let savedObjectNamespace: string | undefined; + let savedObjectNamespaces: string[] | undefined; + let versionProperties; + const { + preflightCheckIndex, + object: { initialNamespaces, version, ...object }, + method, + } = expectedBulkGetResult.value; + if (preflightCheckIndex !== undefined) { + const preflightResult = preflightCheckResponse[preflightCheckIndex]; + const { type, id, existingDocument, error } = preflightResult; + if (error) { + const { metadata } = error; + return { + tag: 'Left', + value: { + id, + type, + error: { + ...errorContent(SavedObjectsErrorHelpers.createConflictError(type, id)), + ...(metadata && { metadata }), }, - }; - } - savedObjectNamespaces = - initialNamespaces || - // @ts-expect-error MultiGetHit._source is optional - getSavedObjectNamespaces(namespace, docFound ? actualResult : undefined); - // @ts-expect-error MultiGetHit._source is optional - versionProperties = getExpectedVersionProperties(version, actualResult); - } else { - if (this._registry.isSingleNamespace(object.type)) { - savedObjectNamespace = initialNamespaces - ? normalizeNamespace(initialNamespaces[0]) - : namespace; - } else if (this._registry.isMultiNamespace(object.type)) { - savedObjectNamespaces = initialNamespaces || getSavedObjectNamespaces(namespace); - } - versionProperties = getExpectedVersionProperties(version); + }, + }; } + savedObjectNamespaces = + initialNamespaces || getSavedObjectNamespaces(namespace, existingDocument); + versionProperties = getExpectedVersionProperties(version, existingDocument); + } else { + if (this._registry.isSingleNamespace(object.type)) { + savedObjectNamespace = initialNamespaces + ? normalizeNamespace(initialNamespaces[0]) + : namespace; + } else if (this._registry.isMultiNamespace(object.type)) { + savedObjectNamespaces = initialNamespaces || getSavedObjectNamespaces(namespace); + } + versionProperties = getExpectedVersionProperties(version); + } - const expectedResult = { - esRequestIndex: bulkRequestIndexCounter++, - requestedId: object.id, - rawMigratedDoc: this._serializer.savedObjectToRaw( - this._migrator.migrateDocument({ - id: object.id, - type: object.type, - attributes: object.attributes, - migrationVersion: object.migrationVersion, - ...(savedObjectNamespace && { namespace: savedObjectNamespace }), - ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }), - updated_at: time, - references: object.references || [], - originId: object.originId, - }) as SavedObjectSanitizedDoc - ), - }; + const expectedResult = { + esRequestIndex: bulkRequestIndexCounter++, + requestedId: object.id, + rawMigratedDoc: this._serializer.savedObjectToRaw( + this._migrator.migrateDocument({ + id: object.id, + type: object.type, + attributes: object.attributes, + migrationVersion: object.migrationVersion, + ...(savedObjectNamespace && { namespace: savedObjectNamespace }), + ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }), + updated_at: time, + references: object.references || [], + originId: object.originId, + }) as SavedObjectSanitizedDoc + ), + }; - bulkCreateParams.push( - { - [method]: { - _id: expectedResult.rawMigratedDoc._id, - _index: this.getIndexForType(object.type), - ...(overwrite && versionProperties), - }, + bulkCreateParams.push( + { + [method]: { + _id: expectedResult.rawMigratedDoc._id, + _index: this.getIndexForType(object.type), + ...(overwrite && versionProperties), }, - expectedResult.rawMigratedDoc._source - ); + }, + expectedResult.rawMigratedDoc._source + ); - return { tag: 'Right', value: expectedResult }; - }); + return { tag: 'Right', value: expectedResult }; + }); const bulkResponse = bulkCreateParams.length ? await this.client.bulk({ @@ -650,16 +633,7 @@ export class SavedObjectsRepository { { ignore: [404] } ) : undefined; - // throw if we can't verify a 404 response is from Elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } + const errors: SavedObjectsCheckConflictsResponse['errors'] = []; expectedBulkGetResults.forEach((expectedResult) => { if (isLeft(expectedResult)) { @@ -731,7 +705,7 @@ export class SavedObjectsRepository { } } - const { body, statusCode, headers } = await this.client.delete( + const { body, statusCode } = await this.client.delete( { id: rawId, index: this.getIndexForType(type), @@ -741,10 +715,6 @@ export class SavedObjectsRepository { { ignore: [404] } ); - if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id); - } - const deleted = body.result === 'deleted'; if (deleted) { return {}; @@ -793,7 +763,7 @@ export class SavedObjectsRepository { const match2 = buildNode('not', buildNode('is', 'type', LEGACY_URL_ALIAS_TYPE)); const kueryNode = buildNode('or', [match1, match2]); - const { body, statusCode, headers } = await this.client.updateByQuery( + const { body } = await this.client.updateByQuery( { index: this.getIndicesForTypes(typesToUpdate), refresh: options.refresh, @@ -822,10 +792,6 @@ export class SavedObjectsRepository { }, { ignore: [404] } ); - // throw if we can't verify a 404 response is from Elasticsearch - if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } return body; } @@ -970,16 +936,10 @@ export class SavedObjectsRepository { }, }; - const { body, statusCode, headers } = await this.client.search( - esOptions, - { - ignore: [404], - } - ); + const { body, statusCode } = await this.client.search(esOptions, { + ignore: [404], + }); if (statusCode === 404) { - if (!isSupportedEsServer(headers)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } // 404 is only possible here if the index is missing, which // we don't want to leak, see "404s from missing index" above return { @@ -1086,16 +1046,7 @@ export class SavedObjectsRepository { { ignore: [404] } ) : undefined; - // fail fast if we can't verify a 404 is from Elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } + return { saved_objects: expectedBulkGetResults.map((expectedResult) => { if (isLeft(expectedResult)) { @@ -1186,7 +1137,7 @@ export class SavedObjectsRepository { throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); } const namespace = normalizeNamespace(options.namespace); - const { body, statusCode, headers } = await this.client.get( + const { body, statusCode } = await this.client.get( { id: this._serializer.generateRawId(namespace, type, id), index: this.getIndexForType(type), @@ -1194,10 +1145,7 @@ export class SavedObjectsRepository { { ignore: [404] } ); const indexNotFound = statusCode === 404; - // check if we have the elasticsearch header when index is not found and if we do, ensure it is Elasticsearch - if (indexNotFound && !isSupportedEsServer(headers)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id); - } + if ( !isFoundGetResponse(body) || indexNotFound || @@ -1277,6 +1225,12 @@ export class SavedObjectsRepository { ) { throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); } + if (upsert && preflightResult.checkResult === 'not_found') { + // If an upsert would result in the creation of a new object, we need to check for alias conflicts too. + // This takes an extra round trip to Elasticsearch, but this won't happen often. + // TODO: improve performance by combining these into a single preflight check + await this.preflightCheckForUpsertAliasConflict(type, id, namespace); + } } const time = getCurrentTime(); @@ -1326,9 +1280,6 @@ export class SavedObjectsRepository { require_alias: true, }) .catch((err) => { - if (SavedObjectsErrorHelpers.isEsUnavailableError(err)) { - throw err; - } if (SavedObjectsErrorHelpers.isNotFoundError(err)) { // see "404s from missing index" above throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); @@ -1501,16 +1452,7 @@ export class SavedObjectsRepository { } ) : undefined; - // fail fast if we can't verify a 404 response is from Elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } + let bulkUpdateRequestIndexCounter = 0; const bulkUpdateParams: object[] = []; const expectedBulkUpdateResults: Array, Record>> = @@ -1644,7 +1586,7 @@ export class SavedObjectsRepository { // we need to target all SO indices as all types of objects may have references to the given SO. const targetIndices = this.getIndicesForTypes(allTypes); - const { body, statusCode, headers } = await this.client.updateByQuery( + const { body } = await this.client.updateByQuery( { index: targetIndices, refresh, @@ -1677,10 +1619,7 @@ export class SavedObjectsRepository { }, { ignore: [404] } ); - // fail fast if we can't verify a 404 is from Elasticsearch - if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id); - } + if (body.failures?.length) { throw SavedObjectsErrorHelpers.createConflictError( type, @@ -1828,6 +1767,14 @@ export class SavedObjectsRepository { if (preflightResult.checkResult === 'found_outside_namespace') { throw SavedObjectsErrorHelpers.createConflictError(type, id); } + + if (preflightResult.checkResult === 'not_found') { + // If an upsert would result in the creation of a new object, we need to check for alias conflicts too. + // This takes an extra round trip to Elasticsearch, but this won't happen often. + // TODO: improve performance by combining these into a single preflight check + await this.preflightCheckForUpsertAliasConflict(type, id, namespace); + } + savedObjectNamespaces = preflightResult.savedObjectNamespaces; } @@ -1954,15 +1901,12 @@ export class SavedObjectsRepository { ...(preference ? { preference } : {}), }; - const { body, statusCode, headers } = await this.client.openPointInTime(esOptions, { + const { body, statusCode } = await this.client.openPointInTime(esOptions, { ignore: [404], }); + if (statusCode === 404) { - if (!isSupportedEsServer(headers)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } else { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(); - } + throw SavedObjectsErrorHelpers.createGenericNotFoundError(); } return { @@ -2133,7 +2077,7 @@ export class SavedObjectsRepository { throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`); } - const { body, statusCode, headers } = await this.client.get( + const { body, statusCode } = await this.client.get( { id: this._serializer.generateRawId(undefined, type, id), index: this.getIndexForType(type), @@ -2155,9 +2099,6 @@ export class SavedObjectsRepository { savedObjectNamespaces: initialNamespaces ?? getSavedObjectNamespaces(namespace, body), rawDocSource: body, }; - } else if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { - // checking if the 404 is from Elasticsearch - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id); } return { checkResult: 'not_found', @@ -2165,6 +2106,29 @@ export class SavedObjectsRepository { }; } + /** + * Pre-flight check to ensure that an upsert which would create a new object does not result in an alias conflict. + */ + private async preflightCheckForUpsertAliasConflict( + type: string, + id: string, + namespace: string | undefined + ) { + const namespaceString = SavedObjectsUtils.namespaceIdToString(namespace); + const [{ error }] = await preflightCheckForCreate({ + registry: this._registry, + client: this.client, + serializer: this._serializer, + getIndexForType: this.getIndexForType.bind(this), + createPointInTimeFinder: this.createPointInTimeFinder.bind(this), + objects: [{ type, id, namespaces: [namespaceString] }], + }); + if (error?.type === 'aliasConflict') { + throw SavedObjectsErrorHelpers.createConflictError(type, id); + } + // any other error from this check does not matter + } + /** The `initialNamespaces` field (create, bulkCreate) is used to create an object in an initial set of spaces. */ private validateInitialNamespaces(type: string, initialNamespaces: string[] | undefined) { if (!initialNamespaces) { diff --git a/src/core/server/saved_objects/service/lib/repository_es_client.ts b/src/core/server/saved_objects/service/lib/repository_es_client.ts index 4e8592fa94cca..4c1ae294cc7db 100644 --- a/src/core/server/saved_objects/service/lib/repository_es_client.ts +++ b/src/core/server/saved_objects/service/lib/repository_es_client.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; +import type { TransportRequestOptions } from '@elastic/elasticsearch'; import { ElasticsearchClient } from '../../../elasticsearch/'; import { retryCallCluster } from '../../../elasticsearch/client/retry_call_cluster'; diff --git a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts index 3196a59ca39ee..f2cf0013dfe08 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts @@ -8,7 +8,7 @@ import Boom from '@hapi/boom'; -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IndexMapping } from '../../../mappings'; import { SavedObjectsPitParams } from '../../../types'; import { getQueryParams, HasReferenceQueryParams, SearchOperator } from './query_params'; diff --git a/src/core/server/saved_objects/service/lib/search_dsl/sorting_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/sorting_params.ts index 592110a5413ec..2a3dca2629098 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/sorting_params.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/sorting_params.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import Boom from '@hapi/boom'; import { getProperty, IndexMapping } from '../../../mappings'; diff --git a/src/core/server/saved_objects/service/lib/update_objects_spaces.test.ts b/src/core/server/saved_objects/service/lib/update_objects_spaces.test.ts index ba15fbabfba6b..11dbe6149878c 100644 --- a/src/core/server/saved_objects/service/lib/update_objects_spaces.test.ts +++ b/src/core/server/saved_objects/service/lib/update_objects_spaces.test.ts @@ -23,7 +23,6 @@ import type { UpdateObjectsSpacesParams, } from './update_objects_spaces'; import { updateObjectsSpaces } from './update_objects_spaces'; -import { SavedObjectsErrorHelpers } from './errors'; type SetupParams = Partial< Pick @@ -106,32 +105,6 @@ describe('#updateObjectsSpaces', () => { }) ); } - /** Mocks the saved objects client so as to test unsupported server responding with 404 */ - function mockMgetResultsNotFound(...results: Array<{ found: boolean }>) { - client.mget.mockReturnValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { - docs: results.map((x) => - x.found - ? { - _id: 'doesnt-matter', - _index: 'doesnt-matter', - _source: { namespaces: [EXISTING_SPACE] }, - ...VERSION_PROPS, - found: true, - } - : { - _id: 'doesnt-matter', - _index: 'doesnt-matter', - found: false, - } - ), - }, - { statusCode: 404 }, - {} - ) - ); - } /** Asserts that mget is called for the given objects */ function expectMgetArgs(...objects: SavedObjectsUpdateObjectsSpacesObject[]) { @@ -267,17 +240,6 @@ describe('#updateObjectsSpaces', () => { { ...obj7, spaces: [EXISTING_SPACE, 'foo-space'] }, ]); }); - - it('throws when mget not found response is missing the Elasticsearch header', async () => { - const objects = [{ type: SHAREABLE_OBJ_TYPE, id: 'id-1' }]; - const spacesToAdd = ['foo-space']; - const params = setup({ objects, spacesToAdd }); - mockMgetResultsNotFound({ found: true }); - - await expect(() => updateObjectsSpaces(params)).rejects.toThrowError( - SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError() - ); - }); }); // Note: these test cases do not include requested objects that will result in errors (those are covered above) diff --git a/src/core/server/saved_objects/service/lib/update_objects_spaces.ts b/src/core/server/saved_objects/service/lib/update_objects_spaces.ts index 6d7c272c26eec..d88bf700a900e 100644 --- a/src/core/server/saved_objects/service/lib/update_objects_spaces.ts +++ b/src/core/server/saved_objects/service/lib/update_objects_spaces.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import intersection from 'lodash/intersection'; import type { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; @@ -28,7 +28,6 @@ import { } from './internal_utils'; import { DEFAULT_REFRESH_SETTING } from './repository'; import type { RepositoryEsClient } from './repository_es_client'; -import { isNotFoundFromUnsupportedServer } from '../../../elasticsearch'; /** * An object that should have its spaces updated. @@ -188,16 +187,6 @@ export async function updateObjectsSpaces({ ) : undefined; - // fail fast if we can't verify a 404 response is from Elasticsearch - if ( - bulkGetResponse && - isNotFoundFromUnsupportedServer({ - statusCode: bulkGetResponse.statusCode, - headers: bulkGetResponse.headers, - }) - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(); - } const time = new Date().toISOString(); let bulkOperationRequestIndexCounter = 0; const bulkOperationParams: estypes.BulkOperationContainer[] = []; @@ -259,7 +248,6 @@ export async function updateObjectsSpaces({ // @ts-expect-error BulkOperation.retry_on_conflict, BulkOperation.routing. BulkOperation.version, and BulkOperation.version_type are optional bulkOperationParams.push({ update: documentMetadata }, { doc: documentToSave }); } else { - // @ts-expect-error BulkOperation.retry_on_conflict, BulkOperation.routing. BulkOperation.version, and BulkOperation.version_type are optional bulkOperationParams.push({ delete: documentMetadata }); } } diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index dca8814b2914a..68040d9c6e003 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SavedObjectsClient } from './service/saved_objects_client'; import { SavedObjectsTypeMappingDefinition } from './mappings'; import { SavedObjectMigrationMap } from './migrations'; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 9e50a3008293b..f135d8caaf54e 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -5,11 +5,10 @@ ```ts import { AddConfigDeprecation } from '@kbn/config'; -import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; import Boom from '@hapi/boom'; import { ByteSizeValue } from '@kbn/config-schema'; import { CliArgs } from '@kbn/config'; -import { ClientOptions } from '@elastic/elasticsearch'; +import { ClientOptions } from '@elastic/elasticsearch/lib/client'; import { ConfigDeprecation } from '@kbn/config'; import { ConfigDeprecationContext } from '@kbn/config'; import { ConfigDeprecationFactory } from '@kbn/config'; @@ -25,9 +24,9 @@ import { EcsEventKind } from '@kbn/logging'; import { EcsEventOutcome } from '@kbn/logging'; import { EcsEventType } from '@kbn/logging'; import { EnvironmentMode } from '@kbn/config'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IncomingHttpHeaders } from 'http'; -import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import { Logger } from '@kbn/logging'; import { LoggerFactory } from '@kbn/logging'; import { LogLevel } from '@kbn/logging'; @@ -49,9 +48,9 @@ import { ResponseToolkit } from '@hapi/hapi'; import { SchemaTypeError } from '@kbn/config-schema'; import { ShallowPromise } from '@kbn/utility-types'; import { Stream } from 'stream'; -import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; +import { TransportRequestOptions } from '@elastic/elasticsearch'; +import { TransportRequestParams } from '@elastic/elasticsearch'; +import { TransportResult } from '@elastic/elasticsearch'; import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; import { UiCounterMetricType } from '@kbn/analytics'; @@ -870,9 +869,9 @@ export { EcsEventOutcome } export { EcsEventType } // @public -export type ElasticsearchClient = Omit & { +export type ElasticsearchClient = Omit & { transport: { - request(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise; + request(params: TransportRequestParams, options?: TransportRequestOptions): Promise>; }; }; @@ -918,6 +917,15 @@ export interface ElasticsearchConfigPreboot { readonly hosts: string[]; } +// @public (undocumented) +export interface ElasticsearchErrorDetails { + // (undocumented) + error?: { + type: string; + reason?: string; + }; +} + // @public (undocumented) export interface ElasticsearchServicePreboot { readonly config: Readonly; @@ -2171,8 +2179,6 @@ export class SavedObjectsErrorHelpers { // (undocumented) static createGenericNotFoundError(type?: string | null, id?: string | null): DecoratedError; // (undocumented) - static createGenericNotFoundEsUnavailableError(type?: string | null, id?: string | null): DecoratedError; - // (undocumented) static createIndexAliasNotFoundError(alias: string): DecoratedError; // (undocumented) static createInvalidVersionError(versionInput?: string): DecoratedError; @@ -2704,6 +2710,7 @@ export class SavedObjectsSerializer { // @public export interface SavedObjectsServiceSetup { addClientWrapper: (priority: number, id: string, factory: SavedObjectsClientWrapperFactory) => void; + getKibanaIndex: () => string; registerType: (type: SavedObjectsType) => void; setClientFactoryProvider: (clientFactoryProvider: SavedObjectsClientFactoryProvider) => void; } @@ -2977,7 +2984,6 @@ export interface ShardsResponse { // @public (undocumented) export type SharedGlobalConfig = RecursiveReadonly<{ - kibana: Pick; elasticsearch: Pick; path: Pick; savedObjects: Pick; @@ -3050,11 +3056,10 @@ export const validBodyOutput: readonly ["data", "stream"]; // Warnings were encountered during analysis: // -// src/core/server/elasticsearch/client/types.ts:94:7 - (ae-forgotten-export) The symbol "Explanation" needs to be exported by the entry point index.d.ts +// src/core/server/elasticsearch/client/types.ts:93:7 - (ae-forgotten-export) The symbol "Explanation" needs to be exported by the entry point index.d.ts // src/core/server/http/router/response.ts:302:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:380:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:486:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" +// src/core/server/plugins/types.ts:375:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:483:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" ``` diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 2d3b87207fcbe..e8c7ce6abb029 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -36,7 +36,6 @@ import { config as cspConfig } from './csp'; import { config as elasticsearchConfig } from './elasticsearch'; import { config as httpConfig } from './http'; import { config as loggingConfig } from './logging'; -import { config as kibanaConfig } from './kibana_config'; import { savedObjectsConfig, savedObjectsMigrationConfig } from './saved_objects'; import { config as uiSettingsConfig } from './ui_settings'; import { config as statusConfig } from './status'; @@ -373,7 +372,6 @@ export class Server { loggingConfig, httpConfig, pluginsConfig, - kibanaConfig, savedObjectsConfig, savedObjectsMigrationConfig, uiSettingsConfig, diff --git a/src/core/server/ui_settings/integration_tests/lib/servers.ts b/src/core/server/ui_settings/integration_tests/lib/servers.ts index 96ba08a0728ab..d94ab98060a27 100644 --- a/src/core/server/ui_settings/integration_tests/lib/servers.ts +++ b/src/core/server/ui_settings/integration_tests/lib/servers.ts @@ -8,7 +8,7 @@ import type supertest from 'supertest'; import type { SavedObjectsClientContract, IUiSettingsClient } from 'src/core/server'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana'; import { createTestServers, @@ -55,7 +55,7 @@ export function getServices() { return services; } - const esClient = esServer.es.getClient(); + const esClient = esServer.es.getKibanaEsClient(); const savedObjectsClient = kbn.coreStart.savedObjects.getScopedClient( httpServerMock.createKibanaRequest() diff --git a/src/core/types/elasticsearch/index.ts b/src/core/types/elasticsearch/index.ts index bec611778e6f5..09eff555fc857 100644 --- a/src/core/types/elasticsearch/index.ts +++ b/src/core/types/elasticsearch/index.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { InferSearchResponseOf, AggregateOf as AggregationResultOf, SearchHit } from './search'; export type ESFilter = estypes.QueryDslQueryContainer; diff --git a/src/core/types/elasticsearch/search.ts b/src/core/types/elasticsearch/search.ts index a54f5f3758ce3..2e79bf6fea57c 100644 --- a/src/core/types/elasticsearch/search.ts +++ b/src/core/types/elasticsearch/search.ts @@ -7,7 +7,7 @@ */ import { ValuesType } from 'utility-types'; -import { estypes } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; type InvalidAggregationRequest = unknown; diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 235a5fbe1a1a3..a9a54bf6794b2 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -85,8 +85,6 @@ kibana_vars=( logging.root.appenders logging.root.level map.includeElasticMapsService - map.proxyElasticMapsServiceInMaps - map.regionmap map.tilemap.options.attribution map.tilemap.options.maxZoom map.tilemap.options.minZoom @@ -343,7 +341,6 @@ kibana_vars=( xpack.security.authc.saml.realm xpack.security.authc.selector.enabled xpack.security.cookieName - xpack.security.enabled xpack.security.encryptionKey xpack.security.loginAssistanceMessage xpack.security.loginHelp @@ -366,7 +363,6 @@ kibana_vars=( xpack.securitySolution.prebuiltRulesFromFileSystem xpack.securitySolution.prebuiltRulesFromSavedObjects xpack.spaces.maxSpaces - xpack.task_manager.index xpack.task_manager.max_attempts xpack.task_manager.max_poll_inactivity_cycles xpack.task_manager.max_workers @@ -379,6 +375,7 @@ kibana_vars=( xpack.task_manager.poll_interval xpack.task_manager.request_capacity xpack.task_manager.version_conflict_threshold + xpack.uptime.index ) longopts='' diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index efa54e74fdf2f..4c630ae1c10e1 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -74,7 +74,7 @@ export const DEV_ONLY_LICENSE_ALLOWED = ['MPL-2.0']; export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint - '@elastic/ems-client@7.16.0': ['Elastic License 2.0'], - '@elastic/eui@39.1.1': ['SSPL-1.0 OR Elastic License 2.0'], + '@elastic/ems-client@8.0.0': ['Elastic License 2.0'], + '@elastic/eui@40.0.0': ['SSPL-1.0 OR Elastic License 2.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry }; diff --git a/src/plugins/console/server/lib/spec_definitions/json/overrides/ilm.put_lifecycle.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/ilm.put_lifecycle.json index 64014adc86e19..7648ab48621d5 100644 --- a/src/plugins/console/server/lib/spec_definitions/json/overrides/ilm.put_lifecycle.json +++ b/src/plugins/console/server/lib/spec_definitions/json/overrides/ilm.put_lifecycle.json @@ -31,7 +31,7 @@ "forcemerge": { "max_num_segments": 1 } - } + } }, "min_age": "1d", "actions": { @@ -69,7 +69,6 @@ "set_priority": { "priority": 0 }, - "freeze": {}, "allocate": { "number_of_replicas": 1, "include": { @@ -85,14 +84,13 @@ "_ip": "" } } - } + } }, "min_age": "1d", "actions": { "set_priority": { "priority": 0 }, - "freeze": {}, "unfollow": {}, "allocate": { "number_of_replicas": 1, @@ -123,7 +121,7 @@ "max_docs": 1000, "max_size": "5gb" } - } + } }, "min_age": "1d", "actions": { @@ -154,4 +152,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/plugins/dashboard/common/embeddable/dashboard_container_persistable_state.ts b/src/plugins/dashboard/common/embeddable/dashboard_container_persistable_state.ts index 6104fcfdbe949..c04f2623d6d55 100644 --- a/src/plugins/dashboard/common/embeddable/dashboard_container_persistable_state.ts +++ b/src/plugins/dashboard/common/embeddable/dashboard_container_persistable_state.ts @@ -12,10 +12,17 @@ import { EmbeddableStateWithType, } from '../../../embeddable/common'; import { SavedObjectReference } from '../../../../core/types'; -import { DashboardContainerStateWithType, DashboardPanelState } from '../types'; +import { + DashboardContainerControlGroupInput, + DashboardContainerStateWithType, + DashboardPanelState, +} from '../types'; +import { CONTROL_GROUP_TYPE } from '../../../presentation_util/common/lib'; const getPanelStatePrefix = (state: DashboardPanelState) => `${state.explicitInput.id}:`; +const controlGroupReferencePrefix = 'controlGroup_'; + export const createInject = ( persistableStateService: EmbeddablePersistableStateService ): EmbeddablePersistableStateService['inject'] => { @@ -69,6 +76,26 @@ export const createInject = ( } } + // since the controlGroup is not part of the panels array, its references need to be injected separately + if ('controlGroupInput' in workingState && workingState.controlGroupInput) { + const controlGroupReferences = references + .filter((reference) => reference.name.indexOf(controlGroupReferencePrefix) === 0) + .map((reference) => ({ + ...reference, + name: reference.name.replace(controlGroupReferencePrefix, ''), + })); + + const { type, ...injectedControlGroupState } = persistableStateService.inject( + { + ...workingState.controlGroupInput, + type: CONTROL_GROUP_TYPE, + }, + controlGroupReferences + ); + workingState.controlGroupInput = + injectedControlGroupState as DashboardContainerControlGroupInput; + } + return workingState as EmbeddableStateWithType; }; }; @@ -120,6 +147,22 @@ export const createExtract = ( } } + // since the controlGroup is not part of the panels array, its references need to be extracted separately + if ('controlGroupInput' in workingState && workingState.controlGroupInput) { + const { state: extractedControlGroupState, references: controlGroupReferences } = + persistableStateService.extract({ + ...workingState.controlGroupInput, + type: CONTROL_GROUP_TYPE, + }); + workingState.controlGroupInput = + extractedControlGroupState as DashboardContainerControlGroupInput; + const prefixedControlGroupReferences = controlGroupReferences.map((reference) => ({ + ...reference, + name: `${controlGroupReferencePrefix}${reference.name}`, + })); + references.push(...prefixedControlGroupReferences); + } + return { state: workingState as EmbeddableStateWithType, references }; }; }; diff --git a/src/plugins/dashboard/common/saved_dashboard_references.ts b/src/plugins/dashboard/common/saved_dashboard_references.ts index 4b3a379068c48..bc7358b49ceb4 100644 --- a/src/plugins/dashboard/common/saved_dashboard_references.ts +++ b/src/plugins/dashboard/common/saved_dashboard_references.ts @@ -7,13 +7,20 @@ */ import semverGt from 'semver/functions/gt'; import { SavedObjectAttributes, SavedObjectReference } from '../../../core/types'; -import { DashboardContainerStateWithType, DashboardPanelState } from './types'; +import { + DashboardContainerControlGroupInput, + DashboardContainerStateWithType, + DashboardPanelState, + RawControlGroupAttributes, +} from './types'; import { EmbeddablePersistableStateService } from '../../embeddable/common/types'; import { convertPanelStateToSavedDashboardPanel, convertSavedDashboardPanelToPanelState, } from './embeddable/embeddable_saved_object_converters'; import { SavedDashboardPanel } from './types'; +import { CONTROL_GROUP_TYPE } from '../../presentation_util/common/lib'; + export interface ExtractDeps { embeddablePersistableStateService: EmbeddablePersistableStateService; } @@ -35,10 +42,27 @@ function dashboardAttributesToState(attributes: SavedObjectAttributes): { inputPanels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[]; } + let controlGroupInput: DashboardContainerControlGroupInput | undefined; + if (attributes.controlGroupInput) { + const rawControlGroupInput = + attributes.controlGroupInput as unknown as RawControlGroupAttributes; + if (rawControlGroupInput.panelsJSON && typeof rawControlGroupInput.panelsJSON === 'string') { + const controlGroupPanels = JSON.parse(rawControlGroupInput.panelsJSON); + if (controlGroupPanels && typeof controlGroupPanels === 'object') { + controlGroupInput = { + ...rawControlGroupInput, + type: CONTROL_GROUP_TYPE, + panels: controlGroupPanels, + }; + } + } + } + return { panels: inputPanels, state: { id: attributes.id as string, + controlGroupInput, type: 'dashboard', panels: inputPanels.reduce>((current, panel, index) => { const panelIndex = panel.panelIndex || `${index}`; @@ -92,20 +116,27 @@ export function extractReferences( throw new Error(`"type" attribute is missing from panel "${missingTypeIndex}"`); } - const { state: extractedState, references: extractedReferences } = + const { references: extractedReferences, state: rawExtractedState } = deps.embeddablePersistableStateService.extract(state); + const extractedState = rawExtractedState as DashboardContainerStateWithType; + + const extractedPanels = panelStatesToPanels(extractedState.panels, panels); - const extractedPanels = panelStatesToPanels( - (extractedState as DashboardContainerStateWithType).panels, - panels - ); + const newAttributes = { + ...attributes, + panelsJSON: JSON.stringify(extractedPanels), + } as SavedObjectAttributes; + + if (extractedState.controlGroupInput) { + newAttributes.controlGroupInput = { + ...(attributes.controlGroupInput as SavedObjectAttributes), + panelsJSON: JSON.stringify(extractedState.controlGroupInput.panels), + }; + } return { references: [...references, ...extractedReferences], - attributes: { - ...attributes, - panelsJSON: JSON.stringify(extractedPanels), - }, + attributes: newAttributes, }; } @@ -131,16 +162,25 @@ export function injectReferences( const { panels, state } = dashboardAttributesToState(attributes); - const injectedState = deps.embeddablePersistableStateService.inject(state, references); - const injectedPanels = panelStatesToPanels( - (injectedState as DashboardContainerStateWithType).panels, - panels - ); + const injectedState = deps.embeddablePersistableStateService.inject( + state, + references + ) as DashboardContainerStateWithType; + const injectedPanels = panelStatesToPanels(injectedState.panels, panels); - return { + const newAttributes = { ...attributes, panelsJSON: JSON.stringify(injectedPanels), - }; + } as SavedObjectAttributes; + + if (injectedState.controlGroupInput) { + newAttributes.controlGroupInput = { + ...(attributes.controlGroupInput as SavedObjectAttributes), + panelsJSON: JSON.stringify(injectedState.controlGroupInput.panels), + }; + } + + return newAttributes; } function pre730ExtractReferences( diff --git a/src/plugins/dashboard/common/types.ts b/src/plugins/dashboard/common/types.ts index 5851ffa045bc7..bfe53514969d7 100644 --- a/src/plugins/dashboard/common/types.ts +++ b/src/plugins/dashboard/common/types.ts @@ -22,6 +22,7 @@ import { } from './bwc/types'; import { GridData } from './embeddable/types'; +import { ControlGroupInput } from '../../presentation_util/common/controls/control_group/types'; export type PanelId = string; export type SavedObjectId = string; @@ -96,8 +97,22 @@ export type SavedDashboardPanel730ToLatest = Pick< // Making this interface because so much of the Container type from embeddable is tied up in public // Once that is all available from common, we should be able to move the dashboard_container type to our common as well + +export interface DashboardContainerControlGroupInput extends EmbeddableStateWithType { + panels: ControlGroupInput['panels']; + controlStyle: ControlGroupInput['controlStyle']; + id: string; +} + +export interface RawControlGroupAttributes { + controlStyle: ControlGroupInput['controlStyle']; + panelsJSON: string; + id: string; +} + export interface DashboardContainerStateWithType extends EmbeddableStateWithType { panels: { [panelId: string]: DashboardPanelState; }; + controlGroupInput?: DashboardContainerControlGroupInput; } diff --git a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx index 0f7acfbb3f5f6..fa484de2180b4 100644 --- a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx @@ -7,7 +7,7 @@ */ import { AddToLibraryAction } from '.'; -import { DashboardContainer } from '../embeddable'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { getSampleDashboardInput } from '../test_helpers'; import { CoreStart } from 'kibana/public'; diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx index 08e115ffca908..99665d312d32e 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { DashboardContainer, DashboardPanelState } from '../embeddable'; +import { DashboardPanelState } from '../embeddable'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { getSampleDashboardInput, getSampleDashboardPanel } from '../test_helpers'; import { coreMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; diff --git a/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx index 48bb787116862..0635152332993 100644 --- a/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx @@ -7,7 +7,7 @@ */ import { ExpandPanelAction } from './expand_panel_action'; -import { DashboardContainer } from '../embeddable'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { getSampleDashboardInput, getSampleDashboardPanel } from '../test_helpers'; import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx index 3d68f720d1eb3..51c64f1875376 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx @@ -9,7 +9,7 @@ import { CoreStart } from 'kibana/public'; import { isErrorEmbeddable, IContainer, ErrorEmbeddable } from '../../services/embeddable'; -import { DashboardContainer } from '../../application/embeddable'; +import { DashboardContainer } from '../../application/embeddable/dashboard_container'; import { getSampleDashboardInput, getSampleDashboardPanel } from '../../application/test_helpers'; import { ContactCardEmbeddable, diff --git a/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx b/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx index 95e12918bb8e9..587f741461bb4 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { DashboardContainer } from '../embeddable'; import { getSampleDashboardInput } from '../test_helpers'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { coreMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { CoreStart } from 'kibana/public'; diff --git a/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx b/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx index fab640694cb64..b5efa0447e651 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx @@ -7,8 +7,9 @@ */ import React from 'react'; -import { DashboardContainer } from '..'; import { mountWithIntl } from '@kbn/test/jest'; + +import { DashboardContainer } from '../embeddable/dashboard_container'; import { embeddablePluginMock } from '../../../../embeddable/public/mocks'; import { getSampleDashboardInput } from '../test_helpers'; import { diff --git a/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx index c8fe39f63fa23..f8880ac5618fc 100644 --- a/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx @@ -7,7 +7,7 @@ */ import { ReplacePanelAction } from './replace_panel_action'; -import { DashboardContainer } from '../embeddable'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { getSampleDashboardInput, getSampleDashboardPanel } from '../test_helpers'; import { coreMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; diff --git a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx index daa21b034f7c2..7d87c49bda649 100644 --- a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx @@ -17,8 +17,8 @@ import { SavedObjectEmbeddableInput, } from '../../services/embeddable'; import { UnlinkFromLibraryAction } from '.'; -import { DashboardContainer } from '../embeddable'; import { getSampleDashboardInput } from '../test_helpers'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { coreMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx index 86f81aa1ee10d..f86307d71fb18 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx @@ -25,6 +25,8 @@ import { EmbeddableStart, EmbeddableOutput, EmbeddableFactory, + ErrorEmbeddable, + isErrorEmbeddable, } from '../../services/embeddable'; import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants'; import { createPanelState } from './panel'; @@ -39,6 +41,11 @@ import { PLACEHOLDER_EMBEDDABLE } from './placeholder'; import { DashboardAppCapabilities, DashboardContainerInput } from '../../types'; import { PresentationUtilPluginStart } from '../../services/presentation_util'; import { PanelPlacementMethod, IPanelPlacementArgs } from './panel/dashboard_panel_placement'; +import { + combineDashboardFiltersWithControlGroupFilters, + syncDashboardControlGroup, +} from '../lib/dashboard_control_group'; +import { ControlGroupContainer } from '../../../../presentation_util/public'; export interface DashboardContainerServices { ExitFullScreenButton: React.ComponentType; @@ -88,6 +95,9 @@ const defaultCapabilities: DashboardAppCapabilities = { export class DashboardContainer extends Container { public readonly type = DASHBOARD_CONTAINER_TYPE; + private onDestroyControlGroup?: () => void; + public controlGroup?: ControlGroupContainer; + public getPanelCount = () => { return Object.keys(this.getInput().panels).length; }; @@ -95,7 +105,8 @@ export class DashboardContainer extends Container { + if (!result) return; + const { onDestroyControlGroup } = result; + this.onDestroyControlGroup = onDestroyControlGroup; + } + ); + } } protected createNewPanelState< @@ -232,7 +258,7 @@ export class DashboardContainer extends Container - + , @@ -240,6 +266,11 @@ export class DashboardContainer extends Container => { const services = await this.getStartServices(); - return new DashboardContainer(initialInput, services, parent); + const controlsGroupFactory = services.embeddable.getEmbeddableFactory< + ControlGroupInput, + ControlGroupOutput, + ControlGroupContainer + >(CONTROL_GROUP_TYPE); + const controlGroup = await controlsGroupFactory?.create({ + ...getDefaultDashboardControlGroupInput(), + ...(initialInput.controlGroupInput ?? {}), + viewMode: initialInput.viewMode, + id: `control_group_${initialInput.id ?? 'new_dashboard'}`, + }); + const { DashboardContainer: DashboardContainerEmbeddable } = await import( + './dashboard_container' + ); + + return new DashboardContainerEmbeddable(initialInput, services, parent, controlGroup); }; public inject = createInject(this.persistableStateService); diff --git a/src/plugins/dashboard/public/application/embeddable/index.ts b/src/plugins/dashboard/public/application/embeddable/index.ts index a678dbea16a55..b3ee0f83ee852 100644 --- a/src/plugins/dashboard/public/application/embeddable/index.ts +++ b/src/plugins/dashboard/public/application/embeddable/index.ts @@ -10,7 +10,7 @@ export { DashboardContainerFactoryDefinition, DashboardContainerFactory, } from './dashboard_container_factory'; -export { DashboardContainer } from './dashboard_container'; +export type { DashboardContainer } from './dashboard_container'; export { createPanelState } from './panel'; export * from './types'; diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/_dashboard_viewport.scss b/src/plugins/dashboard/public/application/embeddable/viewport/_dashboard_viewport.scss index bb95840676969..f71868b059159 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/_dashboard_viewport.scss +++ b/src/plugins/dashboard/public/application/embeddable/viewport/_dashboard_viewport.scss @@ -5,3 +5,11 @@ .dshDashboardViewport-withMargins { width: 100%; } + +.dshDashboardViewport-controlGroup { + margin: 0 $euiSizeS 0 $euiSizeS; +} + +.dshDashboardEmptyScreen { + margin-top: $euiSizeS; +} diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.tsx b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.tsx index e401721d48442..1f4cd3952e7a5 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.tsx +++ b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.tsx @@ -13,13 +13,16 @@ import { DashboardContainer, DashboardReactContextValue } from '../dashboard_con import { DashboardGrid } from '../grid'; import { context } from '../../../services/kibana_react'; import { DashboardEmptyScreen } from '../empty_screen/dashboard_empty_screen'; +import { ControlGroupContainer } from '../../../../../presentation_util/public'; export interface DashboardViewportProps { container: DashboardContainer; + controlGroup?: ControlGroupContainer; } interface State { isFullScreenMode: boolean; + controlGroupReady: boolean; useMargins: boolean; title: string; description?: string; @@ -29,8 +32,10 @@ interface State { export class DashboardViewport extends React.Component { static contextType = context; - public readonly context!: DashboardReactContextValue; + + private controlsRoot: React.RefObject; + private subscription?: Subscription; private mounted: boolean = false; constructor(props: DashboardViewportProps) { @@ -38,7 +43,10 @@ export class DashboardViewport extends React.Component this.setState({ controlGroupReady: true })); + } } public componentWillUnmount() { @@ -83,7 +97,8 @@ export class DashboardViewport extends React.Component + <> +
)} - + {this.state.controlGroupReady && }
- + ); } } diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx index c3b4075690261..5561d1676e41c 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx @@ -12,13 +12,13 @@ import { Provider } from 'react-redux'; import { createBrowserHistory } from 'history'; import { renderHook, act, RenderHookResult } from '@testing-library/react-hooks'; -import { DashboardContainer } from '..'; import { DashboardSessionStorage } from '../lib'; import { coreMock } from '../../../../../core/public/mocks'; import { DashboardConstants } from '../../dashboard_constants'; import { dataPluginMock } from '../../../../data/public/mocks'; import { SavedObjectLoader } from '../../services/saved_objects'; import { DashboardAppServices, DashboardAppState } from '../../types'; +import { DashboardContainer } from '../embeddable/dashboard_container'; import { KibanaContextProvider } from '../../../../kibana_react/public'; import { EmbeddableFactory, ViewMode } from '../../services/embeddable'; import { dashboardStateStore, setDescription, setViewMode } from '../state'; @@ -206,7 +206,9 @@ describe('Dashboard container lifecycle', () => { }); }); -describe('Dashboard initial state', () => { +// FLAKY: https://github.com/elastic/kibana/issues/116050 +// FLAKY: https://github.com/elastic/kibana/issues/105018 +describe.skip('Dashboard initial state', () => { it('Extracts state from Dashboard Saved Object', async () => { const { renderHookResult, embeddableFactoryResult } = renderDashboardAppStateHook({}); const getResult = () => renderHookResult.result.current; @@ -276,7 +278,8 @@ describe('Dashboard initial state', () => { }); }); -describe('Dashboard state sync', () => { +// FLAKY: https://github.com/elastic/kibana/issues/116043 +describe.skip('Dashboard state sync', () => { let defaultDashboardAppStateHookResult: RenderDashboardStateHookReturn; const getResult = () => defaultDashboardAppStateHookResult.renderHookResult.result.current; diff --git a/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts index 0bd49cccbe5ef..8d55af5808da6 100644 --- a/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts @@ -20,6 +20,8 @@ import { DashboardBuildContext, } from '../../types'; import { convertSavedPanelsToPanelMap } from './convert_dashboard_panels'; +import { deserializeControlGroupFromDashboardSavedObject } from './dashboard_control_group'; +import { ControlGroupInput } from '../../../../presentation_util/public'; interface SavedObjectToDashboardStateProps { version: string; @@ -73,6 +75,9 @@ export const savedObjectToDashboardState = ({ usageCollection ); + rawState.controlGroupInput = deserializeControlGroupFromDashboardSavedObject( + savedDashboard + ) as ControlGroupInput; return { ...rawState, panels: convertSavedPanelsToPanelMap(rawState.panels) }; }; @@ -91,8 +96,17 @@ export const stateToDashboardContainerInput = ({ const { filterManager, timefilter: timefilterService } = queryService; const { timefilter } = timefilterService; - const { expandedPanelId, fullScreenMode, description, options, viewMode, panels, query, title } = - dashboardState; + const { + controlGroupInput, + expandedPanelId, + fullScreenMode, + description, + options, + viewMode, + panels, + query, + title, + } = dashboardState; return { refreshConfig: timefilter.getRefreshInterval(), @@ -102,6 +116,7 @@ export const stateToDashboardContainerInput = ({ dashboardCapabilities, isEmbeddedExternally, ...(options || {}), + controlGroupInput, searchSessionId, expandedPanelId, description, diff --git a/src/plugins/dashboard/public/application/lib/dashboard_control_group.ts b/src/plugins/dashboard/public/application/lib/dashboard_control_group.ts new file mode 100644 index 0000000000000..aaf6c5f0af4fc --- /dev/null +++ b/src/plugins/dashboard/public/application/lib/dashboard_control_group.ts @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Subscription } from 'rxjs'; +import deepEqual from 'fast-deep-equal'; +import { compareFilters, COMPARE_ALL_OPTIONS, Filter } from '@kbn/es-query'; +import { distinctUntilChanged, distinctUntilKeyChanged } from 'rxjs/operators'; + +import { DashboardContainer } from '..'; +import { DashboardState } from '../../types'; +import { getDefaultDashboardControlGroupInput } from '../../dashboard_constants'; +import { DashboardContainerInput, DashboardSavedObject } from '../..'; +import { ControlGroupContainer, ControlGroupInput } from '../../../../presentation_util/public'; + +// only part of the control group input should be stored in dashboard state. The rest is passed down from the dashboard. +export interface DashboardControlGroupInput { + panels: ControlGroupInput['panels']; + controlStyle: ControlGroupInput['controlStyle']; +} + +interface DiffChecks { + [key: string]: (a?: unknown, b?: unknown) => boolean; +} + +const distinctUntilDiffCheck = (a: T, b: T, diffChecks: DiffChecks) => + !(Object.keys(diffChecks) as Array) + .map((key) => deepEqual(a[key], b[key])) + .includes(false); + +type DashboardControlGroupCommonKeys = keyof Pick< + DashboardContainerInput | ControlGroupInput, + 'filters' | 'lastReloadRequestTime' | 'timeRange' | 'query' +>; + +export const syncDashboardControlGroup = async ({ + controlGroup, + dashboardContainer, +}: { + controlGroup: ControlGroupContainer; + dashboardContainer: DashboardContainer; +}) => { + const subscriptions = new Subscription(); + + const isControlGroupInputEqual = () => + controlGroupInputIsEqual( + controlGroup.getInput(), + dashboardContainer.getInput().controlGroupInput + ); + + // Because dashboard container stores control group state, certain control group changes need to be passed up dashboard container + const controlGroupDiff: DiffChecks = { + panels: deepEqual, + controlStyle: deepEqual, + }; + + subscriptions.add( + controlGroup + .getInput$() + .pipe( + distinctUntilChanged((a, b) => + distinctUntilDiffCheck(a, b, controlGroupDiff) + ) + ) + .subscribe(() => { + const { panels, controlStyle } = controlGroup.getInput(); + if (!isControlGroupInputEqual()) { + dashboardContainer.updateInput({ controlGroupInput: { panels, controlStyle } }); + } + }) + ); + + const dashboardRefetchDiff: DiffChecks = { + filters: (a, b) => + compareFilters((a as Filter[]) ?? [], (b as Filter[]) ?? [], COMPARE_ALL_OPTIONS), + lastReloadRequestTime: deepEqual, + timeRange: deepEqual, + query: deepEqual, + viewMode: deepEqual, + }; + + // pass down any pieces of input needed to refetch or force refetch data for the controls + subscriptions.add( + dashboardContainer + .getInput$() + .pipe( + distinctUntilChanged((a, b) => + distinctUntilDiffCheck(a, b, dashboardRefetchDiff) + ) + ) + .subscribe(() => { + const newInput: { [key: string]: unknown } = {}; + (Object.keys(dashboardRefetchDiff) as DashboardControlGroupCommonKeys[]).forEach((key) => { + if ( + !dashboardRefetchDiff[key]?.( + dashboardContainer.getInput()[key], + controlGroup.getInput()[key] + ) + ) { + newInput[key] = dashboardContainer.getInput()[key]; + } + }); + if (Object.keys(newInput).length > 0) { + controlGroup.updateInput(newInput); + } + }) + ); + + // dashboard may reset the control group input when discarding changes. Subscribe to these changes and update accordingly + subscriptions.add( + dashboardContainer + .getInput$() + .pipe(distinctUntilKeyChanged('controlGroupInput')) + .subscribe(() => { + if (!isControlGroupInputEqual()) { + if (!dashboardContainer.getInput().controlGroupInput) { + controlGroup.updateInput(getDefaultDashboardControlGroupInput()); + return; + } + controlGroup.updateInput({ ...dashboardContainer.getInput().controlGroupInput }); + } + }) + ); + + // when control group outputs filters, force a refresh! + subscriptions.add( + controlGroup + .getOutput$() + .subscribe(() => dashboardContainer.updateInput({ lastReloadRequestTime: Date.now() })) + ); + + return { + onDestroyControlGroup: () => { + subscriptions.unsubscribe(); + controlGroup.destroy(); + }, + }; +}; + +export const controlGroupInputIsEqual = ( + a: DashboardControlGroupInput | undefined, + b: DashboardControlGroupInput | undefined +) => { + const defaultInput = getDefaultDashboardControlGroupInput(); + const inputA = { + panels: a?.panels ?? defaultInput.panels, + controlStyle: a?.controlStyle ?? defaultInput.controlStyle, + }; + const inputB = { + panels: b?.panels ?? defaultInput.panels, + controlStyle: b?.controlStyle ?? defaultInput.controlStyle, + }; + if (deepEqual(inputA, inputB)) return true; + return false; +}; + +export const serializeControlGroupToDashboardSavedObject = ( + dashboardSavedObject: DashboardSavedObject, + dashboardState: DashboardState +) => { + // only save to saved object if control group is not default + if (controlGroupInputIsEqual(dashboardState.controlGroupInput, {} as ControlGroupInput)) { + dashboardSavedObject.controlGroupInput = undefined; + return; + } + if (dashboardState.controlGroupInput) { + dashboardSavedObject.controlGroupInput = { + controlStyle: dashboardState.controlGroupInput.controlStyle, + panelsJSON: JSON.stringify(dashboardState.controlGroupInput.panels), + }; + } +}; + +export const deserializeControlGroupFromDashboardSavedObject = ( + dashboardSavedObject: DashboardSavedObject +): Omit | undefined => { + if (!dashboardSavedObject.controlGroupInput) return; + + const defaultControlGroupInput = getDefaultDashboardControlGroupInput(); + return { + controlStyle: + dashboardSavedObject.controlGroupInput?.controlStyle ?? defaultControlGroupInput.controlStyle, + panels: dashboardSavedObject.controlGroupInput?.panelsJSON + ? JSON.parse(dashboardSavedObject.controlGroupInput?.panelsJSON) + : {}, + }; +}; + +export const combineDashboardFiltersWithControlGroupFilters = ( + dashboardFilters: Filter[], + controlGroup: ControlGroupContainer +) => { + const dashboardFiltersByKey = dashboardFilters.reduce( + (acc: { [key: string]: Filter }, current) => { + const key = current.meta.key; + if (key) acc[key] = current; + return acc; + }, + {} + ); + const controlGroupFiltersByKey = controlGroup + .getOutput() + .filters?.reduce((acc: { [key: string]: Filter }, current) => { + const key = current.meta.key; + if (key) acc[key] = current; + return acc; + }, {}); + const finalFilters = { ...dashboardFiltersByKey, ...(controlGroupFiltersByKey ?? {}) }; + return Object.values(finalFilters); +}; diff --git a/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts b/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts index 7dd2b53a58155..ca4fa85b4b55c 100644 --- a/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts +++ b/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts @@ -7,18 +7,19 @@ */ import { History } from 'history'; -import { DashboardConstants } from '../..'; +import { DashboardAppLocatorParams, DashboardConstants } from '../..'; import { DashboardState } from '../../types'; import { getDashboardTitle } from '../../dashboard_strings'; import { DashboardSavedObject } from '../../saved_dashboards'; import { getQueryParams } from '../../services/kibana_utils'; import { createQueryParamObservable } from '../../../../kibana_utils/public'; -import { DASHBOARD_APP_URL_GENERATOR, DashboardUrlGeneratorState } from '../../url_generator'; import { DataPublicPluginStart, noSearchSessionStorageCapabilityMessage, + SearchSessionInfoProvider, } from '../../services/data'; import { stateToRawDashboardState } from './convert_dashboard_state'; +import { DASHBOARD_APP_LOCATOR } from '../../locator'; export const getSearchSessionIdFromURL = (history: History): string | undefined => getQueryParams(history.location)[DashboardConstants.SEARCH_SESSION_ID] as string | undefined; @@ -32,16 +33,14 @@ export function createSessionRestorationDataProvider(deps: { getAppState: () => DashboardState; getDashboardTitle: () => string; getDashboardId: () => string; -}) { +}): SearchSessionInfoProvider { return { getName: async () => deps.getDashboardTitle(), - getUrlGeneratorData: async () => { - return { - urlGeneratorId: DASHBOARD_APP_URL_GENERATOR, - initialState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: false }), - restoreState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: true }), - }; - }, + getLocatorData: async () => ({ + id: DASHBOARD_APP_LOCATOR, + initialState: getLocatorParams({ ...deps, shouldRestoreSearchSession: false }), + restoreState: getLocatorParams({ ...deps, shouldRestoreSearchSession: true }), + }), }; } @@ -93,7 +92,7 @@ export function enableDashboardSearchSessions({ * Fetches the state to store when a session is saved so that this dashboard can be recreated exactly * as it was. */ -function getUrlGeneratorState({ +function getLocatorParams({ data, getAppState, kibanaVersion, @@ -105,7 +104,7 @@ function getUrlGeneratorState({ getAppState: () => DashboardState; getDashboardId: () => string; shouldRestoreSearchSession: boolean; -}): DashboardUrlGeneratorState { +}): DashboardAppLocatorParams { const appState = stateToRawDashboardState({ state: getAppState(), version: kibanaVersion }); const { filterManager, queryString } = data.query; const { timefilter } = data.query.timefilter; diff --git a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts index e718c98cb3626..2e89ee70d057d 100644 --- a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts @@ -15,6 +15,7 @@ import { DashboardPanelMap, DashboardState, } from '../../types'; +import { controlGroupInputIsEqual } from './dashboard_control_group'; interface DashboardDiffCommon { [key: string]: unknown; @@ -40,7 +41,7 @@ export const diffDashboardState = ( const common = commonDiffFilters( original as unknown as DashboardDiffCommonFilters, newState as unknown as DashboardDiffCommonFilters, - ['viewMode', 'panels', 'options', 'savedQuery', 'expandedPanelId'], + ['viewMode', 'panels', 'options', 'savedQuery', 'expandedPanelId', 'controlGroupInput'], true ); @@ -48,6 +49,9 @@ export const diffDashboardState = ( ...common, ...(panelsAreEqual(original.panels, newState.panels) ? {} : { panels: newState.panels }), ...(optionsAreEqual(original.options, newState.options) ? {} : { options: newState.options }), + ...(controlGroupInputIsEqual(original.controlGroupInput, newState.controlGroupInput) + ? {} + : { controlGroupInput: newState.controlGroupInput }), }; }; diff --git a/src/plugins/dashboard/public/application/lib/save_dashboard.ts b/src/plugins/dashboard/public/application/lib/save_dashboard.ts index 960d7d9cc8687..5a699eb116401 100644 --- a/src/plugins/dashboard/public/application/lib/save_dashboard.ts +++ b/src/plugins/dashboard/public/application/lib/save_dashboard.ts @@ -19,6 +19,7 @@ import { SavedObjectsTaggingApi } from '../../services/saved_objects_tagging_oss import { RefreshInterval, TimefilterContract, esFilters } from '../../services/data'; import { convertPanelStateToSavedDashboardPanel } from '../../../common/embeddable/embeddable_saved_object_converters'; import { DashboardSessionStorage } from './dashboard_session_storage'; +import { serializeControlGroupToDashboardSavedObject } from './dashboard_control_group'; export type SavedDashboardSaveOpts = SavedObjectSaveOpts & { stayInEditMode?: boolean }; @@ -60,6 +61,9 @@ export const saveDashboard = async ({ savedDashboard.optionsJSON = JSON.stringify(options); savedDashboard.panelsJSON = JSON.stringify(savedDashboardPanels); + // control group input + serializeControlGroupToDashboardSavedObject(savedDashboard, currentState); + if (hasTaggingCapabilities(savedDashboard)) { savedDashboard.setTags(tags); } diff --git a/src/plugins/dashboard/public/application/lib/session_restoration.test.ts b/src/plugins/dashboard/public/application/lib/session_restoration.test.ts index 571dfb0a8beeb..55366ac50fd2e 100644 --- a/src/plugins/dashboard/public/application/lib/session_restoration.test.ts +++ b/src/plugins/dashboard/public/application/lib/session_restoration.test.ts @@ -34,7 +34,7 @@ describe('createSessionRestorationDataProvider', () => { (mockDataPlugin.search.session.getSessionId as jest.Mock).mockImplementation( () => searchSessionId ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.searchSessionId).toBeUndefined(); expect(restoreState.searchSessionId).toBe(searchSessionId); }); @@ -48,13 +48,13 @@ describe('createSessionRestorationDataProvider', () => { (mockDataPlugin.query.timefilter.timefilter.getAbsoluteTime as jest.Mock).mockImplementation( () => absoluteTime ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.timeRange).toBe(relativeTime); expect(restoreState.timeRange).toBe(absoluteTime); }); test('restoreState has refreshInterval paused', async () => { - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.refreshInterval).toBeUndefined(); expect(restoreState.refreshInterval?.pause).toBe(true); }); diff --git a/src/plugins/dashboard/public/application/lib/sync_dashboard_container_input.ts b/src/plugins/dashboard/public/application/lib/sync_dashboard_container_input.ts index 6d06863d02179..0fa7487390cd8 100644 --- a/src/plugins/dashboard/public/application/lib/sync_dashboard_container_input.ts +++ b/src/plugins/dashboard/public/application/lib/sync_dashboard_container_input.ts @@ -13,7 +13,13 @@ import { debounceTime, tap } from 'rxjs/operators'; import { DashboardContainer } from '../embeddable'; import { esFilters, Filter, Query } from '../../services/data'; import { DashboardConstants, DashboardSavedObject } from '../..'; -import { setExpandedPanelId, setFullScreenMode, setPanels, setQuery } from '../state'; +import { + setControlGroupState, + setExpandedPanelId, + setFullScreenMode, + setPanels, + setQuery, +} from '../state'; import { diffDashboardContainerInput } from './diff_dashboard_state'; import { replaceUrlHashQuery } from '../../../../kibana_utils/public'; import { DashboardBuildContext, DashboardContainerInput } from '../../types'; @@ -113,6 +119,10 @@ export const applyContainerChangesToState = ({ if (!_.isEqual(input.expandedPanelId, latestState.expandedPanelId)) { dispatchDashboardStateChange(setExpandedPanelId(input.expandedPanelId)); } + + if (!_.isEqual(input.controlGroupInput, latestState.controlGroupInput)) { + dispatchDashboardStateChange(setControlGroupState(input.controlGroupInput)); + } dispatchDashboardStateChange(setFullScreenMode(input.isFullScreenMode)); }; diff --git a/src/plugins/dashboard/public/application/lib/sync_dashboard_index_patterns.ts b/src/plugins/dashboard/public/application/lib/sync_dashboard_index_patterns.ts index 3a1d60696331a..5460ef7b00037 100644 --- a/src/plugins/dashboard/public/application/lib/sync_dashboard_index_patterns.ts +++ b/src/plugins/dashboard/public/application/lib/sync_dashboard_index_patterns.ts @@ -8,7 +8,7 @@ import { uniqBy } from 'lodash'; import deepEqual from 'fast-deep-equal'; -import { Observable, pipe } from 'rxjs'; +import { Observable, pipe, combineLatest } from 'rxjs'; import { distinctUntilChanged, switchMap, filter, mapTo, map } from 'rxjs/operators'; import { DashboardContainer } from '..'; @@ -30,6 +30,7 @@ export const syncDashboardIndexPatterns = ({ filter((container: DashboardContainer) => !!container && !isErrorEmbeddable(container)), map((container: DashboardContainer): IndexPattern[] | undefined => { let panelIndexPatterns: IndexPattern[] = []; + Object.values(container.getChildIds()).forEach((id) => { const embeddableInstance = container.getChild(id); if (isErrorEmbeddable(embeddableInstance)) return; @@ -37,6 +38,9 @@ export const syncDashboardIndexPatterns = ({ if (!embeddableIndexPatterns) return; panelIndexPatterns.push(...embeddableIndexPatterns); }); + if (container.controlGroup) { + panelIndexPatterns.push(...(container.controlGroup.getOutput().dataViews ?? [])); + } panelIndexPatterns = uniqBy(panelIndexPatterns, 'id'); /** @@ -77,8 +81,11 @@ export const syncDashboardIndexPatterns = ({ }) ); - return dashboardContainer - .getOutput$() + const indexPatternSources = [dashboardContainer.getOutput$()]; + if (dashboardContainer.controlGroup) + indexPatternSources.push(dashboardContainer.controlGroup.getOutput$()); + + return combineLatest(indexPatternSources) .pipe(mapTo(dashboardContainer), updateIndexPatternsOperator) .subscribe(); }; diff --git a/src/plugins/dashboard/public/application/state/dashboard_state_slice.ts b/src/plugins/dashboard/public/application/state/dashboard_state_slice.ts index 1acf806ae2f0d..5604dfaa875e1 100644 --- a/src/plugins/dashboard/public/application/state/dashboard_state_slice.ts +++ b/src/plugins/dashboard/public/application/state/dashboard_state_slice.ts @@ -10,6 +10,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { Filter, Query } from '../../services/data'; import { ViewMode } from '../../services/embeddable'; +import type { DashboardControlGroupInput } from '../lib/dashboard_control_group'; import { DashboardOptions, DashboardPanelMap, DashboardState } from '../../types'; export const dashboardStateSlice = createSlice({ @@ -41,6 +42,12 @@ export const dashboardStateSlice = createSlice({ state.tags = action.payload.tags; } }, + setControlGroupState: ( + state, + action: PayloadAction + ) => { + state.controlGroupInput = action.payload; + }, setUseMargins: (state, action: PayloadAction) => { state.options.useMargins = action.payload; }, @@ -92,6 +99,7 @@ export const dashboardStateSlice = createSlice({ export const { setStateFromSaveModal, + setControlGroupState, setDashboardOptions, setExpandedPanelId, setHidePanelTitles, diff --git a/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx index 8a46a16c1bf0c..effbf8ce980d7 100644 --- a/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx @@ -231,7 +231,7 @@ export const EditorMenu = ({ dashboardContainer, createNewVisType }: Props) => { ({ + controlStyle: 'oneLine' as ControlStyle, + panels: {}, +}); + export function createDashboardEditUrl(id?: string, editMode?: boolean) { if (!id) { return `${DashboardConstants.CREATE_NEW_DASHBOARD_URL}`; diff --git a/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts b/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts index 4afb42aa841bb..d8e8b70fc1340 100644 --- a/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts +++ b/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts @@ -18,6 +18,8 @@ import { extractReferences, injectReferences } from '../../common/saved_dashboar import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/types'; import { DashboardOptions } from '../types'; +import { ControlStyle } from '../../../presentation_util/public'; + export interface DashboardSavedObject extends SavedObject { id?: string; timeRestore: boolean; @@ -36,6 +38,8 @@ export interface DashboardSavedObject extends SavedObject { getFullEditPath: (editMode?: boolean) => string; outcome?: string; aliasId?: string; + + controlGroupInput?: { controlStyle?: ControlStyle; panelsJSON?: string }; } const defaults = { @@ -86,6 +90,13 @@ export function createSavedDashboardClass( value: { type: 'integer' }, }, }, + controlGroupInput: { + type: 'object', + properties: { + controlStyle: { type: 'keyword' }, + panelsJSON: { type: 'text' }, + }, + }, }; public static fieldOrder = ['title', 'description']; public static searchSource = true; diff --git a/src/plugins/dashboard/public/types.ts b/src/plugins/dashboard/public/types.ts index 651a51834a794..c4cc00838a343 100644 --- a/src/plugins/dashboard/public/types.ts +++ b/src/plugins/dashboard/public/types.ts @@ -33,10 +33,11 @@ import { SavedObjectsTaggingApi } from './services/saved_objects_tagging_oss'; import { DataPublicPluginStart, IndexPatternsContract } from './services/data'; import { SavedObjectLoader, SavedObjectsStart } from './services/saved_objects'; import { IKbnUrlStateStorage } from './services/kibana_utils'; -import { DashboardContainer, DashboardSavedObject } from '.'; +import type { DashboardContainer, DashboardSavedObject } from '.'; import { VisualizationsStart } from '../../visualizations/public'; import { DashboardAppLocatorParams } from './locator'; import { SpacesPluginStart } from './services/spaces'; +import type { DashboardControlGroupInput } from './application/lib/dashboard_control_group'; export { SavedDashboardPanel }; @@ -65,6 +66,8 @@ export interface DashboardState { expandedPanelId?: string; options: DashboardOptions; panels: DashboardPanelMap; + + controlGroupInput?: DashboardControlGroupInput; } /** @@ -74,6 +77,7 @@ export type RawDashboardState = Omit & { panels: Saved export interface DashboardContainerInput extends ContainerInput { dashboardCapabilities?: DashboardAppCapabilities; + controlGroupInput?: DashboardControlGroupInput; refreshConfig?: RefreshInterval; isEmbeddedExternally?: boolean; isFullScreenMode: boolean; diff --git a/src/plugins/dashboard/server/saved_objects/dashboard.ts b/src/plugins/dashboard/server/saved_objects/dashboard.ts index 068883c429e61..2ddbcfd9fdb74 100644 --- a/src/plugins/dashboard/server/saved_objects/dashboard.ts +++ b/src/plugins/dashboard/server/saved_objects/dashboard.ts @@ -19,7 +19,8 @@ export const createDashboardSavedObjectType = ({ }): SavedObjectsType => ({ name: 'dashboard', hidden: false, - namespaceType: 'single', + namespaceType: 'multiple-isolated', + convertToMultiNamespaceTypeVersion: '8.0.0', management: { icon: 'dashboardApp', defaultSearchField: 'title', @@ -51,6 +52,12 @@ export const createDashboardSavedObjectType = ({ value: { type: 'integer', index: false, doc_values: false }, }, }, + controlGroupInput: { + properties: { + controlStyle: { type: 'keyword', index: false, doc_values: false }, + panelsJSON: { type: 'text', index: false }, + }, + }, timeFrom: { type: 'keyword', index: false, doc_values: false }, timeRestore: { type: 'boolean', index: false, doc_values: false }, timeTo: { type: 'keyword', index: false, doc_values: false }, diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index e141bfbef3c89..1c457fdb64ce2 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -35,4 +35,5 @@ export const UI_SETTINGS = { AUTOCOMPLETE_USE_TIMERANGE: 'autocomplete:useTimeRange', AUTOCOMPLETE_VALUE_SUGGESTION_METHOD: 'autocomplete:valueSuggestionMethod', DATE_FORMAT: 'dateFormat', + DATEFORMAT_TZ: 'dateFormat:tz', } as const; diff --git a/src/plugins/data/common/search/aggs/agg_configs.ts b/src/plugins/data/common/search/aggs/agg_configs.ts index 3157735a39967..9a362466c0fd7 100644 --- a/src/plugins/data/common/search/aggs/agg_configs.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.ts @@ -11,7 +11,7 @@ import _, { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; import { Assign } from '@kbn/utility-types'; import { isRangeFilter } from '@kbn/es-query'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IEsSearchResponse, diff --git a/src/plugins/data/common/search/aggs/agg_type.ts b/src/plugins/data/common/search/aggs/agg_type.ts index ebc1705f6c01b..917f80d3b7819 100644 --- a/src/plugins/data/common/search/aggs/agg_type.ts +++ b/src/plugins/data/common/search/aggs/agg_type.ts @@ -14,7 +14,7 @@ import { DatatableColumnType } from 'src/plugins/expressions/common'; import type { RequestAdapter } from 'src/plugins/inspector/common'; import type { SerializedFieldFormat } from 'src/plugins/field_formats/common'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { initParams } from './agg_params'; import { AggConfig } from './agg_config'; import { IAggConfigs } from './agg_configs'; diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts index 436cc5614ac80..ef5066e84f985 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -7,7 +7,7 @@ */ import { isNumber, keys, values, find, each, cloneDeep, flatten } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildExistsFilter, buildPhrasesFilter, buildQueryFromFilters } from '@kbn/es-query'; import { AggGroupNames } from '../agg_groups'; import { IAggConfigs } from '../agg_configs'; diff --git a/src/plugins/data/common/search/aggs/utils/time_splits.ts b/src/plugins/data/common/search/aggs/utils/time_splits.ts index 0510f629540f6..c4a603a383e38 100644 --- a/src/plugins/data/common/search/aggs/utils/time_splits.ts +++ b/src/plugins/data/common/search/aggs/utils/time_splits.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import _, { isArray } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RangeFilter } from '@kbn/es-query'; import { AggGroupNames } from '../agg_groups'; diff --git a/src/plugins/data/common/search/expressions/es_raw_response.ts b/src/plugins/data/common/search/expressions/es_raw_response.ts index 2d12af017d88c..61d79939e8635 100644 --- a/src/plugins/data/common/search/expressions/es_raw_response.ts +++ b/src/plugins/data/common/search/expressions/es_raw_response.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ExpressionTypeDefinition } from '../../../../expressions/common'; const name = 'es_raw_response'; diff --git a/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts b/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts index 67c23fb16b8de..df32b6ffed2e7 100644 --- a/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts +++ b/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts @@ -14,7 +14,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ISearchSource } from 'src/plugins/data/public'; import type { RequestStatistics } from 'src/plugins/inspector/common'; diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 7b4537043c31c..50752523403cf 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -71,7 +71,7 @@ import { tap, } from 'rxjs/operators'; import { defer, EMPTY, from, Observable } from 'rxjs'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildEsQuery, Filter } from '@kbn/es-query'; import { normalizeSortRequest } from './normalize_sort_request'; import { fieldWildcardFilter } from '../../../../kibana_utils/common'; diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index a19316c1c8418..c411e53abfcd2 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IAggConfigs } from 'src/plugins/data/public'; import { Query } from '../..'; import { Filter } from '../../es_query'; diff --git a/src/plugins/data/common/search/session/types.ts b/src/plugins/data/common/search/session/types.ts index 8e3c298aa9316..cbe3de9be4c73 100644 --- a/src/plugins/data/common/search/session/types.ts +++ b/src/plugins/data/common/search/session/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { SerializableRecord } from '@kbn/utility-types'; import { SearchSessionStatus } from './status'; export const SEARCH_SESSION_TYPE = 'search-session'; @@ -43,19 +44,19 @@ export interface SearchSessionSavedObjectAttributes { */ status: SearchSessionStatus; /** - * urlGeneratorId + * locatorId (see share.url.locators service) */ - urlGeneratorId?: string; + locatorId?: string; /** * The application state that was used to create the session. * Should be used, for example, to re-load an expired search session. */ - initialState?: Record; + initialState?: SerializableRecord; /** * Application state that should be used to restore the session. * For example, relative dates are conveted to absolute ones. */ - restoreState?: Record; + restoreState?: SerializableRecord; /** * Mapping of search request hashes to their corresponsing info (async search id, etc.) */ diff --git a/src/plugins/data/common/search/strategies/eql_search/types.ts b/src/plugins/data/common/search/strategies/eql_search/types.ts index a30adbaf47c60..7f6ec4809b2c5 100644 --- a/src/plugins/data/common/search/strategies/eql_search/types.ts +++ b/src/plugins/data/common/search/strategies/eql_search/types.ts @@ -6,17 +6,17 @@ * Side Public License, v 1. */ -import { EqlSearch } from '@elastic/elasticsearch/api/requestParams'; -import { ApiResponse, TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; +import type { EqlSearchRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TransportResult, TransportRequestOptions } from '@elastic/elasticsearch'; import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../types'; export const EQL_SEARCH_STRATEGY = 'eql'; -export type EqlRequestParams = EqlSearch>; +export type EqlRequestParams = EqlSearchRequest; export interface EqlSearchStrategyRequest extends IKibanaSearchRequest { options?: TransportRequestOptions; } -export type EqlSearchStrategyResponse = IKibanaSearchResponse>; +export type EqlSearchStrategyResponse = IKibanaSearchResponse>; diff --git a/src/plugins/data/common/search/strategies/es_search/types.ts b/src/plugins/data/common/search/strategies/es_search/types.ts index 05df661d466c8..73bf7961fea9b 100644 --- a/src/plugins/data/common/search/strategies/es_search/types.ts +++ b/src/plugins/data/common/search/strategies/es_search/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../types'; diff --git a/src/plugins/data/common/search/tabify/tabify_docs.test.ts b/src/plugins/data/common/search/tabify/tabify_docs.test.ts index 1964247b09585..8bba487cef9b3 100644 --- a/src/plugins/data/common/search/tabify/tabify_docs.test.ts +++ b/src/plugins/data/common/search/tabify/tabify_docs.test.ts @@ -8,7 +8,7 @@ import { tabifyDocs, flattenHit } from './tabify_docs'; import { IndexPattern, DataView } from '../..'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; import { stubbedSavedObjectIndexPattern } from '../../../../data_views/common/data_view.stub'; diff --git a/src/plugins/data/common/search/tabify/tabify_docs.ts b/src/plugins/data/common/search/tabify/tabify_docs.ts index 353a0c10ba12a..43b6155f6662f 100644 --- a/src/plugins/data/common/search/tabify/tabify_docs.ts +++ b/src/plugins/data/common/search/tabify/tabify_docs.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPlainObject } from 'lodash'; import { IndexPattern } from '../..'; import { Datatable, DatatableColumn, DatatableColumnType } from '../../../../expressions/common'; diff --git a/src/plugins/data/public/search/errors/types.ts b/src/plugins/data/public/search/errors/types.ts index 13c5d0c242ed0..d541e53be78f9 100644 --- a/src/plugins/data/public/search/errors/types.ts +++ b/src/plugins/data/public/search/errors/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { KibanaServerError } from '../../../../kibana_utils/common'; export interface FailedShard { diff --git a/src/plugins/data/public/search/errors/utils.ts b/src/plugins/data/public/search/errors/utils.ts index cb3e83dc8001c..4373939878d68 100644 --- a/src/plugins/data/public/search/errors/utils.ts +++ b/src/plugins/data/public/search/errors/utils.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { ErrorCause } from '@elastic/elasticsearch/api/types'; +import type { ErrorCause } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { FailedShard, Reason } from './types'; import { KibanaServerError } from '../../../../kibana_utils/common'; diff --git a/src/plugins/data/public/search/session/search_session_state.test.ts b/src/plugins/data/public/search/session/search_session_state.test.ts index 65b931f23cf2e..ef18275da12fa 100644 --- a/src/plugins/data/public/search/session/search_session_state.test.ts +++ b/src/plugins/data/public/search/session/search_session_state.test.ts @@ -16,7 +16,7 @@ const mockSavedObject: SearchSessionSavedObject = { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_url_generator_id', idMapping: {}, sessionId: 'session_id', touched: new Date().toISOString(), diff --git a/src/plugins/data/public/search/session/session_service.test.ts b/src/plugins/data/public/search/session/session_service.test.ts index 5c1882248f76a..4a11cdb38bb7d 100644 --- a/src/plugins/data/public/search/session/session_service.test.ts +++ b/src/plugins/data/public/search/session/session_service.test.ts @@ -25,7 +25,7 @@ const mockSavedObject: SearchSessionSavedObject = { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', idMapping: {}, sessionId: 'session_id', touched: new Date().toISOString(), @@ -192,8 +192,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -245,8 +245,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -299,8 +299,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -319,8 +319,8 @@ describe('Session service', () => { sessionService.enableStorage( { getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -336,10 +336,10 @@ describe('Session service', () => { expect(sessionService.getSearchSessionIndicatorUiConfig().isDisabled().disabled).toBe(false); }); - test('save() throws in case getUrlGeneratorData returns throws', async () => { + test('save() throws in case getLocatorData returns throws', async () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => { + getLocatorData: async () => { throw new Error('Haha'); }, }); @@ -373,8 +373,8 @@ describe('Session service', () => { sessionsClient.rename.mockRejectedValue(renameError); sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), diff --git a/src/plugins/data/public/search/session/session_service.ts b/src/plugins/data/public/search/session/session_service.ts index 874fad67c4df1..360e8808c186d 100644 --- a/src/plugins/data/public/search/session/session_service.ts +++ b/src/plugins/data/public/search/session/session_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PublicContract } from '@kbn/utility-types'; +import { PublicContract, SerializableRecord } from '@kbn/utility-types'; import { distinctUntilChanged, map, startWith } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; import { @@ -15,14 +15,13 @@ import { ToastsStart as ToastService, } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { UrlGeneratorId, UrlGeneratorStateMapping } from '../../../../share/public/'; import { ConfigSchema } from '../../../config'; import { createSessionStateContainer, SearchSessionState, - SessionStateInternal, SessionMeta, SessionStateContainer, + SessionStateInternal, } from './search_session_state'; import { ISessionsClient } from './sessions_client'; import { ISearchOptions } from '../../../common'; @@ -44,7 +43,7 @@ export type SessionSnapshot = SessionStateInternal; /** * Provide info about current search session to be stored in the Search Session saved object */ -export interface SearchSessionInfoProvider { +export interface SearchSessionInfoProvider

{ /** * User-facing name of the session. * e.g. will be displayed in saved Search Sessions management list @@ -57,10 +56,10 @@ export interface SearchSessionInfoProvider Promise<{ - urlGeneratorId: ID; - initialState: UrlGeneratorStateMapping[ID]['State']; - restoreState: UrlGeneratorStateMapping[ID]['State']; + getLocatorData: () => Promise<{ + id: string; + initialState: P; + restoreState: P; }>; } @@ -316,9 +315,9 @@ export class SessionService { if (!this.hasAccess()) throw new Error('No access to search sessions'); const currentSessionInfoProvider = this.searchSessionInfoProvider; if (!currentSessionInfoProvider) throw new Error('No info provider for current session'); - const [name, { initialState, restoreState, urlGeneratorId }] = await Promise.all([ + const [name, { initialState, restoreState, id: locatorId }] = await Promise.all([ currentSessionInfoProvider.getName(), - currentSessionInfoProvider.getUrlGeneratorData(), + currentSessionInfoProvider.getLocatorData(), ]); const formattedName = formatSessionName(name, { @@ -329,9 +328,9 @@ export class SessionService { const searchSessionSavedObject = await this.sessionsClient.create({ name: formattedName, appId: currentSessionApp, - restoreState: restoreState as unknown as Record, - initialState: initialState as unknown as Record, - urlGeneratorId, + locatorId, + restoreState, + initialState, sessionId, }); @@ -411,8 +410,8 @@ export class SessionService { * @param searchSessionInfoProvider - info provider for saving a search session * @param searchSessionIndicatorUiConfig - config for "Search session indicator" UI */ - public enableStorage( - searchSessionInfoProvider: SearchSessionInfoProvider, + public enableStorage

( + searchSessionInfoProvider: SearchSessionInfoProvider

, searchSessionIndicatorUiConfig?: SearchSessionIndicatorUiConfig ) { this.searchSessionInfoProvider = { diff --git a/src/plugins/data/public/search/session/sessions_client.ts b/src/plugins/data/public/search/session/sessions_client.ts index 0b6f1b79f0c63..d267ba52b024c 100644 --- a/src/plugins/data/public/search/session/sessions_client.ts +++ b/src/plugins/data/public/search/session/sessions_client.ts @@ -37,26 +37,26 @@ export class SessionsClient { public create({ name, appId, - urlGeneratorId, + locatorId, initialState, restoreState, sessionId, }: { name: string; appId: string; + locatorId: string; initialState: Record; restoreState: Record; - urlGeneratorId: string; sessionId: string; }): Promise { return this.http.post(`/internal/session`, { body: JSON.stringify({ name, + appId, + locatorId, initialState, restoreState, sessionId, - appId, - urlGeneratorId, }), }); } diff --git a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx index 09fd818f23703..8abf6a41d8762 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx @@ -55,6 +55,8 @@ function FilterBarUI(props: Props) { } } + const onAddFilterClick = () => setIsAddFilterPopoverOpen(!isAddFilterPopoverOpen); + function renderItems() { return props.filters.map((filter, i) => ( @@ -81,7 +83,7 @@ function FilterBarUI(props: Props) { const button = ( setIsAddFilterPopoverOpen(true)} + onClick={onAddFilterClick} data-test-subj="addFilter" className="globalFilterBar__addButton" > diff --git a/src/plugins/data/public/ui/shard_failure_modal/__mocks__/shard_failure_response.ts b/src/plugins/data/public/ui/shard_failure_modal/__mocks__/shard_failure_response.ts index e4a31995e47b6..50355a933ec5d 100644 --- a/src/plugins/data/public/ui/shard_failure_modal/__mocks__/shard_failure_response.ts +++ b/src/plugins/data/public/ui/shard_failure_modal/__mocks__/shard_failure_response.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export const shardFailureResponse: estypes.SearchResponse = { _shards: { diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_modal.tsx b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_modal.tsx index 8e6ad4bc92c8f..e009af4250e6c 100644 --- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_modal.tsx +++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_modal.tsx @@ -21,7 +21,7 @@ import { EuiButtonEmpty, EuiCallOut, } from '@elastic/eui'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ShardFailureTable } from './shard_failure_table'; import { ShardFailureRequest } from './shard_failure_types'; diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx index a230378d6c3d3..4ebdd64fede13 100644 --- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx +++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiTextAlign } from '@elastic/eui'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getOverlays } from '../../services'; import { toMountPoint } from '../../../../kibana_react/public'; diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_types.ts b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_types.ts index 83e4abf55d525..c6533f9f0a850 100644 --- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_types.ts +++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export interface ShardFailureRequest { docvalue_fields: string[]; _source: unknown; diff --git a/src/plugins/data/server/autocomplete/terms_agg.test.ts b/src/plugins/data/server/autocomplete/terms_agg.test.ts index dcaa5390f3fe6..eb24b71cae274 100644 --- a/src/plugins/data/server/autocomplete/terms_agg.test.ts +++ b/src/plugins/data/server/autocomplete/terms_agg.test.ts @@ -10,9 +10,9 @@ import { coreMock } from '../../../../core/server/mocks'; import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; import { ConfigSchema } from '../../config'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import type { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { termsAggSuggestions } from './terms_agg'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { duration } from 'moment'; let savedObjectsClientMock: jest.Mocked; @@ -32,7 +32,7 @@ const mockResponse = { }, }, }, -} as ApiResponse>; +} as TransportResult>; jest.mock('../data_views'); diff --git a/src/plugins/data/server/autocomplete/terms_agg.ts b/src/plugins/data/server/autocomplete/terms_agg.ts index 41544b9e01233..20a8a5c212f26 100644 --- a/src/plugins/data/server/autocomplete/terms_agg.ts +++ b/src/plugins/data/server/autocomplete/terms_agg.ts @@ -8,11 +8,10 @@ import { get, map } from 'lodash'; import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ConfigSchema } from '../../config'; import { IFieldType, getFieldSubtypeNested } from '../../common'; import { findIndexPatternById, getFieldByName } from '../data_views'; -import { shimAbortSignal } from '../search'; export async function termsAggSuggestions( config: ConfigSchema, @@ -38,8 +37,12 @@ export async function termsAggSuggestions( const body = await getBody(autocompleteSearchOptions, field ?? fieldName, query, filters); - const promise = esClient.search({ index, body }); - const result = await shimAbortSignal(promise, abortSignal); + const result = await esClient.search( + { index, body }, + { + signal: abortSignal, + } + ); const buckets = get(result.body, 'aggregations.suggestions.buckets') || diff --git a/src/plugins/data/server/autocomplete/terms_enum.test.ts b/src/plugins/data/server/autocomplete/terms_enum.test.ts index 444ba4e89c58b..c0750ead5cc0a 100644 --- a/src/plugins/data/server/autocomplete/terms_enum.test.ts +++ b/src/plugins/data/server/autocomplete/terms_enum.test.ts @@ -11,8 +11,8 @@ import { coreMock } from '../../../../core/server/mocks'; import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; import { ConfigSchema } from '../../config'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import type { ApiResponse } from '@elastic/elasticsearch'; -import { TermsEnumResponse } from '@elastic/elasticsearch/api/types'; +import type { TransportResult } from '@elastic/elasticsearch'; +import { TermsEnumResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; let savedObjectsClientMock: jest.Mocked; let esClientMock: DeeplyMockedKeys; @@ -31,7 +31,7 @@ describe('_terms_enum suggestions', () => { savedObjectsClientMock = requestHandlerContext.savedObjects.client; esClientMock = requestHandlerContext.elasticsearch.client.asCurrentUser; esClientMock.termsEnum.mockResolvedValue( - mockResponse as unknown as ApiResponse + mockResponse as unknown as TransportResult ); }); diff --git a/src/plugins/data/server/autocomplete/terms_enum.ts b/src/plugins/data/server/autocomplete/terms_enum.ts index 3d7f369233720..201ff32c056ce 100644 --- a/src/plugins/data/server/autocomplete/terms_enum.ts +++ b/src/plugins/data/server/autocomplete/terms_enum.ts @@ -7,10 +7,9 @@ */ import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IFieldType } from '../../common'; import { findIndexPatternById, getFieldByName } from '../data_views'; -import { shimAbortSignal } from '../search'; import { ConfigSchema } from '../../config'; export async function termsEnumSuggestions( @@ -30,26 +29,30 @@ export async function termsEnumSuggestions( field = indexPattern && getFieldByName(fieldName, indexPattern); } - const promise = esClient.termsEnum({ - index, - body: { - field: field?.name ?? fieldName, - string: query, - index_filter: { - bool: { - must: [ - ...(filters ?? []), - { - terms: { - _tier: tiers, + const result = await esClient.termsEnum( + { + index, + body: { + field: field?.name ?? fieldName, + string: query, + index_filter: { + bool: { + must: [ + ...(filters ?? []), + { + terms: { + _tier: tiers, + }, }, - }, - ], + ], + }, }, }, }, - }); + { + signal: abortSignal, + } + ); - const result = await shimAbortSignal(promise, abortSignal); return result.body.terms; } diff --git a/src/plugins/data/server/kql_telemetry/kql_telemetry_service.ts b/src/plugins/data/server/kql_telemetry/kql_telemetry_service.ts index 09e64ba7f4310..423ebbdcd43c7 100644 --- a/src/plugins/data/server/kql_telemetry/kql_telemetry_service.ts +++ b/src/plugins/data/server/kql_telemetry/kql_telemetry_service.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { first } from 'rxjs/operators'; import { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; import { registerKqlTelemetryRoute } from './route'; import { UsageCollectionSetup } from '../../../usage_collection/server'; @@ -28,15 +27,13 @@ export class KqlTelemetryService implements Plugin { ); if (usageCollection) { - this.initializerContext.config.legacy.globalConfig$ - .pipe(first()) - .toPromise() - .then((config) => makeKQLUsageCollector(usageCollection, config.kibana.index)) - .catch((e) => { - this.initializerContext.logger - .get('kql-telemetry') - .warn(`Registering KQL telemetry collector failed: ${e}`); - }); + try { + makeKQLUsageCollector(usageCollection, savedObjects.getKibanaIndex()); + } catch (e) { + this.initializerContext.logger + .get('kql-telemetry') + .warn(`Registering KQL telemetry collector failed: ${e}`); + } } } diff --git a/src/plugins/data/server/kql_telemetry/usage_collector/make_kql_usage_collector.ts b/src/plugins/data/server/kql_telemetry/usage_collector/make_kql_usage_collector.ts index f3b5865bd0893..39ea7d6ab2dec 100644 --- a/src/plugins/data/server/kql_telemetry/usage_collector/make_kql_usage_collector.ts +++ b/src/plugins/data/server/kql_telemetry/usage_collector/make_kql_usage_collector.ts @@ -9,10 +9,7 @@ import { fetchProvider, Usage } from './fetch'; import { UsageCollectionSetup } from '../../../../usage_collection/server'; -export async function makeKQLUsageCollector( - usageCollection: UsageCollectionSetup, - kibanaIndex: string -) { +export function makeKQLUsageCollector(usageCollection: UsageCollectionSetup, kibanaIndex: string) { const kqlUsageCollector = usageCollection.makeUsageCollector({ type: 'kql', fetch: fetchProvider(kibanaIndex), diff --git a/src/plugins/data/server/search/collectors/fetch.ts b/src/plugins/data/server/search/collectors/fetch.ts index 8c4b79b290565..a2d1917fc4770 100644 --- a/src/plugins/data/server/search/collectors/fetch.ts +++ b/src/plugins/data/server/search/collectors/fetch.ts @@ -6,21 +6,18 @@ * Side Public License, v 1. */ -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; -import { SharedGlobalConfig } from 'kibana/server'; import { CollectorFetchContext } from 'src/plugins/usage_collection/server'; import { CollectedUsage, ReportedUsage } from './register'; + interface SearchTelemetry { 'search-telemetry': CollectedUsage; } -export function fetchProvider(config$: Observable) { +export function fetchProvider(kibanaIndex: string) { return async ({ esClient }: CollectorFetchContext): Promise => { - const config = await config$.pipe(first()).toPromise(); const { body: esResponse } = await esClient.search( { - index: config.kibana.index, + index: kibanaIndex, body: { query: { term: { type: { value: 'search-telemetry' } } }, }, diff --git a/src/plugins/data/server/search/collectors/register.ts b/src/plugins/data/server/search/collectors/register.ts index a370377c30eea..a70b9760122a9 100644 --- a/src/plugins/data/server/search/collectors/register.ts +++ b/src/plugins/data/server/search/collectors/register.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from 'kibana/server'; import { UsageCollectionSetup } from '../../../../usage_collection/server'; import { fetchProvider } from './fetch'; @@ -22,15 +21,12 @@ export interface ReportedUsage { averageDuration: number | null; } -export async function registerUsageCollector( - usageCollection: UsageCollectionSetup, - context: PluginInitializerContext -) { +export function registerUsageCollector(usageCollection: UsageCollectionSetup, kibanaIndex: string) { try { const collector = usageCollection.makeUsageCollector({ type: 'search', isReady: () => true, - fetch: fetchProvider(context.config.legacy.globalConfig$), + fetch: fetchProvider(kibanaIndex), schema: { successCount: { type: 'long' }, errorCount: { type: 'long' }, diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 04db51fdce7fb..d3b1c57b67779 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -184,7 +184,7 @@ export class SearchService implements Plugin { core.savedObjects.registerType(searchTelemetry); if (usageCollection) { - registerUsageCollector(usageCollection, this.initializerContext); + registerUsageCollector(usageCollection, core.savedObjects.getKibanaIndex()); } expressions.registerFunction(getEsaggs({ getStartServices: core.getStartServices })); diff --git a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts index 4c75d62f12190..3d9294765cc15 100644 --- a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { tap } from 'rxjs/operators'; import type { IScopedClusterClient, Logger } from 'kibana/server'; import { @@ -18,7 +18,7 @@ import { import { toEqlKibanaSearchResponse } from './response_utils'; import { EqlSearchResponse } from './types'; import { ISearchStrategy } from '../../types'; -import { getDefaultSearchParams, shimAbortSignal } from '../es_search'; +import { getDefaultSearchParams } from '../es_search'; import { getDefaultAsyncGetParams, getIgnoreThrottled } from '../ese_search/request_utils'; export const eqlSearchStrategyProvider = ( @@ -52,12 +52,15 @@ export const eqlSearchStrategyProvider = ( ...getDefaultAsyncGetParams(null, options), ...request.params, }; - const promise = id - ? client.get({ ...params, id }, request.options) - : // @ts-expect-error EqlRequestParams | undefined is not assignable to EqlRequestParams - client.search(params as EqlSearchStrategyRequest['params'], request.options); - const response = await shimAbortSignal(promise, options.abortSignal); - return toEqlKibanaSearchResponse(response as ApiResponse); + const response = id + ? await client.get({ ...params, id }, { ...request.options, signal: options.abortSignal }) + : // @ts-expect-error optional key cannot be used since search doesn't expect undefined + await client.search(params as EqlSearchStrategyRequest['params'], { + ...request.options, + abortController: { signal: options.abortSignal }, + }); + + return toEqlKibanaSearchResponse(response as TransportResult); }; const cancel = async () => { diff --git a/src/plugins/data/server/search/strategies/eql_search/response_utils.ts b/src/plugins/data/server/search/strategies/eql_search/response_utils.ts index 11b5a286e709d..f9bdf5bc7de30 100644 --- a/src/plugins/data/server/search/strategies/eql_search/response_utils.ts +++ b/src/plugins/data/server/search/strategies/eql_search/response_utils.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { EqlSearchResponse } from './types'; import { EqlSearchStrategyResponse } from '../../../../common'; @@ -15,7 +15,7 @@ import { EqlSearchStrategyResponse } from '../../../../common'; * (EQL does not provide _shard info, so total/loaded cannot be calculated.) */ export function toEqlKibanaSearchResponse( - response: ApiResponse + response: TransportResult ): EqlSearchStrategyResponse { return { id: response.body.id, diff --git a/src/plugins/data/server/search/strategies/eql_search/types.ts b/src/plugins/data/server/search/strategies/eql_search/types.ts index 4b3c19fda78ea..695490b668e38 100644 --- a/src/plugins/data/server/search/strategies/eql_search/types.ts +++ b/src/plugins/data/server/search/strategies/eql_search/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export interface EqlSearchResponse extends estypes.SearchResponse { id?: string; diff --git a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts index bbbc99d157fe0..c06a75f3148a8 100644 --- a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts @@ -5,18 +5,14 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import { - elasticsearchClientMock, - MockedTransportRequestPromise, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../core/server/elasticsearch/client/mocks'; +import type { TransportResult } from '@elastic/elasticsearch'; +import { elasticsearchServiceMock } from '../../../../../../core/server/mocks'; import { pluginInitializerContextConfigMock } from '../../../../../../core/server/mocks'; import { esSearchStrategyProvider } from './es_search_strategy'; import { SearchStrategyDependencies } from '../../types'; import * as indexNotFoundException from '../../../../common/search/test_data/index_not_found_exception.json'; -import { ElasticsearchClientError, ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { KbnServerError } from '../../../../../kibana_utils/server'; describe('ES search strategy', () => { @@ -27,9 +23,9 @@ describe('ES search strategy', () => { skipped: 2, successful: 7, }, - }; - let mockedApiCaller: MockedTransportRequestPromise; - let mockApiCaller: jest.Mock<() => MockedTransportRequestPromise>; + } as const; + let mockedApiCaller: Promise>; + let mockApiCaller: jest.Mock<() => TransportResult>; const mockLogger: any = { debug: () => {}, }; @@ -37,9 +33,9 @@ describe('ES search strategy', () => { function getMockedDeps(err?: Record) { mockApiCaller = jest.fn().mockImplementation(() => { if (err) { - mockedApiCaller = elasticsearchClientMock.createErrorTransportRequestPromise(err); + mockedApiCaller = elasticsearchServiceMock.createErrorTransportRequestPromise(err); } else { - mockedApiCaller = elasticsearchClientMock.createSuccessTransportRequestPromise( + mockedApiCaller = elasticsearchServiceMock.createSuccessTransportRequestPromise( successBody, { statusCode: 200 } ); @@ -108,7 +104,6 @@ describe('ES search strategy', () => { expect(data.isPartial).toBe(false); expect(data).toHaveProperty('loaded'); expect(data).toHaveProperty('rawResponse'); - expect(mockedApiCaller.abort).not.toBeCalled(); done(); })); @@ -127,12 +122,11 @@ describe('ES search strategy', () => { ...params, track_total_hits: true, }); - expect(mockedApiCaller.abort).toBeCalled(); }); it('throws normalized error if ResponseError is thrown', async (done) => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; - const errResponse = new ResponseError({ + const errResponse = new errors.ResponseError({ body: indexNotFoundException, statusCode: 404, headers: {}, @@ -156,7 +150,7 @@ describe('ES search strategy', () => { it('throws normalized error if ElasticsearchClientError is thrown', async (done) => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; - const errResponse = new ElasticsearchClientError('This is a general ESClient error'); + const errResponse = new errors.ElasticsearchClientError('This is a general ESClient error'); try { await esSearchStrategyProvider(mockConfig$, mockLogger) diff --git a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts index c24aa37082bd8..097e099bf2997 100644 --- a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts @@ -11,7 +11,7 @@ import { first, tap } from 'rxjs/operators'; import type { Logger, SharedGlobalConfig } from 'kibana/server'; import type { ISearchStrategy } from '../../types'; import type { SearchUsage } from '../../collectors'; -import { getDefaultSearchParams, getShardTimeout, shimAbortSignal } from './request_utils'; +import { getDefaultSearchParams, getShardTimeout } from './request_utils'; import { shimHitsTotal, toKibanaSearchResponse } from './response_utils'; import { searchUsageObserver } from '../../collectors/usage'; import { getKbnServerError, KbnServerError } from '../../../../../kibana_utils/server'; @@ -38,13 +38,17 @@ export const esSearchStrategyProvider = ( const search = async () => { try { const config = await config$.pipe(first()).toPromise(); + // @ts-expect-error params fall back to any, but should be valid SearchRequest params + const { terminateAfter, ...requestParams } = request.params ?? {}; const params = { ...(await getDefaultSearchParams(uiSettingsClient)), ...getShardTimeout(config), - ...request.params, + ...(terminateAfter ? { terminate_after: terminateAfter } : {}), + ...requestParams, }; - const promise = esClient.asCurrentUser.search(params); - const { body } = await shimAbortSignal(promise, abortSignal); + const { body } = await esClient.asCurrentUser.search(params, { + signal: abortSignal, + }); const response = shimHitsTotal(body, options); return toKibanaSearchResponse(response); } catch (e) { diff --git a/src/plugins/data/server/search/strategies/es_search/request_utils.test.ts b/src/plugins/data/server/search/strategies/es_search/request_utils.test.ts index 5d1826d92f182..d6e078c71a87d 100644 --- a/src/plugins/data/server/search/strategies/es_search/request_utils.test.ts +++ b/src/plugins/data/server/search/strategies/es_search/request_utils.test.ts @@ -6,19 +6,9 @@ * Side Public License, v 1. */ -import { getShardTimeout, getDefaultSearchParams, shimAbortSignal } from './request_utils'; +import { getShardTimeout, getDefaultSearchParams } from './request_utils'; import { IUiSettingsClient, SharedGlobalConfig } from 'kibana/server'; -const createSuccessTransportRequestPromise = ( - body: any, - { statusCode = 200 }: { statusCode?: number } = {} -) => { - const promise = Promise.resolve({ body, statusCode }) as any; - promise.abort = jest.fn(); - - return promise; -}; - describe('request utils', () => { describe('getShardTimeout', () => { test('returns an empty object if the config does not contain a value', () => { @@ -89,49 +79,4 @@ describe('request utils', () => { }); }); }); - - describe('shimAbortSignal', () => { - test('aborts the promise if the signal is already aborted', async () => { - const promise = createSuccessTransportRequestPromise({ - success: true, - }); - const controller = new AbortController(); - controller.abort(); - shimAbortSignal(promise, controller.signal); - - expect(promise.abort).toHaveBeenCalled(); - }); - - test('aborts the promise if the signal is aborted', () => { - const promise = createSuccessTransportRequestPromise({ - success: true, - }); - const controller = new AbortController(); - shimAbortSignal(promise, controller.signal); - controller.abort(); - - expect(promise.abort).toHaveBeenCalled(); - }); - - test('returns the original promise', async () => { - const promise = createSuccessTransportRequestPromise({ - success: true, - }); - const controller = new AbortController(); - const response = await shimAbortSignal(promise, controller.signal); - - expect(response).toEqual(expect.objectContaining({ body: { success: true } })); - }); - - test('allows the promise to be aborted manually', () => { - const promise = createSuccessTransportRequestPromise({ - success: true, - }); - const controller = new AbortController(); - const enhancedPromise = shimAbortSignal(promise, controller.signal); - - enhancedPromise.abort(); - expect(promise.abort).toHaveBeenCalled(); - }); - }); }); diff --git a/src/plugins/data/server/search/strategies/es_search/request_utils.ts b/src/plugins/data/server/search/strategies/es_search/request_utils.ts index 15cad34065ddc..9a57ac56ce250 100644 --- a/src/plugins/data/server/search/strategies/es_search/request_utils.ts +++ b/src/plugins/data/server/search/strategies/es_search/request_utils.ts @@ -6,21 +6,24 @@ * Side Public License, v 1. */ -import type { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; -import type { Search } from '@elastic/elasticsearch/api/requestParams'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { IUiSettingsClient, SharedGlobalConfig } from 'kibana/server'; import { UI_SETTINGS } from '../../../../common'; -export function getShardTimeout(config: SharedGlobalConfig): Pick { +export function getShardTimeout( + config: SharedGlobalConfig +): Pick { const timeout = config.elasticsearch.shardTimeout.asMilliseconds(); return timeout ? { timeout: `${timeout}ms` } : {}; } export async function getDefaultSearchParams( uiSettingsClient: Pick -): Promise< - Pick -> { +): Promise<{ + max_concurrent_shard_requests?: number; + ignore_unavailable: boolean; + track_total_hits: boolean; +}> { const maxConcurrentShardRequests = await uiSettingsClient.get( UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS ); @@ -31,25 +34,3 @@ export async function getDefaultSearchParams( track_total_hits: true, }; } - -/** - * Temporary workaround until https://github.com/elastic/elasticsearch-js/issues/1297 is resolved. - * Shims the `AbortSignal` behavior so that, if the given `signal` aborts, the `abort` method on the - * `TransportRequestPromise` is called, actually performing the cancellation. - * @internal - */ -export const shimAbortSignal = (promise: TransportRequestPromise, signal?: AbortSignal) => { - if (!signal) return promise; - const abortHandler = () => { - promise.abort(); - cleanup(); - }; - const cleanup = () => signal.removeEventListener('abort', abortHandler); - if (signal.aborted) { - promise.abort(); - } else { - signal.addEventListener('abort', abortHandler); - promise.then(cleanup, cleanup); - } - return promise; -}; diff --git a/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts b/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts index fc35187429a98..043bfd2e518ff 100644 --- a/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts +++ b/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts @@ -7,7 +7,7 @@ */ import { getTotalLoaded, toKibanaSearchResponse, shimHitsTotal } from './response_utils'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; describe('response utils', () => { describe('getTotalLoaded', () => { diff --git a/src/plugins/data/server/search/strategies/es_search/response_utils.ts b/src/plugins/data/server/search/strategies/es_search/response_utils.ts index 0553c015fb2da..4773b6df3bbaf 100644 --- a/src/plugins/data/server/search/strategies/es_search/response_utils.ts +++ b/src/plugins/data/server/search/strategies/es_search/response_utils.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ISearchOptions } from '../../../../common'; /** diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts index 8d5fbf98db2d3..d4fe74486ee85 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts @@ -8,7 +8,7 @@ import { BehaviorSubject } from 'rxjs'; import { KbnServerError } from '../../../../../kibana_utils/server'; -import { ElasticsearchClientError, ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import * as indexNotFoundException from '../../../../common/search/test_data/index_not_found_exception.json'; import * as xContentParseException from '../../../../common/search/test_data/x_content_parse_exception.json'; import { SearchStrategyDependencies } from '../../types'; @@ -191,7 +191,7 @@ describe('ES search strategy', () => { }); it('throws normalized error if ResponseError is thrown', async () => { - const errResponse = new ResponseError({ + const errResponse = new errors.ResponseError({ body: indexNotFoundException, statusCode: 404, headers: {}, @@ -254,7 +254,7 @@ describe('ES search strategy', () => { }); it('throws normalized error on ResponseError', async () => { - const errResponse = new ResponseError({ + const errResponse = new errors.ResponseError({ body: xContentParseException, statusCode: 400, headers: {}, @@ -297,7 +297,7 @@ describe('ES search strategy', () => { }); it('throws normalized error on ElasticsearchClientError', async () => { - const errResponse = new ElasticsearchClientError('something is wrong with EsClient'); + const errResponse = new errors.ElasticsearchClientError('something is wrong with EsClient'); mockGetCaller.mockRejectedValue(errResponse); const id = 'some_other_id'; diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts index 75a4ddf051418..e94f1aa44d351 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts @@ -9,7 +9,7 @@ import type { Observable } from 'rxjs'; import type { IScopedClusterClient, Logger, SharedGlobalConfig } from 'kibana/server'; import { catchError, first, tap } from 'rxjs/operators'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { from } from 'rxjs'; import type { ISearchStrategy, SearchStrategyDependencies } from '../../types'; import type { @@ -31,7 +31,6 @@ import { getDefaultSearchParams, getShardTimeout, getTotalLoaded, - shimAbortSignal, shimHitsTotal, } from '../es_search'; @@ -68,10 +67,11 @@ export const enhancedEsSearchStrategyProvider = ( )), ...request.params, }; - const promise = id - ? client.asyncSearch.get({ ...params, id }) - : client.asyncSearch.submit(params); - const { body, headers } = await shimAbortSignal(promise, options.abortSignal); + const { body, headers } = id + ? await client.asyncSearch.get({ ...params, id }, { signal: options.abortSignal }) + : await client.asyncSearch.submit(params, { + signal: options.abortSignal, + }); const response = shimHitsTotal(body.response, options); @@ -115,14 +115,18 @@ export const enhancedEsSearchStrategyProvider = ( }; try { - const promise = client.transport.request({ - method, - path, - body, - querystring, - }); + const esResponse = await client.transport.request( + { + method, + path, + body, + querystring, + }, + { + signal: options?.abortSignal, + } + ); - const esResponse = await shimAbortSignal(promise, options?.abortSignal); const response = esResponse.body as estypes.SearchResponse; return { rawResponse: shimHitsTotal(response, options), diff --git a/src/plugins/data/server/search/strategies/ese_search/request_utils.ts b/src/plugins/data/server/search/strategies/ese_search/request_utils.ts index f8fb54cfd870b..85f9f243ad2b1 100644 --- a/src/plugins/data/server/search/strategies/ese_search/request_utils.ts +++ b/src/plugins/data/server/search/strategies/ese_search/request_utils.ts @@ -7,11 +7,8 @@ */ import { IUiSettingsClient } from 'kibana/server'; -import { - AsyncSearchGet, - AsyncSearchSubmit, - Search, -} from '@elastic/elasticsearch/api/requestParams'; +import { AsyncSearchGetRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { AsyncSearchSubmitRequest } from '@elastic/elasticsearch/lib/api/types'; import { ISearchOptions, UI_SETTINGS } from '../../../../common'; import { getDefaultSearchParams } from '../es_search'; import { SearchSessionsConfigSchema } from '../../../../config'; @@ -21,7 +18,7 @@ import { SearchSessionsConfigSchema } from '../../../../config'; */ export async function getIgnoreThrottled( uiSettingsClient: Pick -): Promise> { +): Promise<{ ignore_throttled?: boolean }> { const includeFrozen = await uiSettingsClient.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); return includeFrozen ? { ignore_throttled: false } : {}; } @@ -35,7 +32,7 @@ export async function getDefaultAsyncSubmitParams( options: ISearchOptions ): Promise< Pick< - AsyncSearchSubmit, + AsyncSearchSubmitRequest, | 'batched_reduce_size' | 'keep_alive' | 'wait_for_completion_timeout' @@ -75,7 +72,7 @@ export async function getDefaultAsyncSubmitParams( export function getDefaultAsyncGetParams( searchSessionsConfig: SearchSessionsConfigSchema | null, options: ISearchOptions -): Pick { +): Pick { const useSearchSessions = searchSessionsConfig?.enabled && !!options.sessionId; return { diff --git a/src/plugins/data/server/search/strategies/ese_search/types.ts b/src/plugins/data/server/search/strategies/ese_search/types.ts index 7f21aa3616e4e..4116aa4380339 100644 --- a/src/plugins/data/server/search/strategies/ese_search/types.ts +++ b/src/plugins/data/server/search/strategies/ese_search/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export interface AsyncSearchResponse { id?: string; diff --git a/src/plugins/data_views/common/data_views/data_view.test.ts b/src/plugins/data_views/common/data_views/data_view.test.ts index 990b8fa4d5f35..ad66beb1daa6a 100644 --- a/src/plugins/data_views/common/data_views/data_view.test.ts +++ b/src/plugins/data_views/common/data_views/data_view.test.ts @@ -10,7 +10,7 @@ import { map, last } from 'lodash'; import { IndexPattern } from './data_view'; -import { DuplicateField } from '../../../kibana_utils/common'; +import { CharacterNotAllowedInField, DuplicateField } from '../../../kibana_utils/common'; import { IndexPatternField } from '../fields'; @@ -207,6 +207,14 @@ describe('IndexPattern', () => { expect(e).toBeInstanceOf(DuplicateField); } }); + + test('should not allow scripted field with * in name', async () => { + try { + await indexPattern.addScriptedField('test*123', "'new script'", 'string'); + } catch (e) { + expect(e).toBeInstanceOf(CharacterNotAllowedInField); + } + }); }); describe('setFieldFormat and deleteFieldFormaat', () => { @@ -267,6 +275,14 @@ describe('IndexPattern', () => { }); expect(indexPattern.toSpec()!.fields!.new_field).toBeUndefined(); }); + + test('should not allow runtime field with * in name', async () => { + try { + await indexPattern.addRuntimeField('test*123', runtime); + } catch (e) { + expect(e).toBeInstanceOf(CharacterNotAllowedInField); + } + }); }); describe('getFormatterForField', () => { diff --git a/src/plugins/data_views/common/data_views/data_view.ts b/src/plugins/data_views/common/data_views/data_view.ts index b7823677b70f9..8d3fcbf7d0ced 100644 --- a/src/plugins/data_views/common/data_views/data_view.ts +++ b/src/plugins/data_views/common/data_views/data_view.ts @@ -10,10 +10,10 @@ import _, { each, reject } from 'lodash'; import { castEsToKbnFieldTypeName, ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FieldAttrs, FieldAttrSet, DataViewAttributes } from '..'; import type { RuntimeField } from '../types'; -import { DuplicateField } from '../../../kibana_utils/common'; +import { CharacterNotAllowedInField, DuplicateField } from '../../../kibana_utils/common'; import { IIndexPattern, IFieldType } from '../../common'; import { DataViewField, IIndexPatternFieldList, fieldList } from '../fields'; @@ -237,6 +237,10 @@ export class DataView implements IIndexPattern { const scriptedFields = this.getScriptedFields(); const names = _.map(scriptedFields, 'name'); + if (name.includes('*')) { + throw new CharacterNotAllowedInField('*', name); + } + if (_.includes(names, name)) { throw new DuplicateField(name); } @@ -358,6 +362,11 @@ export class DataView implements IIndexPattern { */ addRuntimeField(name: string, runtimeField: RuntimeField) { const existingField = this.getFieldByName(name); + + if (name.includes('*')) { + throw new CharacterNotAllowedInField('*', name); + } + if (existingField) { existingField.runtimeField = runtimeField; } else { diff --git a/src/plugins/data_views/common/types.ts b/src/plugins/data_views/common/types.ts index bbc5ad374636f..3a623f89a72e2 100644 --- a/src/plugins/data_views/common/types.ts +++ b/src/plugins/data_views/common/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { DataViewFieldBase, IFieldSubType, DataViewBase } from '@kbn/es-query'; import { ToastInputFields, ErrorToastOptions } from 'src/core/public/notifications'; // eslint-disable-next-line diff --git a/src/plugins/data_views/server/fetcher/lib/field_capabilities/field_caps_response.ts b/src/plugins/data_views/server/fetcher/lib/field_capabilities/field_caps_response.ts index 6dff343f9e00e..75bede61e10d8 100644 --- a/src/plugins/data_views/server/fetcher/lib/field_capabilities/field_caps_response.ts +++ b/src/plugins/data_views/server/fetcher/lib/field_capabilities/field_caps_response.ts @@ -7,7 +7,7 @@ */ import { uniq } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { castEsToKbnFieldTypeName } from '@kbn/field-types'; import { shouldReadFieldFromDocValues } from './should_read_field_from_doc_values'; import { FieldDescriptor } from '../../../fetcher'; @@ -116,7 +116,6 @@ export function readFieldCapsResponse( }), {} ), - // @ts-expect-error metadata_field: capsByType[types[0]].metadata_field, }; // This is intentionally using a "hash" and a "push" to be highly optimized with very large indexes @@ -133,7 +132,6 @@ export function readFieldCapsResponse( searchable: isSearchable, aggregatable: isAggregatable, readFromDocValues: shouldReadFieldFromDocValues(isAggregatable, esType), - // @ts-expect-error metadata_field: capsByType[types[0]].metadata_field, }; // This is intentionally using a "hash" and a "push" to be highly optimized with very large indexes diff --git a/src/plugins/data_views/server/saved_objects/data_views.ts b/src/plugins/data_views/server/saved_objects/data_views.ts index 5bb85a9bb6e98..ca7592732c3ee 100644 --- a/src/plugins/data_views/server/saved_objects/data_views.ts +++ b/src/plugins/data_views/server/saved_objects/data_views.ts @@ -13,7 +13,8 @@ import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../../common'; export const dataViewSavedObjectType: SavedObjectsType = { name: DATA_VIEW_SAVED_OBJECT_TYPE, hidden: false, - namespaceType: 'single', + namespaceType: 'multiple-isolated', + convertToMultiNamespaceTypeVersion: '8.0.0', management: { displayName: 'Data view', icon: 'indexPatternApp', diff --git a/src/plugins/discover/public/application/apps/main/components/doc_table/components/_table_header.scss b/src/plugins/discover/public/application/apps/main/components/doc_table/components/_table_header.scss index 3450084e19269..3ea6fb5502764 100644 --- a/src/plugins/discover/public/application/apps/main/components/doc_table/components/_table_header.scss +++ b/src/plugins/discover/public/application/apps/main/components/doc_table/components/_table_header.scss @@ -1,7 +1,8 @@ .kbnDocTableHeader { white-space: nowrap; } -.kbnDocTableHeader button { +.kbnDocTableHeader button, +.kbnDocTableHeader svg { margin-left: $euiSizeXS * .5; } .kbnDocTableHeader__move, diff --git a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap index 18b0ae8699e3e..3f72349f3e2a0 100644 --- a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap +++ b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap @@ -15,7 +15,16 @@ exports[`TableHeader with time column renders correctly 1`] = ` class="kbnDocTableHeader__actions" data-test-subj="docTableHeader-time" > - Time + time + + + diff --git a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx index d313e95c1ebb1..f04454d33e9f2 100644 --- a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx +++ b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/helpers.tsx @@ -28,7 +28,7 @@ export interface ColumnProps { export function getTimeColumn(timeFieldName: string): ColumnProps { return { name: timeFieldName, - displayName: 'Time', + displayName: timeFieldName, isSortable: true, isRemoveable: false, colLeftIdx: -1, diff --git a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/table_header.tsx index f891e809ee702..1877c014ddcbd 100644 --- a/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/table_header.tsx +++ b/src/plugins/discover/public/application/apps/main/components/doc_table/components/table_header/table_header.tsx @@ -45,6 +45,8 @@ export function TableHeader({ void; onMoveColumn?: (name: string, idx: number) => void; @@ -54,6 +56,8 @@ export function TableHeaderColumn({ displayName, isRemoveable, isSortable, + isTimeColumn, + customLabel, name, onChangeSortOrder, onMoveColumn, @@ -65,6 +69,14 @@ export function TableHeaderColumn({ const curColSort = sortOrder.find((pair) => pair[0] === name); const curColSortDir = (curColSort && curColSort[1]) || ''; + const timeAriaLabel = i18n.translate( + 'discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel', + { defaultMessage: 'Primary time field.' } + ); + const timeTooltip = i18n.translate('discover.docTable.tableHeader.timeFieldIconTooltip', { + defaultMessage: 'This field represents the time that events occurred.', + }); + // If this is the _score column, and _score is not one of the columns inside the sort, show a // warning that the _score will not be retrieved from Elasticsearch const showScoreSortWarning = name === '_score' && !curColSort; @@ -183,7 +195,15 @@ export function TableHeaderColumn({ {showScoreSortWarning && } - {displayName} + {customLabel ?? displayName} + {isTimeColumn && ( + + )} {buttons .filter((button) => button.active) .map((button, idx) => ( diff --git a/src/plugins/discover/public/application/apps/main/components/doc_table/lib/row_formatter.tsx b/src/plugins/discover/public/application/apps/main/components/doc_table/lib/row_formatter.tsx index 2702a232f21ef..a73bc3f175be1 100644 --- a/src/plugins/discover/public/application/apps/main/components/doc_table/lib/row_formatter.tsx +++ b/src/plugins/discover/public/application/apps/main/components/doc_table/lib/row_formatter.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import React, { Fragment } from 'react'; import type { IndexPattern } from 'src/plugins/data/common'; import { MAX_DOC_FIELDS_DISPLAYED } from '../../../../../../../common'; diff --git a/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts b/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts index 9968ca6f1f63f..7f875be0a42c5 100644 --- a/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts +++ b/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts @@ -183,7 +183,7 @@ describe('createSearchSessionRestorationDataProvider', () => { (mockDataPlugin.search.session.getSessionId as jest.Mock).mockImplementation( () => searchSessionId ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.searchSessionId).toBeUndefined(); expect(restoreState.searchSessionId).toBe(searchSessionId); }); @@ -197,15 +197,20 @@ describe('createSearchSessionRestorationDataProvider', () => { (mockDataPlugin.query.timefilter.timefilter.getAbsoluteTime as jest.Mock).mockImplementation( () => absoluteTime ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.timeRange).toBe(relativeTime); expect(restoreState.timeRange).toBe(absoluteTime); }); test('restoreState has paused autoRefresh', async () => { - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.refreshInterval).toBe(undefined); - expect(restoreState.refreshInterval?.pause).toBe(true); + expect(restoreState.refreshInterval).toMatchInlineSnapshot(` + Object { + "pause": true, + "value": 0, + } + `); }); }); }); diff --git a/src/plugins/discover/public/application/apps/main/services/discover_state.ts b/src/plugins/discover/public/application/apps/main/services/discover_state.ts index 9a61fdc996e3b..388d4f19d1c27 100644 --- a/src/plugins/discover/public/application/apps/main/services/discover_state.ts +++ b/src/plugins/discover/public/application/apps/main/services/discover_state.ts @@ -32,9 +32,9 @@ import { } from '../../../../../../data/public'; import { migrateLegacyQuery } from '../../../helpers/migrate_legacy_query'; import { DiscoverGridSettings } from '../../../components/discover_grid/types'; -import { DISCOVER_APP_URL_GENERATOR, DiscoverUrlGeneratorState } from '../../../../url_generator'; import { SavedSearch } from '../../../../saved_searches'; import { handleSourceColumnState } from '../../../helpers/state_helpers'; +import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '../../../../locator'; import { VIEW_MODE } from '../components/view_mode_toggle'; export interface AppState { @@ -361,9 +361,9 @@ export function createSearchSessionRestorationDataProvider(deps: { }) ); }, - getUrlGeneratorData: async () => { + getLocatorData: async () => { return { - urlGeneratorId: DISCOVER_APP_URL_GENERATOR, + id: DISCOVER_APP_LOCATOR, initialState: createUrlGeneratorState({ ...deps, getSavedSearchId, @@ -389,7 +389,7 @@ function createUrlGeneratorState({ data: DataPublicPluginStart; getSavedSearchId: () => string | undefined; shouldRestoreSearchSession: boolean; -}): DiscoverUrlGeneratorState { +}): DiscoverAppLocatorParams { const appState = appStateContainer.get(); return { filters: data.query.filterManager.getFilters(), diff --git a/src/plugins/discover/public/application/apps/main/utils/fetch_chart.test.ts b/src/plugins/discover/public/application/apps/main/utils/fetch_chart.test.ts index 2c050a9391a86..2c9350b457779 100644 --- a/src/plugins/discover/public/application/apps/main/utils/fetch_chart.test.ts +++ b/src/plugins/discover/public/application/apps/main/utils/fetch_chart.test.ts @@ -14,7 +14,7 @@ import { ReduxLikeStateContainer } from '../../../../../../kibana_utils/common'; import { AppState } from '../services/discover_state'; import { discoverServiceMock } from '../../../../__mocks__/services'; import { calculateBounds, IKibanaSearchResponse } from '../../../../../../data/common'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; function getDataSubjects() { return { diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.test.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.test.tsx index 46e30dd23525b..e5ea657032403 100644 --- a/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.test.tsx +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.test.tsx @@ -117,7 +117,15 @@ describe('Discover grid columns ', function () { [Function], [Function], ], - "display": "Time (timestamp)", + "display": + timestamp + + + , "id": "timestamp", "initialWidth": 190, "isSortable": true, diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx index 2f4c0b5167df8..5eb55a8e99cde 100644 --- a/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiDataGridColumn, EuiScreenReaderOnly } from '@elastic/eui'; +import { EuiDataGridColumn, EuiIconTip, EuiScreenReaderOnly } from '@elastic/eui'; import { ExpandButton } from './discover_grid_expand_button'; import { DiscoverGridSettings } from './types'; import type { IndexPattern } from '../../../../../data/common'; @@ -57,9 +57,6 @@ export function buildEuiGridColumn( defaultColumns: boolean, isSortEnabled: boolean ) { - const timeString = i18n.translate('discover.timeLabel', { - defaultMessage: 'Time', - }); const indexPatternField = indexPattern.getFieldByName(columnName); const column: EuiDataGridColumn = { id: columnName, @@ -88,7 +85,23 @@ export function buildEuiGridColumn( }; if (column.id === indexPattern.timeFieldName) { - column.display = `${timeString} (${indexPattern.timeFieldName})`; + const primaryTimeAriaLabel = i18n.translate( + 'discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel', + { defaultMessage: 'Primary time field.' } + ); + const primaryTimeTooltip = i18n.translate( + 'discover.docTable.tableHeader.timeFieldIconTooltip', + { + defaultMessage: 'This field represents the time that events occurred.', + } + ); + + column.display = ( + + {indexPatternField?.customLabel ?? indexPattern.timeFieldName}{' '} + + + ); column.initialWidth = defaultTimeColumnWidth; } if (columnWidth > 0) { diff --git a/src/plugins/discover/public/application/doc_views/doc_views_types.ts b/src/plugins/discover/public/application/doc_views/doc_views_types.ts index d3e482c0f2e1d..e8faa51bbab40 100644 --- a/src/plugins/discover/public/application/doc_views/doc_views_types.ts +++ b/src/plugins/discover/public/application/doc_views/doc_views_types.ts @@ -8,7 +8,7 @@ import { ComponentType } from 'react'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IndexPattern } from '../../../../data/public'; export type ElasticSearchHit = estypes.SearchHit; diff --git a/src/plugins/discover/public/application/helpers/format_hit.test.ts b/src/plugins/discover/public/application/helpers/format_hit.test.ts index 2cb46f28dd397..ebf5078238ccf 100644 --- a/src/plugins/discover/public/application/helpers/format_hit.test.ts +++ b/src/plugins/discover/public/application/helpers/format_hit.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { indexPatternMock as dataViewMock } from '../../__mocks__/index_pattern'; import { formatHit } from './format_hit'; import { discoverServiceMock } from '../../__mocks__/services'; diff --git a/src/plugins/discover/public/application/helpers/format_hit.ts b/src/plugins/discover/public/application/helpers/format_hit.ts index 3890973a3f3e4..1101439515523 100644 --- a/src/plugins/discover/public/application/helpers/format_hit.ts +++ b/src/plugins/discover/public/application/helpers/format_hit.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataView, flattenHit } from '../../../../data/common'; import { MAX_DOC_FIELDS_DISPLAYED } from '../../../common'; import { getServices } from '../../kibana_services'; diff --git a/src/plugins/discover/public/application/helpers/format_value.ts b/src/plugins/discover/public/application/helpers/format_value.ts index cc33276790372..933309d6dcf8e 100644 --- a/src/plugins/discover/public/application/helpers/format_value.ts +++ b/src/plugins/discover/public/application/helpers/format_value.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataView, DataViewField, KBN_FIELD_TYPES } from '../../../../data/common'; import { getServices } from '../../kibana_services'; diff --git a/src/plugins/discover/public/application/helpers/get_ignored_reason.ts b/src/plugins/discover/public/application/helpers/get_ignored_reason.ts index 4d2fb85bdb2c4..bf8df6e000d4c 100644 --- a/src/plugins/discover/public/application/helpers/get_ignored_reason.ts +++ b/src/plugins/discover/public/application/helpers/get_ignored_reason.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataViewField, KBN_FIELD_TYPES } from '../../../../data/common'; export enum IgnoredReason { diff --git a/src/plugins/discover/public/application/services/use_es_doc_search.ts b/src/plugins/discover/public/application/services/use_es_doc_search.ts index 16a24ff27292b..fa7dce9c7e0a4 100644 --- a/src/plugins/discover/public/application/services/use_es_doc_search.ts +++ b/src/plugins/discover/public/application/services/use_es_doc_search.ts @@ -7,7 +7,7 @@ */ import { useCallback, useEffect, useMemo, useState } from 'react'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IndexPattern } from '../../../../data/common'; import { DocProps } from '../apps/doc/components/doc'; import { ElasticRequestState } from '../apps/doc/types'; diff --git a/src/plugins/discover/public/application/types.ts b/src/plugins/discover/public/application/types.ts index a28c5bbc89aed..f04f3bf77c2f9 100644 --- a/src/plugins/discover/public/application/types.ts +++ b/src/plugins/discover/public/application/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export enum FetchStatus { UNINITIALIZED = 'uninitialized', diff --git a/src/plugins/discover/public/locator.ts b/src/plugins/discover/public/locator.ts index bc632c7e1ccb7..40b62841f19d1 100644 --- a/src/plugins/discover/public/locator.ts +++ b/src/plugins/discover/public/locator.ts @@ -69,7 +69,7 @@ export interface DiscoverAppLocatorParams extends SerializableRecord { /** * Array of the used sorting [[field,direction],...] */ - sort?: string[][] & SerializableRecord; + sort?: string[][]; /** * id of the used saved query diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts index 678c46f69d51f..07a681f002f33 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts @@ -6,13 +6,12 @@ * Side Public License, v 1. */ -import { ApiError } from '@elastic/elasticsearch'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { IKibanaResponse, KibanaResponseFactory } from 'kibana/server'; import { getEsCause } from './es_error_parser'; interface EsErrorHandlerParams { - error: ApiError; + error: errors.ElasticsearchClientError; response: KibanaResponseFactory; handleCustomError?: () => IKibanaResponse; } @@ -34,9 +33,9 @@ export const handleEsError = ({ return handleCustomError(); } - const { statusCode, body } = error as ResponseError; + const { statusCode, body } = error as errors.ResponseError; return response.customError({ - statusCode, + statusCode: statusCode!, body: { message: // We use || instead of ?? as the switch here because reason could be an empty string diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index a1a93e3eba542..36b301823f136 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -9,7 +9,7 @@ import _ from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; -import { EuiFlexItem, EuiFlexGrid, EuiFlexGroup } from '@elastic/eui'; +import { EuiFlexItem, EuiFlexGrid, EuiFlexGroup, EuiLink } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { Synopsis } from './synopsis'; @@ -224,7 +224,17 @@ class TutorialDirectoryUi extends React.Component { description: ( + + + ), + }} /> ), tabs, diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts index 1f0ce6186bb8a..9559aa6b930a3 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts @@ -138,55 +138,26 @@ export const getSavedObjects = (): SavedObject[] => [ version: 'WzIzLDFd', }, { + id: '9c6f83f0-bb4d-11e8-9c84-77068524bcab', + type: 'visualization', + updated_at: '2018-10-01T15:13:03.270Z', + version: '1', + migrationVersion: {}, attributes: { + title: i18n.translate('home.sampleData.ecommerceSpec.salesCountMapTitle', { + defaultMessage: '[eCommerce] Sales Count Map', + }), + visState: + '{"title":"[eCommerce] Sales Count Map","type":"vega","aggs":[],"params":{"spec":"{\\n $schema: https://vega.github.io/schema/vega/v5.json\\n config: {\\n kibana: {type: \\"map\\", latitude: 25, longitude: -40, zoom: 3}\\n }\\n data: [\\n {\\n name: table\\n url: {\\n index: kibana_sample_data_ecommerce\\n %context%: true\\n %timefield%: order_date\\n body: {\\n size: 0\\n aggs: {\\n gridSplit: {\\n geotile_grid: {field: \\"geoip.location\\", precision: 4, size: 10000}\\n aggs: {\\n gridCentroid: {\\n geo_centroid: {\\n field: \\"geoip.location\\"\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n format: {property: \\"aggregations.gridSplit.buckets\\"}\\n transform: [\\n {\\n type: geopoint\\n projection: projection\\n fields: [\\n gridCentroid.location.lon\\n gridCentroid.location.lat\\n ]\\n }\\n ]\\n }\\n ]\\n scales: [\\n {\\n name: gridSize\\n type: linear\\n domain: {data: \\"table\\", field: \\"doc_count\\"}\\n range: [\\n 50\\n 1000\\n ]\\n }\\n ]\\n marks: [\\n {\\n name: gridMarker\\n type: symbol\\n from: {data: \\"table\\"}\\n encode: {\\n update: {\\n size: {scale: \\"gridSize\\", field: \\"doc_count\\"}\\n xc: {signal: \\"datum.x\\"}\\n yc: {signal: \\"datum.y\\"}\\n }\\n }\\n },\\n {\\n name: gridLabel\\n type: text\\n from: {data: \\"table\\"}\\n encode: {\\n enter: {\\n fill: {value: \\"firebrick\\"}\\n text: {signal: \\"datum.doc_count\\"}\\n }\\n update: {\\n x: {signal: \\"datum.x\\"}\\n y: {signal: \\"datum.y\\"}\\n dx: {value: -6}\\n dy: {value: 6}\\n fontSize: {value: 18}\\n fontWeight: {value: \\"bold\\"}\\n }\\n }\\n }\\n ]\\n}"}}', + uiStateJSON: '{}', description: '', - layerListJSON: - '[{"id":"0hmz5","alpha":1,"sourceDescriptor":{"type":"EMS_TMS","isAutoSelect":true},"visible":true,"style":{},"type":"VECTOR_TILE","minZoom":0,"maxZoom":24},{"id":"7ameq","label":null,"minZoom":0,"maxZoom":24,"alpha":1,"sourceDescriptor":{"type":"EMS_FILE","id":"world_countries","tooltipProperties":["name","iso2"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__741db9c6-8ebb-4ea9-9885-b6b4ac019d14","origin":"join"},"color":"Green to Red","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR","joins":[{"leftField":"iso2","right":{"type":"ES_TERM_SOURCE","id":"741db9c6-8ebb-4ea9-9885-b6b4ac019d14","indexPatternTitle":"kibana_sample_data_ecommerce","term":"geoip.country_iso_code","indexPatternRefName":"layer_1_join_0_index_pattern","metrics":[{"type":"count","label":"sales count"}],"applyGlobalQuery":true}}]},{"id":"jmtgf","label":"United States","minZoom":0,"maxZoom":24,"alpha":1,"sourceDescriptor":{"type":"EMS_FILE","id":"usa_states","tooltipProperties":["name"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__30a0ec24-49b6-476a-b4ed-6c1636333695","origin":"join"},"color":"Blues","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR","joins":[{"leftField":"name","right":{"type":"ES_TERM_SOURCE","id":"30a0ec24-49b6-476a-b4ed-6c1636333695","indexPatternTitle":"kibana_sample_data_ecommerce","term":"geoip.region_name","indexPatternRefName":"layer_2_join_0_index_pattern","metrics":[{"type":"count","label":"sales count"}],"applyGlobalQuery":true}}]},{"id":"ui5f8","label":"France","minZoom":0,"maxZoom":24,"alpha":1,"sourceDescriptor":{"type":"EMS_FILE","id":"france_departments","tooltipProperties":["label_en"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__e325c9da-73fa-4b3b-8b59-364b99370826","origin":"join"},"color":"Blues","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR","joins":[{"leftField":"label_en","right":{"type":"ES_TERM_SOURCE","id":"e325c9da-73fa-4b3b-8b59-364b99370826","indexPatternTitle":"kibana_sample_data_ecommerce","term":"geoip.region_name","indexPatternRefName":"layer_3_join_0_index_pattern","metrics":[{"type":"count","label":"sales count"}],"applyGlobalQuery":true}}]},{"id":"y3fjb","label":"United Kingdom","minZoom":0,"maxZoom":24,"alpha":1,"sourceDescriptor":{"type":"EMS_FILE","id":"uk_subdivisions","tooltipProperties":["label_en"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__612d805d-8533-43a9-ac0e-cbf51fe63dcd","origin":"join"},"color":"Blues","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR","joins":[{"leftField":"label_en","right":{"type":"ES_TERM_SOURCE","id":"612d805d-8533-43a9-ac0e-cbf51fe63dcd","indexPatternTitle":"kibana_sample_data_ecommerce","term":"geoip.region_name","indexPatternRefName":"layer_4_join_0_index_pattern","metrics":[{"type":"count","label":"sales count"}],"applyGlobalQuery":true}}]},{"id":"c54wk","label":"Sales","minZoom":9,"maxZoom":24,"alpha":1,"sourceDescriptor":{"id":"04c983b0-8cfa-4e6a-a64b-52c10b7008fe","type":"ES_SEARCH","geoField":"geoip.location","limit":2048,"filterByMapBounds":true,"tooltipProperties":["category","customer_gender","manufacturer","order_id","total_quantity","total_unique_products","taxful_total_price","order_date","geoip.region_name","geoip.country_iso_code"],"indexPatternRefName":"layer_5_source_index_pattern","applyGlobalQuery":true,"scalingType":"LIMIT"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"taxful_total_price","origin":"source"},"color":"Greens","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR"},{"id":"qvhh3","label":"Total Sales Revenue","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"aa7f87b8-9dc5-42be-b19e-1a2fa09b6cad","geoField":"geoip.location","requestType":"point","metrics":[{"type":"count","label":"sales count"},{"type":"sum","field":"taxful_total_price","label":"total sales price"}],"indexPatternRefName":"layer_6_source_index_pattern","applyGlobalQuery":true},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"color":"Greens","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#cccccc"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"name":"sum_of_taxful_total_price","origin":"source"},"minSize":1,"maxSize":20,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelText":{"type":"DYNAMIC","options":{"field":{"name":"sum_of_taxful_total_price","origin":"source"},"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelSize":{"type":"DYNAMIC","options":{"field":{"name":"sum_of_taxful_total_price","origin":"source"},"minSize":12,"maxSize":24,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelBorderSize":{"options":{"size":"MEDIUM"}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"VECTOR"}]', - mapStateJSON: - '{"zoom":2.11,"center":{"lon":-15.07605,"lat":45.88578},"timeFilters":{"from":"now-7d","to":"now"},"refreshConfig":{"isPaused":true,"interval":0},"query":{"query":"","language":"kuery"},"settings":{"autoFitToDataBounds":false}}', - title: '[eCommerce] Orders by Country', - uiStateJSON: '{"isDarkMode":false}', - }, - coreMigrationVersion: '8.0.0', - id: '2c9c1f60-1909-11e9-919b-ffe5949a18d2', - migrationVersion: { - map: '7.14.0', - }, - references: [ - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_1_join_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_2_join_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_3_join_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_4_join_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_5_source_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'layer_6_source_index_pattern', - type: 'index-pattern', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"index":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","query":{"query":"","language":"kuery"},"filter":[]}', }, - ], - type: 'map', - updated_at: '2021-08-05T12:23:57.577Z', - version: 'WzI5LDFd', + }, + references: [], }, { attributes: { @@ -1351,9 +1322,9 @@ export const getSavedObjects = (): SavedObject[] => [ type: 'search', }, { - id: '2c9c1f60-1909-11e9-919b-ffe5949a18d2', + id: '9c6f83f0-bb4d-11e8-9c84-77068524bcab', name: '11:panel_11', - type: 'map', + type: 'visualization', }, { id: 'c00d1f90-f5ea-11eb-a78e-83aac3c38a60', diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.ts index b88f42ca970af..ef453592d9790 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.ts @@ -61,7 +61,8 @@ export class SampleDataRegistry { customIntegrations?: CustomIntegrationsPluginSetup ) { if (usageCollections) { - makeSampleDataUsageCollector(usageCollections, this.initContext); + const kibanaIndex = core.savedObjects.getKibanaIndex(); + makeSampleDataUsageCollector(usageCollections, kibanaIndex); } const usageTracker = usage( core.getStartServices().then(([coreStart]) => coreStart.savedObjects), diff --git a/src/plugins/home/server/services/sample_data/usage/collector.ts b/src/plugins/home/server/services/sample_data/usage/collector.ts index df7d485c1f6fa..06c0c9239942b 100644 --- a/src/plugins/home/server/services/sample_data/usage/collector.ts +++ b/src/plugins/home/server/services/sample_data/usage/collector.ts @@ -6,20 +6,16 @@ * Side Public License, v 1. */ -import type { PluginInitializerContext } from 'kibana/server'; import type { UsageCollectionSetup } from '../../../../../usage_collection/server'; import { fetchProvider, TelemetryResponse } from './collector_fetch'; export function makeSampleDataUsageCollector( usageCollection: UsageCollectionSetup, - context: PluginInitializerContext + kibanaIndex: string ) { - const config = context.config.legacy.get(); - const index = config.kibana.index; - const collector = usageCollection.makeUsageCollector({ type: 'sample-data', - fetch: fetchProvider(index), + fetch: fetchProvider(kibanaIndex), isReady: () => true, schema: { installed: { type: 'array', items: { type: 'keyword' } }, diff --git a/src/plugins/index_pattern_field_editor/public/components/field_editor/form_schema.ts b/src/plugins/index_pattern_field_editor/public/components/field_editor/form_schema.ts index a722f277b8e23..979a1fdb1adc1 100644 --- a/src/plugins/index_pattern_field_editor/public/components/field_editor/form_schema.ts +++ b/src/plugins/index_pattern_field_editor/public/components/field_editor/form_schema.ts @@ -11,7 +11,7 @@ import { fieldValidators } from '../../shared_imports'; import { RUNTIME_FIELD_OPTIONS } from './constants'; -const { emptyField, numberGreaterThanField } = fieldValidators; +const { containsCharsField, emptyField, numberGreaterThanField } = fieldValidators; export const schema = { name: { @@ -29,6 +29,17 @@ export const schema = { ) ), }, + { + validator: containsCharsField({ + message: i18n.translate( + 'indexPatternFieldEditor.editor.form.validations.starCharacterNotAllowedValidationErrorMessage', + { + defaultMessage: 'The field cannot have * in the name.', + } + ), + chars: '*', + }), + }, ], }, type: { diff --git a/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts b/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts index 847dd41e0082b..9ffa5c88df8e8 100644 --- a/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts +++ b/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { API_BASE_PATH } from '../../common/constants'; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/types.ts b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/types.ts index 45a59b97b9490..e2657d7111ea6 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/types.ts +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /** @internal **/ export interface ScriptedFieldItem { name: string; diff --git a/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap b/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap index 87aa20c4617c1..460c6c99786bf 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap @@ -546,7 +546,7 @@ exports[`FieldEditor should show conflict field warning 1`] = ` onClose={[Function]} /> { component.update(); expect(component).toMatchSnapshot(); }); + + it('should not allow field to have * in the name', async () => { + const testField = { + ...field, + name: 'test-field', + }; + const component = createComponentWithContext( + FieldEditor, + { + indexPattern, + spec: testField as unknown as IndexPatternField, + services, + }, + mockContext + ); + + await new Promise((resolve) => process.nextTick(resolve)); + (component.instance() as FieldEditor).onFieldChange('name', 'test*123'); + component.update(); + expect(component.html().includes('The field cannot have * in the name.')).toBe(true); + }); }); diff --git a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx index 9509f4fb46e0b..1c66f37dad141 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx +++ b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import React, { PureComponent, Fragment } from 'react'; import { intersection, union, get } from 'lodash'; @@ -267,7 +267,8 @@ export class FieldEditor extends PureComponent = ({ onSuccess }) => { const [page, setPage] = useState<'token' | 'manual' | 'success'>('token'); const [cluster, setCluster] = useState>(); + const { http } = useKibana(); + const state = useAsync( + () => http.get('/internal/interactive_setup/status'), + [http] + ); + + if (state.loading) { + return null; + } + + if (!state.value || state.value.connectionStatus === 'configured' || !state.value.isSetupOnHold) { + return ( +

+        
+      
+ ); + } return (
diff --git a/src/plugins/interactive_setup/public/enrollment_token_form.test.tsx b/src/plugins/interactive_setup/public/enrollment_token_form.test.tsx index a6a18984ddd94..30983c68e1cf9 100644 --- a/src/plugins/interactive_setup/public/enrollment_token_form.test.tsx +++ b/src/plugins/interactive_setup/public/enrollment_token_form.test.tsx @@ -89,6 +89,20 @@ describe('decodeEnrollmentToken', () => { }); }); + it('should sort IPv4 before IPv6 addresses', () => { + expect( + decodeEnrollmentToken( + btoa( + JSON.stringify({ ...token, adr: ['[::1]:9200', '127.0.0.1:9200', '10.17.1.163:9200'] }) + ) + ) + ).toEqual( + expect.objectContaining({ + adr: ['https://127.0.0.1:9200', 'https://10.17.1.163:9200', 'https://[::1]:9200'], + }) + ); + }); + it('should not decode an invalid token', () => { expect(decodeEnrollmentToken(JSON.stringify(token))).toBeUndefined(); expect( diff --git a/src/plugins/interactive_setup/public/enrollment_token_form.tsx b/src/plugins/interactive_setup/public/enrollment_token_form.tsx index 4b692ed4efcc8..e5a3aca8fd4e2 100644 --- a/src/plugins/interactive_setup/public/enrollment_token_form.tsx +++ b/src/plugins/interactive_setup/public/enrollment_token_form.tsx @@ -205,6 +205,7 @@ export function decodeEnrollmentToken(enrollmentToken: string): EnrollmentToken ) { return; } + json.adr.sort(compareAddresses); return { ...json, adr: json.adr.map((host) => `https://${host}`), @@ -212,3 +213,16 @@ export function decodeEnrollmentToken(enrollmentToken: string): EnrollmentToken }; } catch (error) {} // eslint-disable-line no-empty } + +/** + * Compares two Elasticsearch addresses. Sorts IPv4 addresses before IPv6 addresses. + */ +export function compareAddresses(a: string, b: string) { + if (a.indexOf('[') === -1 && b.indexOf('[') !== -1) { + return -1; + } + if (a.indexOf('[') !== -1 && b.indexOf('[') === -1) { + return 1; + } + return 0; +} diff --git a/src/plugins/interactive_setup/public/progress_indicator.tsx b/src/plugins/interactive_setup/public/progress_indicator.tsx index 44362554609c3..73f757246af53 100644 --- a/src/plugins/interactive_setup/public/progress_indicator.tsx +++ b/src/plugins/interactive_setup/public/progress_indicator.tsx @@ -16,31 +16,48 @@ import useTimeoutFn from 'react-use/lib/useTimeoutFn'; import { i18n } from '@kbn/i18n'; import type { IHttpFetchError } from 'kibana/public'; +import type { StatusResponse } from '../../../core/types/status'; import { useKibana } from './use_kibana'; export interface ProgressIndicatorProps { onSuccess?(): void; } +function isKibanaPastPreboot(response?: Response, body?: StatusResponse) { + if (!response?.headers.get('content-type')?.includes('application/json')) { + return false; + } + + return ( + // Status endpoint may require authentication after `preboot` stage. + response?.status === 401 || + // We're only interested in the availability of the critical core services. + (body?.status?.core?.elasticsearch?.level === 'available' && + body?.status?.core?.savedObjects?.level === 'available') + ); +} + export const ProgressIndicator: FunctionComponent = ({ onSuccess }) => { const { http } = useKibana(); const [status, checkStatus] = useAsyncFn(async () => { let isAvailable: boolean | undefined = false; let isPastPreboot: boolean | undefined = false; try { - const { response } = await http.get('/api/status', { asResponse: true }); + const { response, body } = await http.get('/api/status', { + asResponse: true, + }); isAvailable = response ? response.status < 500 : undefined; - isPastPreboot = response?.headers.get('content-type')?.includes('application/json'); + isPastPreboot = isKibanaPastPreboot(response, body); } catch (error) { - const { response } = error as IHttpFetchError; + const { response, body = {} } = error as IHttpFetchError; isAvailable = response ? response.status < 500 : undefined; - isPastPreboot = response?.headers.get('content-type')?.includes('application/json'); + isPastPreboot = isKibanaPastPreboot(response, body); } - return isAvailable === true && isPastPreboot === true + return isAvailable === true && isPastPreboot ? 'complete' : isAvailable === false ? 'unavailable' - : isAvailable === true && isPastPreboot === false + : isAvailable === true && !isPastPreboot ? 'preboot' : 'unknown'; }); diff --git a/src/plugins/interactive_setup/server/config.test.ts b/src/plugins/interactive_setup/server/config.test.ts index b8ae673ad28f9..50e47735ad3c8 100644 --- a/src/plugins/interactive_setup/server/config.test.ts +++ b/src/plugins/interactive_setup/server/config.test.ts @@ -15,7 +15,7 @@ describe('config schema', () => { "connectionCheck": Object { "interval": "PT5S", }, - "enabled": false, + "enabled": true, } `); }); @@ -27,7 +27,7 @@ describe('config schema', () => { "connectionCheck": Object { "interval": "PT1S", }, - "enabled": false, + "enabled": true, } `); }); diff --git a/src/plugins/interactive_setup/server/config.ts b/src/plugins/interactive_setup/server/config.ts index 9986f16e9ce93..1b1a9525e3527 100644 --- a/src/plugins/interactive_setup/server/config.ts +++ b/src/plugins/interactive_setup/server/config.ts @@ -12,7 +12,7 @@ import { schema } from '@kbn/config-schema'; export type ConfigType = TypeOf; export const ConfigSchema = schema.object({ - enabled: schema.boolean({ defaultValue: false }), + enabled: schema.boolean({ defaultValue: true }), connectionCheck: schema.object({ interval: schema.duration({ defaultValue: '5s', diff --git a/src/plugins/interactive_setup/server/elasticsearch_service.test.ts b/src/plugins/interactive_setup/server/elasticsearch_service.test.ts index 9baed65db299d..93870578d8cc4 100644 --- a/src/plugins/interactive_setup/server/elasticsearch_service.test.ts +++ b/src/plugins/interactive_setup/server/elasticsearch_service.test.ts @@ -289,7 +289,8 @@ describe('ElasticsearchService', () => { it('treats product check error the same as successful response', async () => { mockConnectionStatusClient.asInternalUser.ping.mockRejectedValue( - new errors.ProductNotSupportedError(interactiveSetupMock.createApiResponse({ body: {} })) + // @ts-expect-error not full interface + new errors.ProductNotSupportedError('product-name', { body: {} }) ); const mockHandler = jest.fn(); @@ -538,7 +539,8 @@ some weird+ca/with it('fails if host is not supported', async () => { mockPingClient.asInternalUser.ping.mockRejectedValue( - new errors.ProductNotSupportedError(interactiveSetupMock.createApiResponse({ body: {} })) + // @ts-expect-error not full interface + new errors.ProductNotSupportedError('Elasticsearch', { body: {} }) ); await expect(setupContract.ping('http://localhost:9200')).rejects.toMatchInlineSnapshot( diff --git a/src/plugins/interactive_setup/server/elasticsearch_service.ts b/src/plugins/interactive_setup/server/elasticsearch_service.ts index b3b25b13c5a9b..5d41f16b01add 100644 --- a/src/plugins/interactive_setup/server/elasticsearch_service.ts +++ b/src/plugins/interactive_setup/server/elasticsearch_service.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import type { ApiResponse } from '@elastic/elasticsearch'; import { errors } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import type { Duration } from 'moment'; import type { Observable } from 'rxjs'; import { from, of, timer } from 'rxjs'; @@ -193,7 +193,7 @@ export class ElasticsearchService { .asCurrentUser.transport.request({ method: 'GET', path: '/_security/enroll/kibana', - })) as ApiResponse<{ token: { name: string; value: string }; http_ca: string }>; + })) as TransportResult<{ token: { name: string; value: string }; http_ca: string }>; } catch (err) { // We expect that all hosts belong to exactly same node and any non-connection error for one host would mean // that enrollment will fail for any other host and we should bail out. diff --git a/src/plugins/interactive_setup/server/errors.ts b/src/plugins/interactive_setup/server/errors.ts index 5f1d2388b3938..89962e06e0e61 100644 --- a/src/plugins/interactive_setup/server/errors.ts +++ b/src/plugins/interactive_setup/server/errors.ts @@ -14,7 +14,7 @@ import { errors } from '@elastic/elasticsearch'; */ export function getErrorStatusCode(error: any): number { if (error instanceof errors.ResponseError) { - return error.statusCode; + return error.statusCode!; } return error.statusCode || error.status; diff --git a/src/plugins/interactive_setup/server/kibana_config_writer.test.ts b/src/plugins/interactive_setup/server/kibana_config_writer.test.ts index 4b68451930a3d..005e280fcc744 100644 --- a/src/plugins/interactive_setup/server/kibana_config_writer.test.ts +++ b/src/plugins/interactive_setup/server/kibana_config_writer.test.ts @@ -30,6 +30,7 @@ describe('KibanaConfigWriter', () => { kibanaConfigWriter = new KibanaConfigWriter( '/some/path/kibana.yml', + '/data', loggingSystemMock.createLogger() ); }); @@ -37,15 +38,15 @@ describe('KibanaConfigWriter', () => { afterEach(() => jest.resetAllMocks()); describe('#isConfigWritable()', () => { - it('returns `false` if config directory is not writable even if kibana yml is writable', async () => { + it('returns `false` if data directory is not writable even if kibana yml is writable', async () => { mockFsAccess.mockImplementation((path, modifier) => - path === '/some/path' && modifier === constants.W_OK ? Promise.reject() : Promise.resolve() + path === '/data' && modifier === constants.W_OK ? Promise.reject() : Promise.resolve() ); await expect(kibanaConfigWriter.isConfigWritable()).resolves.toBe(false); }); - it('returns `false` if kibana yml is NOT writable if even config directory is writable', async () => { + it('returns `false` if kibana yml is NOT writable if even data directory is writable', async () => { mockFsAccess.mockImplementation((path, modifier) => path === '/some/path/kibana.yml' && modifier === constants.W_OK ? Promise.reject() @@ -55,219 +56,208 @@ describe('KibanaConfigWriter', () => { await expect(kibanaConfigWriter.isConfigWritable()).resolves.toBe(false); }); - it('returns `true` if both kibana yml and config directory are writable', async () => { + it('returns `true` if both kibana yml and data directory are writable', async () => { mockFsAccess.mockResolvedValue(undefined); await expect(kibanaConfigWriter.isConfigWritable()).resolves.toBe(true); }); - it('returns `true` even if kibana yml does not exist when config directory is writable', async () => { + it('returns `true` even if kibana yml does not exist even if data directory is writable', async () => { mockFsAccess.mockImplementation((path) => path === '/some/path/kibana.yml' ? Promise.reject() : Promise.resolve() ); - await expect(kibanaConfigWriter.isConfigWritable()).resolves.toBe(true); + await expect(kibanaConfigWriter.isConfigWritable()).resolves.toBe(false); }); }); describe('#writeConfig()', () => { - describe('without existing config', () => { - beforeEach(() => { - mockReadFile.mockResolvedValue(''); - }); - - it('throws if cannot write CA file', async () => { - mockWriteFile.mockRejectedValue(new Error('Oh no!')); - - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: '', - serviceAccountToken: { name: '', value: '' }, - }) - ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); - - expect(mockWriteFile).toHaveBeenCalledTimes(1); - expect(mockWriteFile).toHaveBeenCalledWith('/some/path/ca_1234.crt', 'ca-content'); - }); - - it('throws if cannot write config to yaml file', async () => { - mockWriteFile.mockResolvedValueOnce(undefined).mockRejectedValueOnce(new Error('Oh no!')); - - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - serviceAccountToken: { name: 'some-token', value: 'some-value' }, - }) - ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); - - expect(mockWriteFile).toHaveBeenCalledTimes(2); - expect(mockWriteFile).toHaveBeenCalledWith('/some/path/ca_1234.crt', 'ca-content'); - expect(mockWriteFile).toHaveBeenCalledWith( - '/some/path/kibana.yml', - ` - -# This section was automatically generated during setup. -elasticsearch.hosts: [some-host] -elasticsearch.serviceAccountToken: some-value -elasticsearch.ssl.certificateAuthorities: [/some/path/ca_1234.crt] - -` - ); - }); - - it('throws if cannot read existing config', async () => { - mockReadFile.mockRejectedValue(new Error('Oh no!')); - - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - serviceAccountToken: { name: 'some-token', value: 'some-value' }, - }) - ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); - - expect(mockWriteFile).not.toHaveBeenCalled(); - }); - - it('throws if cannot parse existing config', async () => { - mockReadFile.mockResolvedValue('foo: bar\nfoo: baz'); - - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - serviceAccountToken: { name: 'some-token', value: 'some-value' }, - }) - ).rejects.toMatchInlineSnapshot(` - [YAMLException: duplicated mapping key at line 2, column 1: - foo: baz - ^] - `); - - expect(mockWriteFile).not.toHaveBeenCalled(); - }); - - it('can successfully write CA certificate and elasticsearch config with service token', async () => { - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - serviceAccountToken: { name: 'some-token', value: 'some-value' }, - }) - ).resolves.toBeUndefined(); + beforeEach(() => { + mockReadFile.mockResolvedValue( + '# Default Kibana configuration for docker target\nserver.host: "0.0.0.0"\nserver.shutdownTimeout: "5s"' + ); + }); - expect(mockWriteFile).toHaveBeenCalledTimes(2); - expect(mockWriteFile).toHaveBeenCalledWith('/some/path/ca_1234.crt', 'ca-content'); - expect(mockWriteFile).toHaveBeenCalledWith( - '/some/path/kibana.yml', - ` + it('throws if cannot write CA file', async () => { + mockWriteFile.mockRejectedValue(new Error('Oh no!')); -# This section was automatically generated during setup. -elasticsearch.hosts: [some-host] -elasticsearch.serviceAccountToken: some-value -elasticsearch.ssl.certificateAuthorities: [/some/path/ca_1234.crt] + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: '', + serviceAccountToken: { name: '', value: '' }, + }) + ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); -` - ); - }); + expect(mockWriteFile).toHaveBeenCalledTimes(1); + expect(mockWriteFile).toHaveBeenCalledWith('/data/ca_1234.crt', 'ca-content'); + }); - it('can successfully write CA certificate and elasticsearch config with credentials', async () => { - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - username: 'username', - password: 'password', - }) - ).resolves.toBeUndefined(); + it('throws if cannot write config to yaml file', async () => { + mockWriteFile.mockResolvedValueOnce(undefined).mockRejectedValueOnce(new Error('Oh no!')); - expect(mockWriteFile).toHaveBeenCalledTimes(2); - expect(mockWriteFile).toHaveBeenCalledWith('/some/path/ca_1234.crt', 'ca-content'); - expect(mockWriteFile).toHaveBeenCalledWith( - '/some/path/kibana.yml', - ` - -# This section was automatically generated during setup. -elasticsearch.hosts: [some-host] -elasticsearch.password: password -elasticsearch.username: username -elasticsearch.ssl.certificateAuthorities: [/some/path/ca_1234.crt] - -` - ); - }); + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: 'some-host', + serviceAccountToken: { name: 'some-token', value: 'some-value' }, + }) + ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); - it('can successfully write elasticsearch config without CA certificate', async () => { - await expect( - kibanaConfigWriter.writeConfig({ - host: 'some-host', - username: 'username', - password: 'password', - }) - ).resolves.toBeUndefined(); + expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/data/ca_1234.crt", + "ca-content", + ], + Array [ + "/some/path/kibana.yml", + "# Default Kibana configuration for docker target + server.host: \\"0.0.0.0\\" + server.shutdownTimeout: \\"5s\\" + + # This section was automatically generated during setup. + elasticsearch.hosts: [some-host] + elasticsearch.serviceAccountToken: some-value + elasticsearch.ssl.certificateAuthorities: [/data/ca_1234.crt] + + ", + ], + ] + `); + }); - expect(mockWriteFile).toHaveBeenCalledTimes(1); - expect(mockWriteFile).toHaveBeenCalledWith( - '/some/path/kibana.yml', - ` + it('throws if cannot read existing config', async () => { + mockReadFile.mockRejectedValue(new Error('Oh no!')); -# This section was automatically generated during setup. -elasticsearch.hosts: [some-host] -elasticsearch.password: password -elasticsearch.username: username + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: 'some-host', + serviceAccountToken: { name: 'some-token', value: 'some-value' }, + }) + ).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`); -` - ); - }); + expect(mockWriteFile).not.toHaveBeenCalled(); }); - describe('with existing config (no conflicts)', () => { - beforeEach(() => { - mockReadFile.mockResolvedValue( - '# Default Kibana configuration for docker target\nserver.host: "0.0.0.0"\nserver.shutdownTimeout: "5s"' - ); - }); - - it('can successfully write CA certificate and elasticsearch config', async () => { - await expect( - kibanaConfigWriter.writeConfig({ - caCert: 'ca-content', - host: 'some-host', - serviceAccountToken: { name: 'some-token', value: 'some-value' }, - }) - ).resolves.toBeUndefined(); - - expect(mockReadFile).toHaveBeenCalledTimes(1); - expect(mockReadFile).toHaveBeenCalledWith('/some/path/kibana.yml', 'utf-8'); + it('throws if cannot parse existing config', async () => { + mockReadFile.mockResolvedValue('foo: bar\nfoo: baz'); + + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: 'some-host', + serviceAccountToken: { name: 'some-token', value: 'some-value' }, + }) + ).rejects.toMatchInlineSnapshot(` + [YAMLException: duplicated mapping key at line 2, column 1: + foo: baz + ^] + `); + + expect(mockWriteFile).not.toHaveBeenCalled(); + }); - expect(mockWriteFile).toHaveBeenCalledTimes(2); - expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` + it('can successfully write CA certificate and elasticsearch config with credentials', async () => { + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: 'some-host', + username: 'username', + password: 'password', + }) + ).resolves.toBeUndefined(); + + expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` + Array [ Array [ - Array [ - "/some/path/ca_1234.crt", - "ca-content", - ], - Array [ - "/some/path/kibana.yml", - "# Default Kibana configuration for docker target - server.host: \\"0.0.0.0\\" - server.shutdownTimeout: \\"5s\\" + "/data/ca_1234.crt", + "ca-content", + ], + Array [ + "/some/path/kibana.yml", + "# Default Kibana configuration for docker target + server.host: \\"0.0.0.0\\" + server.shutdownTimeout: \\"5s\\" + + # This section was automatically generated during setup. + elasticsearch.hosts: [some-host] + elasticsearch.username: username + elasticsearch.password: password + elasticsearch.ssl.certificateAuthorities: [/data/ca_1234.crt] + + ", + ], + ] + `); + }); - # This section was automatically generated during setup. - elasticsearch.hosts: [some-host] - elasticsearch.serviceAccountToken: some-value - elasticsearch.ssl.certificateAuthorities: [/some/path/ca_1234.crt] + it('can successfully write elasticsearch config without CA certificate', async () => { + await expect( + kibanaConfigWriter.writeConfig({ + host: 'some-host', + username: 'username', + password: 'password', + }) + ).resolves.toBeUndefined(); + + expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/some/path/kibana.yml", + "# Default Kibana configuration for docker target + server.host: \\"0.0.0.0\\" + server.shutdownTimeout: \\"5s\\" + + # This section was automatically generated during setup. + elasticsearch.hosts: [some-host] + elasticsearch.username: username + elasticsearch.password: password + + ", + ], + ] + `); + }); - ", - ], - ] - `); - }); + it('can successfully write CA certificate and elasticsearch config with service token', async () => { + await expect( + kibanaConfigWriter.writeConfig({ + caCert: 'ca-content', + host: 'some-host', + serviceAccountToken: { name: 'some-token', value: 'some-value' }, + }) + ).resolves.toBeUndefined(); + + expect(mockReadFile).toHaveBeenCalledTimes(1); + expect(mockReadFile).toHaveBeenCalledWith('/some/path/kibana.yml', 'utf-8'); + + expect(mockWriteFile).toHaveBeenCalledTimes(2); + expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/data/ca_1234.crt", + "ca-content", + ], + Array [ + "/some/path/kibana.yml", + "# Default Kibana configuration for docker target + server.host: \\"0.0.0.0\\" + server.shutdownTimeout: \\"5s\\" + + # This section was automatically generated during setup. + elasticsearch.hosts: [some-host] + elasticsearch.serviceAccountToken: some-value + elasticsearch.ssl.certificateAuthorities: [/data/ca_1234.crt] + + ", + ], + ] + `); }); - describe('with existing config (with conflicts)', () => { + describe('with conflicts', () => { beforeEach(() => { jest.spyOn(Date.prototype, 'toISOString').mockReturnValue('some date'); mockReadFile.mockResolvedValue( @@ -291,7 +281,7 @@ elasticsearch.username: username expect(mockWriteFile.mock.calls).toMatchInlineSnapshot(` Array [ Array [ - "/some/path/ca_1234.crt", + "/data/ca_1234.crt", "ca-content", ], Array [ @@ -312,7 +302,7 @@ elasticsearch.username: username elasticsearch.hosts: [some-host] monitoring.ui.container.elasticsearch.enabled: true elasticsearch.serviceAccountToken: some-value - elasticsearch.ssl.certificateAuthorities: [/some/path/ca_1234.crt] + elasticsearch.ssl.certificateAuthorities: [/data/ca_1234.crt] ", ], diff --git a/src/plugins/interactive_setup/server/kibana_config_writer.ts b/src/plugins/interactive_setup/server/kibana_config_writer.ts index ff67e887fab49..949bc25ddd253 100644 --- a/src/plugins/interactive_setup/server/kibana_config_writer.ts +++ b/src/plugins/interactive_setup/server/kibana_config_writer.ts @@ -31,24 +31,23 @@ export type WriteConfigParameters = { ); export class KibanaConfigWriter { - constructor(private readonly configPath: string, private readonly logger: Logger) {} + constructor( + private readonly configPath: string, + private readonly dataDirectoryPath: string, + private readonly logger: Logger + ) {} /** - * Checks if we can write to the Kibana configuration file and configuration directory. + * Checks if we can write to the Kibana configuration file and data directory. */ public async isConfigWritable() { try { // We perform two separate checks here: - // 1. If we can write to config directory to add a new CA certificate file and potentially Kibana configuration - // file if it doesn't exist for some reason. + // 1. If we can write to data directory to add a new CA certificate file. // 2. If we can write to the Kibana configuration file if it exists. - const canWriteToConfigDirectory = fs.access(path.dirname(this.configPath), constants.W_OK); await Promise.all([ - canWriteToConfigDirectory, - fs.access(this.configPath, constants.F_OK).then( - () => fs.access(this.configPath, constants.W_OK), - () => canWriteToConfigDirectory - ), + fs.access(this.dataDirectoryPath, constants.W_OK), + fs.access(this.configPath, constants.W_OK), ]); return true; } catch { @@ -61,13 +60,13 @@ export class KibanaConfigWriter { * @param params */ public async writeConfig(params: WriteConfigParameters) { - const caPath = path.join(path.dirname(this.configPath), `ca_${Date.now()}.crt`); + const caPath = path.join(this.dataDirectoryPath, `ca_${Date.now()}.crt`); const config: Record = { 'elasticsearch.hosts': [params.host] }; - if ('serviceAccountToken' in params) { + if ('serviceAccountToken' in params && params.serviceAccountToken) { config['elasticsearch.serviceAccountToken'] = params.serviceAccountToken.value; - } else if ('username' in params) { - config['elasticsearch.password'] = params.password; + } else if ('username' in params && params.username) { config['elasticsearch.username'] = params.username; + config['elasticsearch.password'] = params.password; } if (params.caCert) { config['elasticsearch.ssl.certificateAuthorities'] = [caPath]; diff --git a/src/plugins/interactive_setup/server/mocks.ts b/src/plugins/interactive_setup/server/mocks.ts index 75b28a502b6d4..eb531e35f8dff 100644 --- a/src/plugins/interactive_setup/server/mocks.ts +++ b/src/plugins/interactive_setup/server/mocks.ts @@ -6,15 +6,17 @@ * Side Public License, v 1. */ -import type { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; function createApiResponseMock( - apiResponse: Pick, 'body'> & - Partial, 'body'>> -): ApiResponse { + apiResponse: Pick, 'body'> & + Partial, 'body'>> +): TransportResult { return { + // @ts-expect-error null is not supported statusCode: null, - headers: null, + // @ts-expect-error null is not supported + headers: undefined, warnings: null, meta: {} as any, ...apiResponse, diff --git a/src/plugins/interactive_setup/server/plugin.ts b/src/plugins/interactive_setup/server/plugin.ts index 8c1d00a254764..067b8fd044f30 100644 --- a/src/plugins/interactive_setup/server/plugin.ts +++ b/src/plugins/interactive_setup/server/plugin.ts @@ -10,6 +10,7 @@ import chalk from 'chalk'; import type { Subscription } from 'rxjs'; import type { TypeOf } from '@kbn/config-schema'; +import { getDataPath } from '@kbn/utils'; import type { CorePreboot, Logger, PluginInitializerContext, PrebootPlugin } from 'src/core/server'; import { ElasticsearchConnectionStatus } from '../common'; @@ -146,7 +147,11 @@ Go to ${chalk.cyanBright.underline(url)} to get started. basePath: core.http.basePath, logger: this.#logger.get('routes'), preboot: { ...core.preboot, completeSetup }, - kibanaConfigWriter: new KibanaConfigWriter(configPath, this.#logger.get('kibana-config')), + kibanaConfigWriter: new KibanaConfigWriter( + configPath, + getDataPath(), + this.#logger.get('kibana-config') + ), elasticsearch, verificationCode, getConfig: this.#getConfig.bind(this), diff --git a/src/plugins/interactive_setup/server/routes/index.ts b/src/plugins/interactive_setup/server/routes/index.ts index fb9e06c4c2a18..f1f6b34fb689c 100644 --- a/src/plugins/interactive_setup/server/routes/index.ts +++ b/src/plugins/interactive_setup/server/routes/index.ts @@ -16,6 +16,7 @@ import type { VerificationCode } from '../verification_code'; import { defineConfigureRoute } from './configure'; import { defineEnrollRoutes } from './enroll'; import { definePingRoute } from './ping'; +import { defineStatusRoute } from './status'; import { defineVerifyRoute } from './verify'; /** @@ -39,4 +40,5 @@ export function defineRoutes(params: RouteDefinitionParams) { defineEnrollRoutes(params); definePingRoute(params); defineVerifyRoute(params); + defineStatusRoute(params); } diff --git a/src/plugins/interactive_setup/server/routes/status.test.ts b/src/plugins/interactive_setup/server/routes/status.test.ts new file mode 100644 index 0000000000000..b40c765a8a53a --- /dev/null +++ b/src/plugins/interactive_setup/server/routes/status.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { IRouter, RequestHandler, RequestHandlerContext } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; + +import { routeDefinitionParamsMock } from './index.mock'; +import { defineStatusRoute } from './status'; + +describe('Status routes', () => { + let router: jest.Mocked; + let mockRouteParams: ReturnType; + let mockContext: RequestHandlerContext; + beforeEach(() => { + mockRouteParams = routeDefinitionParamsMock.create(); + mockRouteParams.preboot.isSetupOnHold.mockReturnValue(false); + router = mockRouteParams.router; + + mockContext = {} as unknown as RequestHandlerContext; + + defineStatusRoute(mockRouteParams); + }); + + describe('#status', () => { + let routeHandler: RequestHandler; + + beforeEach(() => { + const [, statusRouteHandler] = router.get.mock.calls.find( + ([{ path }]) => path === '/internal/interactive_setup/status' + )!; + + routeHandler = statusRouteHandler; + }); + + it('should return connection status', async () => { + const mockRequest = httpServerMock.createKibanaRequest(); + + await expect(routeHandler(mockContext, mockRequest, kibanaResponseFactory)).resolves + .toMatchInlineSnapshot(` + KibanaResponse { + "options": Object { + "body": Object { + "connectionStatus": "configured", + "isSetupOnHold": false, + }, + }, + "payload": Object { + "connectionStatus": "configured", + "isSetupOnHold": false, + }, + "status": 200, + } + `); + }); + }); +}); diff --git a/src/plugins/interactive_setup/server/routes/status.ts b/src/plugins/interactive_setup/server/routes/status.ts new file mode 100644 index 0000000000000..51b98732853ef --- /dev/null +++ b/src/plugins/interactive_setup/server/routes/status.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { first } from 'rxjs/operators'; + +import type { RouteDefinitionParams } from '.'; + +export function defineStatusRoute({ router, elasticsearch, preboot }: RouteDefinitionParams) { + router.get( + { + path: '/internal/interactive_setup/status', + validate: false, + options: { authRequired: false }, + }, + async (context, request, response) => { + // `connectionStatus$` is a `ReplaySubject` with a buffer size of 1 so `first()` operator will + // always return the most recently emitted value. We can't use `connectionStatus$.toPromise()` + // directly since the stream hasn't ended so it would never resolve. + const connectionStatus = await elasticsearch.connectionStatus$.pipe(first()).toPromise(); + return response.ok({ + body: { + connectionStatus, + isSetupOnHold: preboot.isSetupOnHold(), + }, + }); + } + ); +} diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap index 30703a4a5ebb7..8e1d0cb92e006 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap @@ -15,16 +15,11 @@ exports[`ElasticAgentCard props button 1`] = ` Button - - Button - -
+ } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -55,15 +50,11 @@ exports[`ElasticAgentCard props category 1`] = ` - - Add Elastic Agent - -
+ Add Elastic Agent + } href="/app/integrations/browse/custom" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -94,16 +85,11 @@ exports[`ElasticAgentCard props href 1`] = ` Button - - Button - - + } href="#" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -135,15 +121,11 @@ exports[`ElasticAgentCard props recommended 1`] = ` betaBadgeLabel="Recommended" description="Use Elastic Agent for a simple, unified way to collect data from your machines." footer={ -
- - Add Elastic Agent - -
+ Add Elastic Agent + } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -174,15 +156,11 @@ exports[`ElasticAgentCard renders 1`] = ` - - Add Elastic Agent - - + Add Elastic Agent + } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap index 6959e2e29095a..fccbbe3a9e8ee 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap @@ -2,7 +2,7 @@ exports[`NoDataCard props button 1`] = `
-
- -
+ +
`; exports[`NoDataCard props href 1`] = `
-
- -
+ +
`; exports[`NoDataCard props recommended 1`] = `
- `; exports[`NoDataCard renders 1`] = `
- `; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx index d429f9d712081..b9d412fe4df89 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx @@ -44,7 +44,6 @@ export const ElasticAgentCard: FunctionComponent = ({ {i18n.translate('kibana-react.noDataPage.elasticAgentCard.noPermission.title', { @@ -93,12 +92,7 @@ export const ElasticAgentCard: FunctionComponent = ({ defaultMessage: `Use Elastic Agent for a simple, unified way to collect data from your machines.`, })} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} - footer={ -
- {button} - {footer} -
- } + footer={footer} layout={layout as 'vertical' | undefined} {...cardRest} /> diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx index ad40a4f8f5499..9cc38cc5f6038 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx @@ -27,7 +27,6 @@ export const NoDataCard: FunctionComponent = ({ return ( = ({ defaultMessage: `Proceed without collecting data`, })} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} - footer={
{footer}
} + footer={footer} layout={layout as 'vertical' | undefined} {...cardRest} /> diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_page.scss b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_page.scss index f1bc12e74cf4e..d4b50536d0d09 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_page.scss +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_page.scss @@ -1,5 +1,5 @@ .kbnNoDataPageContents__item:only-child { - min-width: 400px; + min-width: ($euiSize * 22.5); @include euiBreakpoint('xs', 's') { min-width: auto; diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts index 1312b516daccc..adfe8da335a14 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts @@ -157,7 +157,7 @@ export const applicationUsageSchema = { security_login: commonSchema, security_logout: commonSchema, security_overwritten_session: commonSchema, - securitySolution: commonSchema, + securitySolutionUI: commonSchema, siem: commonSchema, space_selector: commonSchema, uptime: commonSchema, diff --git a/src/plugins/kibana_usage_collection/server/collectors/event_loop_delays/track_delays.ts b/src/plugins/kibana_usage_collection/server/collectors/event_loop_delays/track_delays.ts index facdb549d0df7..33266cdbd9792 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/event_loop_delays/track_delays.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/event_loop_delays/track_delays.ts @@ -52,6 +52,10 @@ export function startTrackingEventLoopDelaysUsage( if (shouldReset) { eventLoopDelaysMonitor.reset(); } - await storeHistogram(histogram, internalRepository, instanceUuid); + try { + await storeHistogram(histogram, internalRepository, instanceUuid); + } catch (e) { + // do not crash if cannot store a histogram. + } }); } diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index bf936b2ae8dbe..007d3a99cb1dd 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -436,6 +436,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'labs:canvas:byValueEmbeddable': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'labs:canvas:useDataService': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, @@ -448,6 +452,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'labs:dashboard:dashboardControls': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'discover:showFieldStatistics': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 7575fa5d2b3f3..d35a05fe04780 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -120,8 +120,10 @@ export interface UsageStats { 'banners:textColor': string; 'banners:backgroundColor': string; 'labs:canvas:enable_ui': boolean; + 'labs:canvas:byValueEmbeddable': boolean; 'labs:canvas:useDataService': boolean; 'labs:presentation:timeToPresent': boolean; 'labs:dashboard:enable_ui': boolean; 'labs:dashboard:deferBelowFold': boolean; + 'labs:dashboard:dashboardControls': boolean; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.test.ts index fc9f9a6e8c2d3..d61b8ca2c7779 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.test.ts @@ -6,11 +6,7 @@ * Side Public License, v 1. */ -import { - loggingSystemMock, - pluginInitializerContextConfigMock, - elasticsearchServiceMock, -} from '../../../../../core/server/mocks'; +import { loggingSystemMock, elasticsearchServiceMock } from '../../../../../core/server/mocks'; import { Collector, createCollectorFetchContextMock, @@ -29,7 +25,7 @@ describe('kibana_usage', () => { return createUsageCollectionSetupMock().makeUsageCollector(config); }); - const legacyConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; + const kibanaIndex = '.kibana-tests'; const getMockFetchClients = (hits?: unknown[]) => { const fetchParamsMock = createCollectorFetchContextMock(); @@ -40,7 +36,7 @@ describe('kibana_usage', () => { return fetchParamsMock; }; - beforeAll(() => registerKibanaUsageCollector(usageCollectionMock, legacyConfig$)); + beforeAll(() => registerKibanaUsageCollector(usageCollectionMock, kibanaIndex)); afterAll(() => jest.clearAllTimers()); test('registered collector is set', () => { diff --git a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.ts index 75d5af2737772..9bd8da2be54df 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/kibana_usage_collector.ts @@ -6,10 +6,8 @@ * Side Public License, v 1. */ -import type { Observable } from 'rxjs'; -import type { ElasticsearchClient, SharedGlobalConfig } from 'src/core/server'; +import type { ElasticsearchClient } from 'src/core/server'; import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { take } from 'rxjs/operators'; import { snakeCase } from 'lodash'; import { getSavedObjectsCounts } from './get_saved_object_counts'; @@ -46,7 +44,7 @@ export async function getKibanaSavedObjectCounts( export function registerKibanaUsageCollector( usageCollection: UsageCollectionSetup, - legacyConfig$: Observable + kibanaIndex: string ) { usageCollection.registerCollector( usageCollection.makeUsageCollector({ @@ -83,12 +81,9 @@ export function registerKibanaUsageCollector( }, }, async fetch({ esClient }) { - const { - kibana: { index }, - } = await legacyConfig$.pipe(take(1)).toPromise(); return { - index, - ...(await getKibanaSavedObjectCounts(esClient, index)), + index: kibanaIndex, + ...(await getKibanaSavedObjectCounts(esClient, kibanaIndex)), }; }, }) diff --git a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.test.ts index 0ef5bffd40ff7..1f507dcc44666 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.test.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { pluginInitializerContextConfigMock } from '../../../../../core/server/mocks'; import { createCollectorFetchContextMock, createUsageCollectionSetupMock, @@ -16,9 +15,9 @@ import { registerSavedObjectsCountUsageCollector } from './saved_objects_count_c describe('saved_objects_count_collector', () => { const usageCollectionMock = createUsageCollectionSetupMock(); - const legacyConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; + const kibanaIndex = '.kibana-tests'; - beforeAll(() => registerSavedObjectsCountUsageCollector(usageCollectionMock, legacyConfig$)); + beforeAll(() => registerSavedObjectsCountUsageCollector(usageCollectionMock, kibanaIndex)); afterAll(() => jest.clearAllTimers()); test('registered collector is set', () => { diff --git a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.ts index 71bf2da7dc270..f541b1ef452e6 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/saved_objects_counts/saved_objects_count_collector.ts @@ -6,9 +6,6 @@ * Side Public License, v 1. */ -import type { Observable } from 'rxjs'; -import { take } from 'rxjs/operators'; -import type { SharedGlobalConfig } from 'src/core/server'; import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { getSavedObjectsCounts } from './get_saved_object_counts'; @@ -23,7 +20,7 @@ interface SavedObjectsCountUsage { export function registerSavedObjectsCountUsageCollector( usageCollection: UsageCollectionSetup, - legacyConfig$: Observable + kibanaIndex: string ) { usageCollection.registerCollector( usageCollection.makeUsageCollector({ @@ -45,10 +42,7 @@ export function registerSavedObjectsCountUsageCollector( }, }, async fetch({ esClient }) { - const { - kibana: { index }, - } = await legacyConfig$.pipe(take(1)).toPromise(); - const buckets = await getSavedObjectsCounts(esClient, index); + const buckets = await getSavedObjectsCounts(esClient, kibanaIndex); return { by_type: buckets.map(({ key: type, doc_count: count }) => { return { type, count }; diff --git a/src/plugins/kibana_usage_collection/server/plugin.ts b/src/plugins/kibana_usage_collection/server/plugin.ts index 07a70dfd56fb4..19adea4f009a2 100644 --- a/src/plugins/kibana_usage_collection/server/plugin.ts +++ b/src/plugins/kibana_usage_collection/server/plugin.ts @@ -7,14 +7,13 @@ */ import type { UsageCollectionSetup, UsageCounter } from 'src/plugins/usage_collection/server'; -import { Subject, Observable } from 'rxjs'; +import { Subject } from 'rxjs'; import type { PluginInitializerContext, CoreSetup, Plugin, ISavedObjectsRepository, IUiSettingsClient, - SharedGlobalConfig, CoreStart, SavedObjectsServiceSetup, OpsMetrics, @@ -55,7 +54,6 @@ type SavedObjectsRegisterType = SavedObjectsServiceSetup['registerType']; export class KibanaUsageCollectionPlugin implements Plugin { private readonly logger: Logger; - private readonly legacyConfig$: Observable; private readonly instanceUuid: string; private savedObjectsClient?: ISavedObjectsRepository; private uiSettingsClient?: IUiSettingsClient; @@ -66,7 +64,6 @@ export class KibanaUsageCollectionPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); - this.legacyConfig$ = initializerContext.config.legacy.globalConfig$; this.metric$ = new Subject(); this.pluginStop$ = new Subject(); this.instanceUuid = initializerContext.env.instanceUuid; @@ -111,6 +108,8 @@ export class KibanaUsageCollectionPlugin implements Plugin { public stop() { this.metric$.complete(); + + this.pluginStop$.next(); this.pluginStop$.complete(); } @@ -121,6 +120,7 @@ export class KibanaUsageCollectionPlugin implements Plugin { pluginStop$: Subject, registerType: SavedObjectsRegisterType ) { + const kibanaIndex = coreSetup.savedObjects.getKibanaIndex(); const getSavedObjectsClient = () => this.savedObjectsClient; const getUiSettingsClient = () => this.uiSettingsClient; const getCoreUsageDataService = () => this.coreUsageData!; @@ -133,8 +133,8 @@ export class KibanaUsageCollectionPlugin implements Plugin { registerUsageCountersUsageCollector(usageCollection); registerOpsStatsCollector(usageCollection, metric$); - registerKibanaUsageCollector(usageCollection, this.legacyConfig$); - registerSavedObjectsCountUsageCollector(usageCollection, this.legacyConfig$); + registerKibanaUsageCollector(usageCollection, kibanaIndex); + registerSavedObjectsCountUsageCollector(usageCollection, kibanaIndex); registerManagementUsageCollector(usageCollection, getUiSettingsClient); registerUiMetricUsageCollector(usageCollection, registerType, getSavedObjectsClient); registerApplicationUsageCollector( diff --git a/src/plugins/kibana_utils/common/errors/errors.ts b/src/plugins/kibana_utils/common/errors/errors.ts index 7f3efc6d9571f..fcfbfa64aca57 100644 --- a/src/plugins/kibana_utils/common/errors/errors.ts +++ b/src/plugins/kibana_utils/common/errors/errors.ts @@ -26,6 +26,17 @@ export class DuplicateField extends KbnError { } } +/** + * when a user is attempting to create a field with disallowed character in the name, like * + * @param {String} character - the character not allowed in name + * @param {String} name - the field name + */ +export class CharacterNotAllowedInField extends KbnError { + constructor(character: string, name: string) { + super(`The field "${name}" cannot have "${character}" in the name`); + } +} + /** * A saved object was not found */ diff --git a/src/plugins/kibana_utils/server/report_server_error.ts b/src/plugins/kibana_utils/server/report_server_error.ts index 9f0bf34eaebb6..57b8c4e207f72 100644 --- a/src/plugins/kibana_utils/server/report_server_error.ts +++ b/src/plugins/kibana_utils/server/report_server_error.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { KibanaResponseFactory } from 'kibana/server'; import { KbnError } from '../common'; @@ -27,8 +27,8 @@ export function getKbnServerError(e: Error) { if (e instanceof KbnServerError) return e; return new KbnServerError( e.message ?? 'Unknown error', - e instanceof ResponseError ? e.statusCode : 500, - e instanceof ResponseError ? e.body : undefined + e instanceof errors.ResponseError ? e.statusCode! : 500, + e instanceof errors.ResponseError ? e.body : undefined ); } diff --git a/src/plugins/maps_ems/common/index.ts b/src/plugins/maps_ems/common/index.ts index 26fdb4fa795fe..acf27bb3a8a73 100644 --- a/src/plugins/maps_ems/common/index.ts +++ b/src/plugins/maps_ems/common/index.ts @@ -10,7 +10,7 @@ export const TMS_IN_YML_ID = 'TMS in config/kibana.yml'; export const DEFAULT_EMS_FILE_API_URL = 'https://vector.maps.elastic.co'; export const DEFAULT_EMS_TILE_API_URL = 'https://tiles.maps.elastic.co'; -export const DEFAULT_EMS_LANDING_PAGE_URL = 'https://maps.elastic.co/v7.16'; +export const DEFAULT_EMS_LANDING_PAGE_URL = 'https://maps.elastic.co/v8.0'; export const DEFAULT_EMS_FONT_LIBRARY_URL = 'https://tiles.maps.elastic.co/fonts/{fontstack}/{range}.pbf'; diff --git a/src/plugins/maps_ems/config.ts b/src/plugins/maps_ems/config.ts index 710cb52f32a09..d64156a0395b1 100644 --- a/src/plugins/maps_ems/config.ts +++ b/src/plugins/maps_ems/config.ts @@ -39,13 +39,7 @@ export const tilemapConfigSchema = schema.object({ export const emsConfigSchema = schema.object({ tilemap: tilemapConfigSchema, includeElasticMapsService: schema.boolean({ defaultValue: true }), - proxyElasticMapsServiceInMaps: schema.boolean({ defaultValue: false }), - emsUrl: schema.conditional( - schema.siblingRef('proxyElasticMapsServiceInMaps'), - true, - schema.never(), - schema.string({ defaultValue: '' }) - ), + emsUrl: schema.string({ defaultValue: '' }), emsFileApiUrl: schema.string({ defaultValue: DEFAULT_EMS_FILE_API_URL }), emsTileApiUrl: schema.string({ defaultValue: DEFAULT_EMS_TILE_API_URL }), emsLandingPageUrl: schema.string({ defaultValue: DEFAULT_EMS_LANDING_PAGE_URL }), diff --git a/src/plugins/maps_ems/server/index.ts b/src/plugins/maps_ems/server/index.ts index 7422dbcfcdec9..1fdafd465da12 100644 --- a/src/plugins/maps_ems/server/index.ts +++ b/src/plugins/maps_ems/server/index.ts @@ -18,7 +18,6 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { tilemap: true, includeElasticMapsService: true, - proxyElasticMapsServiceInMaps: true, emsUrl: true, emsFileApiUrl: true, emsTileApiUrl: true, diff --git a/src/plugins/presentation_util/common/controls/control_group/control_group_persistable_state.ts b/src/plugins/presentation_util/common/controls/control_group/control_group_persistable_state.ts new file mode 100644 index 0000000000000..2da488acdc436 --- /dev/null +++ b/src/plugins/presentation_util/common/controls/control_group/control_group_persistable_state.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + EmbeddableInput, + EmbeddablePersistableStateService, + EmbeddableStateWithType, +} from '../../../../embeddable/common/types'; +import { ControlGroupInput, ControlPanelState } from './types'; +import { SavedObjectReference } from '../../../../../core/types'; + +type ControlGroupInputWithType = Partial & { type: string }; + +const getPanelStatePrefix = (state: ControlPanelState) => `${state.explicitInput.id}:`; + +export const createControlGroupInject = ( + persistableStateService: EmbeddablePersistableStateService +): EmbeddablePersistableStateService['inject'] => { + return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => { + const workingState = { ...state } as EmbeddableStateWithType | ControlGroupInputWithType; + + if ('panels' in workingState) { + workingState.panels = { ...workingState.panels }; + + for (const [key, panel] of Object.entries(workingState.panels)) { + workingState.panels[key] = { ...panel }; + // Find the references for this panel + const prefix = getPanelStatePrefix(panel); + + const filteredReferences = references + .filter((reference) => reference.name.indexOf(prefix) === 0) + .map((reference) => ({ ...reference, name: reference.name.replace(prefix, '') })); + + const panelReferences = filteredReferences.length === 0 ? references : filteredReferences; + + const { type, ...injectedState } = persistableStateService.inject( + { ...workingState.panels[key].explicitInput, type: workingState.panels[key].type }, + panelReferences + ); + workingState.panels[key].explicitInput = injectedState as EmbeddableInput; + } + } + return workingState as EmbeddableStateWithType; + }; +}; + +export const createControlGroupExtract = ( + persistableStateService: EmbeddablePersistableStateService +): EmbeddablePersistableStateService['extract'] => { + return (state: EmbeddableStateWithType) => { + const workingState = { ...state } as EmbeddableStateWithType | ControlGroupInputWithType; + const references: SavedObjectReference[] = []; + + if ('panels' in workingState) { + workingState.panels = { ...workingState.panels }; + + // Run every panel through the state service to get the nested references + for (const [key, panel] of Object.entries(workingState.panels)) { + const prefix = getPanelStatePrefix(panel); + + const { state: panelState, references: panelReferences } = persistableStateService.extract({ + ...panel.explicitInput, + type: panel.type, + }); + + // Map reference to its embeddable id for lookup in inject + const mappedReferences = panelReferences.map((reference) => ({ + ...reference, + name: `${prefix}${reference.name}`, + })); + + references.push(...mappedReferences); + + const { type, ...restOfState } = panelState; + workingState.panels[key].explicitInput = restOfState as EmbeddableInput; + } + } + return { state: workingState as EmbeddableStateWithType, references }; + }; +}; diff --git a/src/plugins/presentation_util/common/controls/control_group/types.ts b/src/plugins/presentation_util/common/controls/control_group/types.ts new file mode 100644 index 0000000000000..da1cec0391102 --- /dev/null +++ b/src/plugins/presentation_util/common/controls/control_group/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EmbeddableInput, PanelState } from '../../../../embeddable/common/types'; +import { ControlInput, ControlStyle, ControlWidth } from '../types'; + +export const CONTROL_GROUP_TYPE = 'control_group'; + +export interface ControlPanelState + extends PanelState { + order: number; + width: ControlWidth; +} + +export interface ControlsPanels { + [panelId: string]: ControlPanelState; +} + +export interface ControlGroupInput extends EmbeddableInput, ControlInput { + defaultControlWidth?: ControlWidth; + controlStyle: ControlStyle; + panels: ControlsPanels; +} diff --git a/src/plugins/presentation_util/common/controls/control_types/options_list/options_list_persistable_state.ts b/src/plugins/presentation_util/common/controls/control_types/options_list/options_list_persistable_state.ts new file mode 100644 index 0000000000000..90390256325ae --- /dev/null +++ b/src/plugins/presentation_util/common/controls/control_types/options_list/options_list_persistable_state.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + EmbeddableStateWithType, + EmbeddablePersistableStateService, +} from '../../../../../embeddable/common/types'; +import { OptionsListEmbeddableInput } from './types'; +import { SavedObjectReference } from '../../../../../../core/types'; +import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../../../../../data_views/common'; + +type OptionsListInputWithType = Partial & { type: string }; +const dataViewReferenceName = 'optionsListDataView'; + +export const createOptionsListInject = (): EmbeddablePersistableStateService['inject'] => { + return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => { + const workingState = { ...state } as EmbeddableStateWithType | OptionsListInputWithType; + references.forEach((reference) => { + if (reference.name === dataViewReferenceName) { + (workingState as OptionsListInputWithType).dataViewId = reference.id; + } + }); + return workingState as EmbeddableStateWithType; + }; +}; + +export const createOptionsListExtract = (): EmbeddablePersistableStateService['extract'] => { + return (state: EmbeddableStateWithType) => { + const workingState = { ...state } as EmbeddableStateWithType | OptionsListInputWithType; + const references: SavedObjectReference[] = []; + + if ('dataViewId' in workingState) { + references.push({ + name: dataViewReferenceName, + type: DATA_VIEW_SAVED_OBJECT_TYPE, + id: workingState.dataViewId!, + }); + delete workingState.dataViewId; + } + return { state: workingState as EmbeddableStateWithType, references }; + }; +}; diff --git a/src/plugins/presentation_util/common/controls/control_types/options_list/types.ts b/src/plugins/presentation_util/common/controls/control_types/options_list/types.ts new file mode 100644 index 0000000000000..9a6a96e861bed --- /dev/null +++ b/src/plugins/presentation_util/common/controls/control_types/options_list/types.ts @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ControlInput } from '../../types'; + +export const OPTIONS_LIST_CONTROL = 'optionsListControl'; + +export interface OptionsListEmbeddableInput extends ControlInput { + fieldName: string; + dataViewId: string; + + selectedOptions?: string[]; + singleSelect?: boolean; + loading?: boolean; +} diff --git a/src/plugins/presentation_util/common/controls/index.ts b/src/plugins/presentation_util/common/controls/index.ts new file mode 100644 index 0000000000000..b01a242bdfa5f --- /dev/null +++ b/src/plugins/presentation_util/common/controls/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './control_group/types'; +export * from './control_types/options_list/types'; diff --git a/src/plugins/presentation_util/common/controls/types.ts b/src/plugins/presentation_util/common/controls/types.ts new file mode 100644 index 0000000000000..288324e30b47c --- /dev/null +++ b/src/plugins/presentation_util/common/controls/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Filter, Query } from '@kbn/es-query'; +import { TimeRange } from '../../../data/common'; +import { EmbeddableInput } from '../../../embeddable/common/types'; + +export type ControlWidth = 'auto' | 'small' | 'medium' | 'large'; +export type ControlStyle = 'twoLine' | 'oneLine'; + +export interface ParentIgnoreSettings { + ignoreFilters?: boolean; + ignoreQuery?: boolean; + ignoreTimerange?: boolean; +} + +export type ControlInput = EmbeddableInput & { + query?: Query; + filters?: Filter[]; + timeRange?: TimeRange; + controlStyle?: ControlStyle; + ignoreParentSettings?: ParentIgnoreSettings; +}; diff --git a/src/plugins/presentation_util/common/labs.ts b/src/plugins/presentation_util/common/labs.ts index b958f3de0814f..8eefbd6981280 100644 --- a/src/plugins/presentation_util/common/labs.ts +++ b/src/plugins/presentation_util/common/labs.ts @@ -10,8 +10,10 @@ import { i18n } from '@kbn/i18n'; export const LABS_PROJECT_PREFIX = 'labs:'; export const DEFER_BELOW_FOLD = `${LABS_PROJECT_PREFIX}dashboard:deferBelowFold` as const; +export const DASHBOARD_CONTROLS = `${LABS_PROJECT_PREFIX}dashboard:dashboardControls` as const; +export const BY_VALUE_EMBEDDABLE = `${LABS_PROJECT_PREFIX}canvas:byValueEmbeddable` as const; -export const projectIDs = [DEFER_BELOW_FOLD] as const; +export const projectIDs = [DEFER_BELOW_FOLD, DASHBOARD_CONTROLS, BY_VALUE_EMBEDDABLE] as const; export const environmentNames = ['kibana', 'browser', 'session'] as const; export const solutionNames = ['canvas', 'dashboard', 'presentation'] as const; @@ -34,6 +36,33 @@ export const projects: { [ID in ProjectID]: ProjectConfig & { id: ID } } = { }), solutions: ['dashboard'], }, + [DASHBOARD_CONTROLS]: { + id: DASHBOARD_CONTROLS, + isActive: false, + isDisplayed: true, + environments: ['kibana', 'browser', 'session'], + name: i18n.translate('presentationUtil.labs.enableDashboardControlsProjectName', { + defaultMessage: 'Enable dashboard controls', + }), + description: i18n.translate('presentationUtil.labs.enableDashboardControlsProjectDescription', { + defaultMessage: + 'Enables the controls system for dashboard, which allows dashboard authors to more easily build interactive elements for their users.', + }), + solutions: ['dashboard'], + }, + [BY_VALUE_EMBEDDABLE]: { + id: BY_VALUE_EMBEDDABLE, + isActive: true, + isDisplayed: true, + environments: ['kibana', 'browser', 'session'], + name: i18n.translate('presentationUtil.labs.enableByValueEmbeddableName', { + defaultMessage: 'By-Value Embeddables', + }), + description: i18n.translate('presentationUtil.labs.enableByValueEmbeddableDescription', { + defaultMessage: 'Enables support for by-value embeddables in Canvas', + }), + solutions: ['canvas'], + }, }; export type ProjectID = typeof projectIDs[number]; diff --git a/src/plugins/presentation_util/common/lib/index.ts b/src/plugins/presentation_util/common/lib/index.ts index 3fe90009ad8df..030780c130fa5 100644 --- a/src/plugins/presentation_util/common/lib/index.ts +++ b/src/plugins/presentation_util/common/lib/index.ts @@ -8,3 +8,4 @@ export * from './utils'; export * from './test_helpers'; +export * from '../controls'; diff --git a/src/plugins/presentation_util/kibana.json b/src/plugins/presentation_util/kibana.json index 71ac224d1976a..210937b335e50 100644 --- a/src/plugins/presentation_util/kibana.json +++ b/src/plugins/presentation_util/kibana.json @@ -10,6 +10,6 @@ "server": true, "ui": true, "extraPublicDirs": ["common/lib"], - "requiredPlugins": ["savedObjects", "kibanaReact"], + "requiredPlugins": ["savedObjects", "data", "dataViews", "embeddable", "kibanaReact"], "optionalPlugins": [] } diff --git a/src/plugins/presentation_util/public/components/controls/__stories__/input_controls.stories.tsx b/src/plugins/presentation_util/public/components/controls/__stories__/controls.stories.tsx similarity index 77% rename from src/plugins/presentation_util/public/components/controls/__stories__/input_controls.stories.tsx rename to src/plugins/presentation_util/public/components/controls/__stories__/controls.stories.tsx index ec1678c5faa96..1b1dada24b288 100644 --- a/src/plugins/presentation_util/public/components/controls/__stories__/input_controls.stories.tsx +++ b/src/plugins/presentation_util/public/components/controls/__stories__/controls.stories.tsx @@ -6,21 +6,22 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo, useState, useCallback, FC } from 'react'; -import uuid from 'uuid'; import { EuiFlexGroup, EuiFlexItem, EuiSwitch, EuiTextAlign } from '@elastic/eui'; +import React, { useEffect, useMemo, useState, useCallback, FC } from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; +import uuid from 'uuid'; import { decorators } from './decorators'; +import { ControlsPanels } from '../control_group/types'; +import { ViewMode } from '../../../../../embeddable/public'; +import { getFlightOptionsAsync, storybookFlightsDataView } from './fixtures/flights'; import { pluginServices, registry } from '../../../services/storybook'; +import { OptionsListEmbeddableInput, OPTIONS_LIST_CONTROL } from '../../..'; +import { replaceValueSuggestionMethod } from '../../../services/storybook/data'; +import { injectStorybookDataView } from '../../../services/storybook/data_views'; import { populateStorybookControlFactories } from './storybook_control_factories'; +import { EmbeddablePersistableStateService } from '../../../../../embeddable/common'; import { ControlGroupContainerFactory } from '../control_group/embeddable/control_group_container_factory'; -import { ControlsPanels } from '../control_group/types'; -import { - OptionsListEmbeddableInput, - OPTIONS_LIST_CONTROL, -} from '../control_types/options_list/options_list_embeddable'; -import { ViewMode } from '../control_group/types'; export default { title: 'Controls', @@ -31,7 +32,10 @@ export default { type UnwrapPromise = T extends Promise ? P : T; type EmbeddableType = UnwrapPromise>; -const EmptyControlGroupStoryComponent: FC<{ +injectStorybookDataView(storybookFlightsDataView); +replaceValueSuggestionMethod(getFlightOptionsAsync); + +const ControlGroupStoryComponent: FC<{ panels?: ControlsPanels; edit?: boolean; }> = ({ panels, edit }) => { @@ -54,13 +58,10 @@ const EmptyControlGroupStoryComponent: FC<{ useEffectOnce(() => { (async () => { - const factory = new ControlGroupContainerFactory(); + const factory = new ControlGroupContainerFactory( + {} as unknown as EmbeddablePersistableStateService + ); const controlGroupContainerEmbeddable = await factory.create({ - inheritParentState: { - useQuery: false, - useFilters: false, - useTimerange: false, - }, controlStyle: 'oneLine', panels: panels ?? {}, id: uuid.v4(), @@ -102,9 +103,9 @@ const EmptyControlGroupStoryComponent: FC<{ ); }; -export const EmptyControlGroupStory = () => ; +export const EmptyControlGroupStory = () => ; export const ConfiguredControlGroupStory = () => ( - ( explicitInput: { title: 'Origin City', id: 'optionsList1', - indexPattern: { - title: 'demo data flights', - }, - field: { - name: 'OriginCityName', - type: 'string', - aggregatable: true, - }, + dataViewId: 'demoDataFlights', + fieldName: 'OriginCityName', selectedOptions: ['Toronto'], } as OptionsListEmbeddableInput, }, @@ -131,14 +126,8 @@ export const ConfiguredControlGroupStory = () => ( explicitInput: { title: 'Destination City', id: 'optionsList2', - indexPattern: { - title: 'demo data flights', - }, - field: { - name: 'DestCityName', - type: 'string', - aggregatable: true, - }, + dataViewId: 'demoDataFlights', + fieldName: 'DestCityName', selectedOptions: ['London'], } as OptionsListEmbeddableInput, }, @@ -149,14 +138,8 @@ export const ConfiguredControlGroupStory = () => ( explicitInput: { title: 'Carrier', id: 'optionsList3', - indexPattern: { - title: 'demo data flights', - }, - field: { - name: 'Carrier', - type: 'string', - aggregatable: true, - }, + dataViewId: 'demoDataFlights', + fieldName: 'Carrier', } as OptionsListEmbeddableInput, }, }} diff --git a/src/plugins/presentation_util/public/components/controls/__stories__/controls_service_stub.ts b/src/plugins/presentation_util/public/components/controls/__stories__/controls_service_stub.ts deleted file mode 100644 index 3f89e2e549d2a..0000000000000 --- a/src/plugins/presentation_util/public/components/controls/__stories__/controls_service_stub.ts +++ /dev/null @@ -1,29 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { ControlsService } from '../controls_service'; -import { InputControlFactory } from '../../../services/controls'; -import { flightFields, getFlightSearchOptions } from './flights'; -import { OptionsListEmbeddableFactory } from '../control_types/options_list'; - -export const getControlsServiceStub = () => { - const controlsServiceStub = new ControlsService(); - - const optionsListFactoryStub = new OptionsListEmbeddableFactory( - ({ field, search }) => - new Promise((r) => setTimeout(() => r(getFlightSearchOptions(field.name, search)), 120)), - () => Promise.resolve([{ title: 'demo data flights', fields: [] }]), - () => Promise.resolve(flightFields) - ); - - // cast to unknown because the stub cannot use the embeddable start contract to transform the EmbeddableFactoryDefinition into an EmbeddableFactory - const optionsListControlFactory = optionsListFactoryStub as unknown as InputControlFactory; - optionsListControlFactory.getDefaultInput = () => ({}); - controlsServiceStub.registerInputControlType(optionsListControlFactory); - return controlsServiceStub; -}; diff --git a/src/plugins/presentation_util/public/components/controls/__stories__/fixtures/flights.ts b/src/plugins/presentation_util/public/components/controls/__stories__/fixtures/flights.ts new file mode 100644 index 0000000000000..921b7f3999faa --- /dev/null +++ b/src/plugins/presentation_util/public/components/controls/__stories__/fixtures/flights.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { map, uniq } from 'lodash'; +import { flights } from '../fixtures/flights_data'; +import { + DataView, + DataViewField, + IIndexPatternFieldList, +} from '../../../../../../data_views/common'; + +export type Flight = typeof flights[number]; +export type FlightField = keyof Flight; + +export const flightFieldNames: FlightField[] = [ + 'AvgTicketPrice', + 'Cancelled', + 'Carrier', + 'dayOfWeek', + 'Dest', + 'DestAirportID', + 'DestCityName', + 'DestCountry', + 'DestLocation', + 'DestRegion', + 'DestWeather', + 'DistanceKilometers', + 'DistanceMiles', + 'FlightDelay', + 'FlightDelayMin', + 'FlightDelayType', + 'FlightNum', + 'FlightTimeHour', + 'FlightTimeMin', + 'Origin', + 'OriginAirportID', + 'OriginCityName', + 'OriginCountry', + 'OriginLocation', + 'OriginRegion', + 'OriginWeather', + 'timestamp', +]; + +export const flightFieldByName: { [key: string]: DataViewField } = {}; +flightFieldNames.forEach( + (flightFieldName) => + (flightFieldByName[flightFieldName] = { + name: flightFieldName, + type: 'string', + aggregatable: true, + } as unknown as DataViewField) +); +flightFieldByName.Cancelled = { name: 'Cancelled', type: 'boolean' } as DataViewField; +flightFieldByName.timestamp = { name: 'timestamp', type: 'date' } as DataViewField; + +export const flightFields: DataViewField[] = Object.values(flightFieldByName); + +export const storybookFlightsDataView: DataView = { + id: 'demoDataFlights', + title: 'demo data flights', + fields: flightFields as unknown as IIndexPatternFieldList, + getFieldByName: (name: string) => flightFieldByName[name], +} as unknown as DataView; + +export const getFlightOptions = (field: string) => uniq(map(flights, field)).sort(); + +export const getFlightSearchOptions = (field: string, search?: string): string[] => { + const options = getFlightOptions(field) + .map((option) => option + '') + .filter((option) => !search || option.toLowerCase().includes(search.toLowerCase())); + if (options.length > 10) options.length = 10; + return options; +}; + +export const getFlightOptionsAsync = ({ field, query }: { field: DataViewField; query: string }) => + new Promise((r) => setTimeout(() => r(getFlightSearchOptions(field.name, query)), 120)); diff --git a/src/plugins/presentation_util/public/components/fixtures/flights.ts b/src/plugins/presentation_util/public/components/controls/__stories__/fixtures/flights_data.ts similarity index 100% rename from src/plugins/presentation_util/public/components/fixtures/flights.ts rename to src/plugins/presentation_util/public/components/controls/__stories__/fixtures/flights_data.ts diff --git a/src/plugins/presentation_util/public/components/controls/__stories__/flights.ts b/src/plugins/presentation_util/public/components/controls/__stories__/flights.ts deleted file mode 100644 index 941b91c0c92f1..0000000000000 --- a/src/plugins/presentation_util/public/components/controls/__stories__/flights.ts +++ /dev/null @@ -1,59 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { map, uniq } from 'lodash'; -import { flights } from '../../fixtures/flights'; - -export type Flight = typeof flights[number]; -export type FlightField = keyof Flight; - -export const getFlightOptions = (field: string) => uniq(map(flights, field)).sort(); - -export const getFlightSearchOptions = (field: string, search?: string): string[] => { - const options = getFlightOptions(field) - .map((option) => option + '') - .filter((option) => !search || option.toLowerCase().includes(search.toLowerCase())); - if (options.length > 10) options.length = 10; - return options; -}; - -export const flightFieldLabels: Record = { - AvgTicketPrice: 'Average Ticket Price', - Cancelled: 'Cancelled', - Carrier: 'Carrier', - dayOfWeek: 'Day of Week', - Dest: 'Destination', - DestAirportID: 'Destination Airport ID', - DestCityName: 'Destination City', - DestCountry: 'Destination Country', - DestLocation: 'Destination Location', - DestRegion: 'Destination Region', - DestWeather: 'Destination Weather', - DistanceKilometers: 'Distance (km)', - DistanceMiles: 'Distance (mi)', - FlightDelay: 'Flight Delay', - FlightDelayMin: 'Flight Delay (min)', - FlightDelayType: 'Flight Delay Type', - FlightNum: 'Flight Number', - FlightTimeHour: 'Flight Time (hr)', - FlightTimeMin: 'Flight Time (min)', - Origin: 'Origin', - OriginAirportID: 'Origin Airport ID', - OriginCityName: 'Origin City', - OriginCountry: 'Origin Country', - OriginLocation: 'Origin Location', - OriginRegion: 'Origin Region', - OriginWeather: 'Origin Weather', - timestamp: 'Timestamp', -}; - -export const flightFields = Object.keys(flightFieldLabels).map((field) => ({ - name: field, - type: 'string', - aggregatable: true, -})); diff --git a/src/plugins/presentation_util/public/components/controls/__stories__/storybook_control_factories.ts b/src/plugins/presentation_util/public/components/controls/__stories__/storybook_control_factories.ts index deb5b85336f27..e4429c1d69b13 100644 --- a/src/plugins/presentation_util/public/components/controls/__stories__/storybook_control_factories.ts +++ b/src/plugins/presentation_util/public/components/controls/__stories__/storybook_control_factories.ts @@ -6,28 +6,17 @@ * Side Public License, v 1. */ -import { flightFields, getFlightSearchOptions } from './flights'; import { OptionsListEmbeddableFactory } from '../control_types/options_list'; -import { InputControlFactory, PresentationControlsService } from '../../../services/controls'; +import { PresentationControlsService } from '../../../services/controls'; +import { ControlFactory } from '..'; export const populateStorybookControlFactories = ( controlsServiceStub: PresentationControlsService ) => { - const optionsListFactoryStub = new OptionsListEmbeddableFactory( - ({ field, search }) => - new Promise((r) => setTimeout(() => r(getFlightSearchOptions(field.name, search)), 120)), - () => - Promise.resolve([ - { - title: 'demo data flights', - fields: [], - }, - ]), - () => Promise.resolve(flightFields) - ); + const optionsListFactoryStub = new OptionsListEmbeddableFactory(); // cast to unknown because the stub cannot use the embeddable start contract to transform the EmbeddableFactoryDefinition into an EmbeddableFactory - const optionsListControlFactory = optionsListFactoryStub as unknown as InputControlFactory; + const optionsListControlFactory = optionsListFactoryStub as unknown as ControlFactory; optionsListControlFactory.getDefaultInput = () => ({}); - controlsServiceStub.registerInputControlType(optionsListControlFactory); + controlsServiceStub.registerControlType(optionsListControlFactory); }; diff --git a/src/plugins/presentation_util/public/components/controls/control_group/component/control_frame_component.tsx b/src/plugins/presentation_util/public/components/controls/control_group/component/control_frame_component.tsx index 7d8893cb6b5a5..f94d2f8fee0dc 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/component/control_frame_component.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/component/control_frame_component.tsx @@ -13,6 +13,7 @@ import { EuiFormControlLayout, EuiFormLabel, EuiFormRow, + EuiLoadingChart, EuiToolTip, } from '@elastic/eui'; @@ -52,7 +53,9 @@ export const ControlFrame = ({ customPrepend, enableActions, embeddableId }: Con embeddable.render(embeddableRoot.current); } const subscription = embeddable?.getInput$().subscribe((newInput) => setTitle(newInput.title)); - return () => subscription?.unsubscribe(); + return () => { + subscription?.unsubscribe(); + }; }, [embeddable, embeddableRoot]); const floatingActions = ( @@ -87,13 +90,18 @@ export const ControlFrame = ({ customPrepend, enableActions, embeddableId }: Con
); + const embeddableParentClassNames = classNames('controlFrame__control', { + 'controlFrame--twoLine': controlStyle === 'twoLine', + 'controlFrame--oneLine': controlStyle === 'oneLine', + }); + const form = ( - {customPrepend ?? null} + {(embeddable && customPrepend) ?? null} {usingTwoLineLayout ? undefined : ( {title} @@ -102,21 +110,34 @@ export const ControlFrame = ({ customPrepend, enableActions, embeddableId }: Con } > -
+ {embeddable && ( +
+ )} + {!embeddable && ( +
+
+ +
+
+ )} ); return ( <> - {enableActions && floatingActions} - + {embeddable && enableActions && floatingActions} + {form} diff --git a/src/plugins/presentation_util/public/components/controls/control_group/component/control_group_component.tsx b/src/plugins/presentation_util/public/components/controls/control_group/component/control_group_component.tsx index 86bcd7de425e0..16ae4c1858660 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/component/control_group_component.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/component/control_group_component.tsx @@ -36,15 +36,16 @@ import { LayoutMeasuringStrategy, } from '@dnd-kit/core'; -import { ControlGroupInput, ViewMode } from '../types'; +import { ControlGroupInput } from '../types'; import { pluginServices } from '../../../../services'; import { ControlGroupStrings } from '../control_group_strings'; import { CreateControlButton } from '../editor/create_control'; +import { ViewMode } from '../../../../../../embeddable/public'; import { EditControlGroup } from '../editor/edit_control_group'; import { forwardAllContext } from '../editor/forward_all_context'; +import { controlGroupReducers } from '../state/control_group_reducers'; import { ControlClone, SortableControl } from './control_group_sortable_item'; import { useReduxContainerContext } from '../../../redux_embeddables/redux_embeddable_context'; -import { controlGroupReducers } from '../state/control_group_reducers'; export const ControlGroup = () => { // Presentation Services Context diff --git a/src/plugins/presentation_util/public/components/controls/control_group/control_group.scss b/src/plugins/presentation_util/public/components/controls/control_group/control_group.scss index 00a135c65a75e..c69674df29616 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/control_group.scss +++ b/src/plugins/presentation_util/public/components/controls/control_group/control_group.scss @@ -118,6 +118,13 @@ $controlMinWidth: $euiSize * 14; width: 100%; } } + + .controlFrame--controlLoading { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } } &--small { diff --git a/src/plugins/presentation_util/public/components/controls/control_group/control_group_strings.ts b/src/plugins/presentation_util/public/components/controls/control_group/control_group_strings.ts index 657add5ef048f..111b247d7417e 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/control_group_strings.ts +++ b/src/plugins/presentation_util/public/components/controls/control_group/control_group_strings.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; export const ControlGroupStrings = { getEmbeddableTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.title', { + i18n.translate('presentationUtil.controls.controlGroup.title', { defaultMessage: 'Control group', }), emptyState: { @@ -25,6 +25,10 @@ export const ControlGroupStrings = { defaultMessage: 'Add control', } ), + getTwoLineLoadingTitle: () => + i18n.translate('presentationUtil.inputControls.controlGroup.emptyState.twoLineLoadingTitle', { + defaultMessage: '...', + }), }, manageControl: { getFlyoutCreateTitle: () => @@ -39,7 +43,7 @@ export const ControlGroupStrings = { defaultMessage: 'Edit control', }), getTitleInputTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.manageControl.titleInputTitle', { + i18n.translate('presentationUtil.controls.controlGroup.manageControl.titleInputTitle', { defaultMessage: 'Title', }), getWidthInputTitle: () => @@ -47,17 +51,17 @@ export const ControlGroupStrings = { defaultMessage: 'Control size', }), getSaveChangesTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.manageControl.saveChangesTitle', { + i18n.translate('presentationUtil.controls.controlGroup.manageControl.saveChangesTitle', { defaultMessage: 'Save and close', }), getCancelTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.manageControl.cancelTitle', { + i18n.translate('presentationUtil.controls.controlGroup.manageControl.cancelTitle', { defaultMessage: 'Cancel', }), }, management: { getAddControlTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.addControl', { + i18n.translate('presentationUtil.controls.controlGroup.management.addControl', { defaultMessage: 'Add control', }), getManageButtonTitle: () => @@ -73,11 +77,11 @@ export const ControlGroupStrings = { defaultMessage: 'Default size', }), getLayoutTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.layoutTitle', { + i18n.translate('presentationUtil.controls.controlGroup.management.layoutTitle', { defaultMessage: 'Layout', }), getDeleteButtonTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.delete', { + i18n.translate('presentationUtil.controls.controlGroup.management.delete', { defaultMessage: 'Delete control', }), getSetAllWidthsToDefaultTitle: () => @@ -85,38 +89,38 @@ export const ControlGroupStrings = { defaultMessage: 'Set all sizes to default', }), getDeleteAllButtonTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.deleteAll', { + i18n.translate('presentationUtil.controls.controlGroup.management.deleteAll', { defaultMessage: 'Delete all', }), controlWidth: { getWidthSwitchLegend: () => i18n.translate( - 'presentationUtil.inputControls.controlGroup.management.layout.controlWidthLegend', + 'presentationUtil.controls.controlGroup.management.layout.controlWidthLegend', { defaultMessage: 'Change control size', } ), getAutoWidthTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.layout.auto', { + i18n.translate('presentationUtil.controls.controlGroup.management.layout.auto', { defaultMessage: 'Auto', }), getSmallWidthTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.layout.small', { + i18n.translate('presentationUtil.controls.controlGroup.management.layout.small', { defaultMessage: 'Small', }), getMediumWidthTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.layout.medium', { + i18n.translate('presentationUtil.controls.controlGroup.management.layout.medium', { defaultMessage: 'Medium', }), getLargeWidthTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.layout.large', { + i18n.translate('presentationUtil.controls.controlGroup.management.layout.large', { defaultMessage: 'Large', }), }, controlStyle: { getDesignSwitchLegend: () => i18n.translate( - 'presentationUtil.inputControls.controlGroup.management.layout.designSwitchLegend', + 'presentationUtil.controls.controlGroup.management.layout.designSwitchLegend', { defaultMessage: 'Switch control designs', } @@ -132,29 +136,23 @@ export const ControlGroupStrings = { }, deleteControls: { getDeleteAllTitle: () => - i18n.translate( - 'presentationUtil.inputControls.controlGroup.management.delete.deleteAllTitle', - { - defaultMessage: 'Delete all controls?', - } - ), + i18n.translate('presentationUtil.controls.controlGroup.management.delete.deleteAllTitle', { + defaultMessage: 'Delete all controls?', + }), getDeleteTitle: () => - i18n.translate( - 'presentationUtil.inputControls.controlGroup.management.delete.deleteTitle', - { - defaultMessage: 'Delete control?', - } - ), + i18n.translate('presentationUtil.controls.controlGroup.management.delete.deleteTitle', { + defaultMessage: 'Delete control?', + }), getSubtitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.delete.sub', { + i18n.translate('presentationUtil.controls.controlGroup.management.delete.sub', { defaultMessage: 'Controls are not recoverable once removed.', }), getConfirm: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.delete.confirm', { + i18n.translate('presentationUtil.controls.controlGroup.management.delete.confirm', { defaultMessage: 'Delete', }), getCancel: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.delete.cancel', { + i18n.translate('presentationUtil.controls.controlGroup.management.delete.cancel', { defaultMessage: 'Cancel', }), }, @@ -172,7 +170,7 @@ export const ControlGroupStrings = { defaultMessage: 'Discard changes', }), getCancel: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.discard.cancel', { + i18n.translate('presentationUtil.controls.controlGroup.management.discard.cancel', { defaultMessage: 'Cancel', }), }, @@ -190,7 +188,7 @@ export const ControlGroupStrings = { defaultMessage: 'Discard control', }), getCancel: () => - i18n.translate('presentationUtil.inputControls.controlGroup.management.deleteNew.cancel', { + i18n.translate('presentationUtil.controls.controlGroup.management.deleteNew.cancel', { defaultMessage: 'Cancel', }), }, @@ -201,7 +199,7 @@ export const ControlGroupStrings = { defaultMessage: 'Edit control', }), getRemoveButtonTitle: () => - i18n.translate('presentationUtil.inputControls.controlGroup.floatingActions.removeTitle', { + i18n.translate('presentationUtil.controls.controlGroup.floatingActions.removeTitle', { defaultMessage: 'Remove control', }), }, diff --git a/src/plugins/presentation_util/public/components/controls/control_group/editor/control_editor.tsx b/src/plugins/presentation_util/public/components/controls/control_group/editor/control_editor.tsx index a55dd381857b7..0fdcba570c941 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/editor/control_editor.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/editor/control_editor.tsx @@ -14,7 +14,7 @@ * Side Public License, v 1. */ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { EuiFlyoutHeader, EuiButtonGroup, @@ -32,39 +32,48 @@ import { } from '@elastic/eui'; import { ControlGroupStrings } from '../control_group_strings'; -import { ControlEditorComponent, ControlWidth } from '../../types'; -import { CONTROL_WIDTH_OPTIONS } from '../control_group_constants'; +import { + ControlEmbeddable, + ControlInput, + ControlWidth, + IEditableControlFactory, +} from '../../types'; +import { CONTROL_WIDTH_OPTIONS } from './editor_constants'; -interface ManageControlProps { - title?: string; +interface EditControlProps { + factory: IEditableControlFactory; + embeddable?: ControlEmbeddable; + width: ControlWidth; isCreate: boolean; + title?: string; onSave: () => void; - width: ControlWidth; onCancel: () => void; removeControl?: () => void; - controlEditorComponent?: ControlEditorComponent; - updateTitle: (title: string) => void; + updateTitle: (title?: string) => void; updateWidth: (newWidth: ControlWidth) => void; + onTypeEditorChange: (partial: Partial) => void; } export const ControlEditor = ({ - controlEditorComponent, + onTypeEditorChange, removeControl, updateTitle, updateWidth, + embeddable, isCreate, onCancel, + factory, onSave, title, width, -}: ManageControlProps) => { +}: EditControlProps) => { const [currentTitle, setCurrentTitle] = useState(title); const [currentWidth, setCurrentWidth] = useState(width); const [controlEditorValid, setControlEditorValid] = useState(false); - const [editorValid, setEditorValid] = useState(false); + const [defaultTitle, setDefaultTitle] = useState(); - useEffect(() => setEditorValid(Boolean(currentTitle)), [currentTitle]); + const ControlTypeEditor = factory.controlEditorComponent; return ( <> @@ -79,17 +88,6 @@ export const ControlEditor = ({ - - { - updateTitle(e.target.value); - setCurrentTitle(e.target.value); - }} - aria-label="Use aria labels when no actual label is in use" - /> - - {controlEditorComponent && - controlEditorComponent({ setValidState: setControlEditorValid })} + {ControlTypeEditor && ( + { + if (!currentTitle || currentTitle === defaultTitle) { + setCurrentTitle(newDefaultTitle); + updateTitle(newDefaultTitle); + } + setDefaultTitle(newDefaultTitle); + }} + /> + )} + + { + updateTitle(e.target.value || defaultTitle); + setCurrentTitle(e.target.value); + }} + /> + {removeControl && ( { - onSave(); - }} + disabled={!controlEditorValid} + onClick={() => onSave()} > {ControlGroupStrings.manageControl.getSaveChangesTitle()} diff --git a/src/plugins/presentation_util/public/components/controls/control_group/editor/create_control.tsx b/src/plugins/presentation_util/public/components/controls/control_group/editor/create_control.tsx index 150977c113cd7..3676fe6617e1b 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/editor/create_control.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/editor/create_control.tsx @@ -20,19 +20,18 @@ import { ControlGroupInput } from '../types'; import { ControlEditor } from './control_editor'; import { pluginServices } from '../../../../services'; import { forwardAllContext } from './forward_all_context'; +import { DEFAULT_CONTROL_WIDTH } from './editor_constants'; import { OverlayRef } from '../../../../../../../core/public'; import { ControlGroupStrings } from '../control_group_strings'; -import { InputControlInput } from '../../../../services/controls'; -import { DEFAULT_CONTROL_WIDTH } from '../control_group_constants'; -import { ControlWidth, IEditableControlFactory } from '../../types'; import { controlGroupReducers } from '../state/control_group_reducers'; +import { ControlWidth, IEditableControlFactory, ControlInput } from '../../types'; import { EmbeddableFactoryNotFoundError } from '../../../../../../embeddable/public'; import { useReduxContainerContext } from '../../../redux_embeddables/redux_embeddable_context'; export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) => { // Presentation Services Context const { overlays, controls } = pluginServices.getHooks(); - const { getInputControlTypes, getControlFactory } = controls.useService(); + const { getControlTypes, getControlFactory } = controls.useService(); const { openFlyout, openConfirm } = overlays.useService(); // Redux embeddable container Context @@ -56,8 +55,8 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) const factory = getControlFactory(type); if (!factory) throw new EmbeddableFactoryNotFoundError(type); - const initialInputPromise = new Promise>((resolve, reject) => { - let inputToReturn: Partial = {}; + const initialInputPromise = new Promise>((resolve, reject) => { + let inputToReturn: Partial = {}; const onCancel = (ref: OverlayRef) => { if (Object.keys(inputToReturn).length === 0) { @@ -78,19 +77,23 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) }); }; + const editableFactory = factory as IEditableControlFactory; + const flyoutInstance = openFlyout( forwardAllContext( (inputToReturn.title = newTitle)} updateWidth={(newWidth) => dispatch(setDefaultControlWidth(newWidth as ControlWidth))} - controlEditorComponent={(factory as IEditableControlFactory).getControlEditor?.({ - onChange: (partialInput) => { - inputToReturn = { ...inputToReturn, ...partialInput }; - }, - })} + onTypeEditorChange={(partialInput) => + (inputToReturn = { ...inputToReturn, ...partialInput }) + } onSave={() => { + if (editableFactory.presaveTransformFunction) { + inputToReturn = editableFactory.presaveTransformFunction(inputToReturn); + } resolve(inputToReturn); flyoutInstance.close(); }} @@ -103,6 +106,7 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) } ); }); + initialInputPromise.then( async (explicitInput) => { await addNewEmbeddable(type, explicitInput); @@ -111,7 +115,7 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) ); }; - if (getInputControlTypes().length === 0) return null; + if (getControlTypes().length === 0) return null; const commonButtonProps = { iconType: 'plusInCircle', @@ -121,11 +125,11 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) }; const onCreateButtonClick = () => { - if (getInputControlTypes().length > 1) { + if (getControlTypes().length > 1) { setIsControlTypePopoverOpen(!isControlTypePopoverOpen); return; } - createNewControl(getInputControlTypes()[0]); + createNewControl(getControlTypes()[0]); }; const createControlButton = isIconButton ? ( @@ -141,9 +145,9 @@ export const CreateControlButton = ({ isIconButton }: { isIconButton: boolean }) ); - if (getInputControlTypes().length > 1) { + if (getControlTypes().length > 1) { const items: ReactElement[] = []; - getInputControlTypes().forEach((type) => { + getControlTypes().forEach((type) => { const factory = getControlFactory(type); items.push( { // Presentation Services Context @@ -55,7 +54,7 @@ export const EditControlButton = ({ embeddableId }: { embeddableId: string }) => const factory = getControlFactory(panel.type); const embeddable = await untilEmbeddableLoaded(embeddableId); - let inputToReturn: Partial = {}; + let inputToReturn: Partial = {}; if (!factory) throw new EmbeddableFactoryNotFoundError(panel.type); @@ -85,12 +84,29 @@ export const EditControlButton = ({ embeddableId }: { embeddableId: string }) => }); }; + const editableFactory = factory as IEditableControlFactory; + const flyoutInstance = openFlyout( forwardAllContext( onCancel(flyoutInstance)} + updateTitle={(newTitle) => (inputToReturn.title = newTitle)} + updateWidth={(newWidth) => dispatch(setControlWidth({ width: newWidth, embeddableId }))} + onTypeEditorChange={(partialInput) => + (inputToReturn = { ...inputToReturn, ...partialInput }) + } + onSave={() => { + if (editableFactory.presaveTransformFunction) { + inputToReturn = editableFactory.presaveTransformFunction(inputToReturn, embeddable); + } + updateInputForChild(embeddableId, inputToReturn); + flyoutInstance.close(); + }} removeControl={() => { openConfirm(ControlGroupStrings.management.deleteControls.getSubtitle(), { confirmButtonText: ControlGroupStrings.management.deleteControls.getConfirm(), @@ -105,19 +121,6 @@ export const EditControlButton = ({ embeddableId }: { embeddableId: string }) => } }); }} - updateTitle={(newTitle) => (inputToReturn.title = newTitle)} - controlEditorComponent={(factory as IEditableControlFactory).getControlEditor?.({ - onChange: (partialInput) => { - inputToReturn = { ...inputToReturn, ...partialInput }; - }, - initialInput: embeddable.getInput(), - })} - onCancel={() => onCancel(flyoutInstance)} - onSave={() => { - updateInputForChild(embeddableId, inputToReturn); - flyoutInstance.close(); - }} - updateWidth={(newWidth) => dispatch(setControlWidth({ width: newWidth, embeddableId }))} />, reduxContainerContext ), diff --git a/src/plugins/presentation_util/public/components/controls/control_group/editor/edit_control_group.tsx b/src/plugins/presentation_util/public/components/controls/control_group/editor/edit_control_group.tsx index 681af9c10ba20..9828f6317ad53 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/editor/edit_control_group.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/editor/edit_control_group.tsx @@ -26,7 +26,7 @@ import { CONTROL_LAYOUT_OPTIONS, CONTROL_WIDTH_OPTIONS, DEFAULT_CONTROL_WIDTH, -} from '../control_group_constants'; +} from './editor_constants'; import { ControlGroupInput } from '../types'; import { pluginServices } from '../../../../services'; import { ControlStyle, ControlWidth } from '../../types'; diff --git a/src/plugins/presentation_util/public/components/controls/control_group/control_group_constants.ts b/src/plugins/presentation_util/public/components/controls/control_group/editor/editor_constants.ts similarity index 87% rename from src/plugins/presentation_util/public/components/controls/control_group/control_group_constants.ts rename to src/plugins/presentation_util/public/components/controls/control_group/editor/editor_constants.ts index 3c22b1ffbcd23..812f794efc8c3 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/control_group_constants.ts +++ b/src/plugins/presentation_util/public/components/controls/control_group/editor/editor_constants.ts @@ -6,10 +6,8 @@ * Side Public License, v 1. */ -import { ControlWidth } from '../types'; -import { ControlGroupStrings } from './control_group_strings'; - -export const CONTROL_GROUP_TYPE = 'control_group'; +import { ControlWidth } from '../../types'; +import { ControlGroupStrings } from '../control_group_strings'; export const DEFAULT_CONTROL_WIDTH: ControlWidth = 'auto'; diff --git a/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container.tsx b/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container.tsx index a722bed6c07d2..ff25286a75211 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container.tsx @@ -7,23 +7,60 @@ */ import React from 'react'; +import { uniqBy } from 'lodash'; import ReactDOM from 'react-dom'; +import deepEqual from 'fast-deep-equal'; +import { Filter, uniqFilters } from '@kbn/es-query'; +import { EMPTY, merge, pipe, Subscription, concat } from 'rxjs'; +import { + distinctUntilChanged, + debounceTime, + catchError, + switchMap, + map, + take, +} from 'rxjs/operators'; import { - InputControlEmbeddable, - InputControlInput, - InputControlOutput, -} from '../../../../services/controls'; + ControlGroupInput, + ControlGroupOutput, + ControlPanelState, + CONTROL_GROUP_TYPE, +} from '../types'; import { pluginServices } from '../../../../services'; -import { ControlGroupInput, ControlPanelState } from '../types'; +import { DataView } from '../../../../../../data_views/public'; import { ControlGroup } from '../component/control_group_component'; import { controlGroupReducers } from '../state/control_group_reducers'; +import { ControlEmbeddable, ControlInput, ControlOutput } from '../../types'; import { Container, EmbeddableFactory } from '../../../../../../embeddable/public'; -import { CONTROL_GROUP_TYPE, DEFAULT_CONTROL_WIDTH } from '../control_group_constants'; import { ReduxEmbeddableWrapper } from '../../../redux_embeddables/redux_embeddable_wrapper'; +import { DEFAULT_CONTROL_WIDTH } from '../editor/editor_constants'; -export class ControlGroupContainer extends Container { +export class ControlGroupContainer extends Container< + ControlInput, + ControlGroupInput, + ControlGroupOutput +> { public readonly type = CONTROL_GROUP_TYPE; + private subscriptions: Subscription = new Subscription(); + private domNode?: HTMLElement; + + public untilReady = () => { + const panelsLoading = () => + Object.values(this.getOutput().embeddableLoaded).some((loaded) => !loaded); + if (panelsLoading()) { + return new Promise((resolve, reject) => { + const subscription = merge(this.getOutput$(), this.getInput$()).subscribe(() => { + if (this.destroyed) reject(); + if (!panelsLoading()) { + subscription.unsubscribe(); + resolve(); + } + }); + }); + } + return Promise.resolve(); + }; constructor(initialInput: ControlGroupInput, parent?: Container) { super( @@ -32,10 +69,44 @@ export class ControlGroupContainer extends Container this.getChildIds()), + distinctUntilChanged(deepEqual), + + // children may change, so make sure we subscribe/unsubscribe with switchMap + switchMap((newChildIds: string[]) => + merge( + ...newChildIds.map((childId) => + this.getChild(childId) + .getOutput$() + // Embeddables often throw errors into their output streams. + .pipe(catchError(() => EMPTY)) + ) + ) + ) + ); + + this.subscriptions.add( + concat( + merge(this.getOutput$(), this.getOutput$().pipe(anyChildChangePipe)).pipe(take(1)), // the first time filters are built, don't debounce so that initial filters are built immediately + merge(this.getOutput$(), this.getOutput$().pipe(anyChildChangePipe)).pipe(debounceTime(10)) + ).subscribe(this.recalculateOutput) + ); } - protected createNewPanelState( - factory: EmbeddableFactory, + private recalculateOutput = () => { + const allFilters: Filter[] = []; + const allDataViews: DataView[] = []; + Object.values(this.children).map((child) => { + const childOutput = child.getOutput() as ControlOutput; + allFilters.push(...(childOutput?.filters ?? [])); + allDataViews.push(...(childOutput.dataViews ?? [])); + }); + this.updateOutput({ filters: uniqFilters(allFilters), dataViews: uniqBy(allDataViews, 'id') }); + }; + + protected createNewPanelState( + factory: EmbeddableFactory, partial: Partial = {} ): ControlPanelState { const panelState = super.createNewPanelState(factory, partial); @@ -50,17 +121,27 @@ export class ControlGroupContainer extends Container; } - protected getInheritedInput(id: string): InputControlInput { - const { filters, query, timeRange, inheritParentState } = this.getInput(); + protected getInheritedInput(id: string): ControlInput { + const { filters, query, ignoreParentSettings, timeRange } = this.getInput(); return { - filters: inheritParentState.useFilters ? filters : undefined, - query: inheritParentState.useQuery ? query : undefined, - timeRange: inheritParentState.useTimerange ? timeRange : undefined, + filters: ignoreParentSettings?.ignoreFilters ? undefined : filters, + query: ignoreParentSettings?.ignoreQuery ? undefined : query, + timeRange: ignoreParentSettings?.ignoreTimerange ? undefined : timeRange, id, }; } + public destroy() { + super.destroy(); + this.subscriptions.unsubscribe(); + if (this.domNode) ReactDOM.unmountComponentAtNode(this.domNode); + } + public render(dom: HTMLElement) { + if (this.domNode) { + ReactDOM.unmountComponentAtNode(this.domNode); + } + this.domNode = dom; const PresentationUtilProvider = pluginServices.getContextProvider(); ReactDOM.render( diff --git a/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container_factory.ts b/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container_factory.ts index e50b1c5d734e4..c5b2972bf0d97 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container_factory.ts +++ b/src/plugins/presentation_util/public/components/controls/control_group/embeddable/control_group_container_factory.ts @@ -14,29 +14,21 @@ * Side Public License, v 1. */ -import { - Container, - ContainerOutput, - EmbeddableFactory, - EmbeddableFactoryDefinition, - ErrorEmbeddable, -} from '../../../../../../embeddable/public'; -import { ControlGroupInput } from '../types'; +import { Container, EmbeddableFactoryDefinition } from '../../../../../../embeddable/public'; +import { EmbeddablePersistableStateService } from '../../../../../../embeddable/common'; +import { ControlGroupInput, CONTROL_GROUP_TYPE } from '../types'; import { ControlGroupStrings } from '../control_group_strings'; -import { CONTROL_GROUP_TYPE } from '../control_group_constants'; -import { ControlGroupContainer } from './control_group_container'; - -export type DashboardContainerFactory = EmbeddableFactory< - ControlGroupInput, - ContainerOutput, - ControlGroupContainer ->; -export class ControlGroupContainerFactory - implements EmbeddableFactoryDefinition -{ +import { + createControlGroupExtract, + createControlGroupInject, +} from '../../../../../common/controls/control_group/control_group_persistable_state'; + +export class ControlGroupContainerFactory implements EmbeddableFactoryDefinition { public readonly isContainerType = true; public readonly type = CONTROL_GROUP_TYPE; + constructor(private persistableStateService: EmbeddablePersistableStateService) {} + public isEditable = async () => false; public readonly getDisplayName = () => { @@ -46,18 +38,19 @@ export class ControlGroupContainerFactory public getDefaultInput(): Partial { return { panels: {}, - inheritParentState: { - useFilters: true, - useQuery: true, - useTimerange: true, + ignoreParentSettings: { + ignoreFilters: false, + ignoreQuery: false, + ignoreTimerange: false, }, }; } - public create = async ( - initialInput: ControlGroupInput, - parent?: Container - ): Promise => { + public create = async (initialInput: ControlGroupInput, parent?: Container) => { + const { ControlGroupContainer } = await import('./control_group_container'); return new ControlGroupContainer(initialInput, parent); }; + + public inject = createControlGroupInject(this.persistableStateService); + public extract = createControlGroupExtract(this.persistableStateService); } diff --git a/src/plugins/presentation_util/public/components/controls/control_group/index.ts b/src/plugins/presentation_util/public/components/controls/control_group/index.ts new file mode 100644 index 0000000000000..45a91a87a7962 --- /dev/null +++ b/src/plugins/presentation_util/public/components/controls/control_group/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { ControlGroupInput, ControlGroupOutput } from './types'; +export type { ControlGroupContainer } from './embeddable/control_group_container'; +export { ControlGroupContainerFactory } from './embeddable/control_group_container_factory'; diff --git a/src/plugins/presentation_util/public/components/controls/control_group/types.ts b/src/plugins/presentation_util/public/components/controls/control_group/types.ts index f6639b6a55bca..3d0123eb4192f 100644 --- a/src/plugins/presentation_util/public/components/controls/control_group/types.ts +++ b/src/plugins/presentation_util/public/components/controls/control_group/types.ts @@ -6,31 +6,9 @@ * Side Public License, v 1. */ -import { PanelState, EmbeddableInput, ViewMode } from '../../../../../embeddable/public'; -import { InputControlInput } from '../../../services/controls'; -import { ControlStyle, ControlWidth } from '../types'; +import { CommonControlOutput } from '../types'; +import { ContainerOutput } from '../../../../../embeddable/public'; -export { ViewMode }; +export type ControlGroupOutput = ContainerOutput & CommonControlOutput; -export interface ControlGroupInput - extends EmbeddableInput, - Omit { - inheritParentState: { - useFilters: boolean; - useQuery: boolean; - useTimerange: boolean; - }; - defaultControlWidth?: ControlWidth; - controlStyle: ControlStyle; - panels: ControlsPanels; -} - -export interface ControlPanelState - extends PanelState { - order: number; - width: ControlWidth; -} - -export interface ControlsPanels { - [panelId: string]: ControlPanelState; -} +export * from '../../../../common/controls/control_group/types'; diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/index.ts b/src/plugins/presentation_util/public/components/controls/control_types/options_list/index.ts index 63275f12076ff..f2d9c29701a5f 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/index.ts +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/index.ts @@ -7,4 +7,4 @@ */ export { OptionsListEmbeddableFactory } from './options_list_embeddable_factory'; -export { OptionsListEmbeddable } from './options_list_embeddable'; +export type { OptionsListEmbeddable } from './options_list_embeddable'; diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list.scss b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list.scss index b74a08d96c8c3..e9a4ef215733e 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list.scss +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list.scss @@ -7,24 +7,10 @@ height: 100%; } -.optionsList--loadingOverlay { - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - position: absolute; - align-items: center; - justify-content: center; - background-color: $euiColorEmptyShade; -} - .optionsList--items { @include euiScrollBar; overflow-y: auto; - position: relative; - min-height: $euiSize * 5; max-height: $euiSize * 30; width: $euiSize * 25; max-width: 100%; diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_component.tsx b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_component.tsx index 900570b38ca4d..9c8af47a1f598 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_component.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_component.tsx @@ -8,17 +8,18 @@ import { EuiFilterButton, EuiFilterGroup, EuiPopover } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { BehaviorSubject, Subject } from 'rxjs'; import classNames from 'classnames'; -import { Subject } from 'rxjs'; +import { debounce } from 'lodash'; -import { useReduxEmbeddableContext } from '../../../redux_embeddables/redux_embeddable_context'; -import { OptionsListEmbeddableInput } from './options_list_embeddable'; -import { OptionsListPopover } from './options_list_popover_component'; -import { optionsListReducers } from './options_list_reducers'; import { OptionsListStrings } from './options_list_strings'; +import { optionsListReducers } from './options_list_reducers'; +import { OptionsListPopover } from './options_list_popover_component'; +import { useReduxEmbeddableContext } from '../../../redux_embeddables/redux_embeddable_context'; import './options_list.scss'; import { useStateObservable } from '../../hooks/use_state_observable'; +import { OptionsListEmbeddableInput } from './types'; // Availableoptions and loading state is controled by the embeddable, but is not considered embeddable input. export interface OptionsListComponentState { @@ -31,7 +32,7 @@ export const OptionsListComponent = ({ componentStateSubject, }: { typeaheadSubject: Subject; - componentStateSubject: Subject; + componentStateSubject: BehaviorSubject; }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [searchString, setSearchString] = useState(''); @@ -43,15 +44,21 @@ export const OptionsListComponent = ({ actions: { replaceSelection }, } = useReduxEmbeddableContext(); const dispatch = useEmbeddableDispatch(); - const { twoLineLayout, selectedOptions, singleSelect } = useEmbeddableSelector((state) => state); + const { controlStyle, selectedOptions, singleSelect } = useEmbeddableSelector((state) => state); // useStateObservable to get component state from Embeddable const { availableOptions, loading } = useStateObservable( componentStateSubject, - { - loading: true, - } + componentStateSubject.getValue() + ); + + // debounce loading state so loading doesn't flash when user types + const [buttonLoading, setButtonLoading] = useState(true); + const debounceSetButtonLoading = useMemo( + () => debounce((latestLoading: boolean) => setButtonLoading(latestLoading), 100), + [] ); + useEffect(() => debounceSetButtonLoading(loading), [loading, debounceSetButtonLoading]); // remove all other selections if this control is single select useEffect(() => { @@ -78,13 +85,13 @@ export const OptionsListComponent = ({ const button = ( setIsPopoverOpen((openState) => !openState)} isSelected={isPopoverOpen} - numFilters={availableOptions?.length ?? 0} // Remove this once https://github.com/elastic/eui/pull/5268 is in an EUI release numActiveFilters={selectedOptionsCount} hasActiveFilters={(selectedOptionsCount ?? 0) > 0} > @@ -95,7 +102,7 @@ export const OptionsListComponent = ({ return ( ['onChange']; - fetchIndexPatterns: OptionsListIndexPatternFetcher; - initialInput?: Partial; - fetchFields: OptionsListFieldFetcher; -} +import { ControlEditorProps } from '../../types'; +import { DataViewListItem, DataView } from '../../../../../../data_views/common'; +import { DataViewPicker } from '../../../data_view_picker/data_view_picker'; +import { OptionsListStrings } from './options_list_strings'; +import { pluginServices } from '../../../../services'; +import { OptionsListEmbeddableInput } from './types'; +import { FieldPicker } from '../../../field_picker/field_picker'; interface OptionsListEditorState { singleSelect?: boolean; - indexPatternSelectOptions: Array>; - availableIndexPatterns?: { [key: string]: IIndexPattern }; - indexPattern?: IIndexPattern; + dataViewListItems: DataViewListItem[]; - fieldSelectOptions: Array>; - availableFields?: { [key: string]: IFieldType }; - field?: IFieldType; + dataView?: DataView; + fieldName?: string; } export const OptionsListEditor = ({ onChange, - fetchFields, initialInput, setValidState, - fetchIndexPatterns, -}: OptionsListEditorProps) => { + setDefaultTitle, +}: ControlEditorProps) => { + // Presentation Services Context + const { dataViews } = pluginServices.getHooks(); + const { getIdsWithTitle, getDefaultId, get } = dataViews.useService(); + const [state, setState] = useState({ - indexPattern: initialInput?.indexPattern, - field: initialInput?.field, + fieldName: initialInput?.fieldName, singleSelect: initialInput?.singleSelect, - indexPatternSelectOptions: [], - fieldSelectOptions: [], + dataViewListItems: [], }); - const applySelection = ({ - field, - singleSelect, - indexPattern, - }: { - field?: IFieldType; - singleSelect?: boolean; - indexPattern?: IIndexPattern; - }) => { - const newState = { - ...(field ? { field } : {}), - ...(indexPattern ? { indexPattern } : {}), - ...(singleSelect !== undefined ? { singleSelect } : {}), - }; - /** - * apply state and run onChange concurrently. State is copied here rather than by subscribing to embeddable - * input so that the same editor component can cover the 'create' use case. - */ - - setState((currentState) => { - return { ...currentState, ...newState }; - }); - onChange(newState); - }; - useMount(() => { + let mounted = true; + if (state.fieldName) setDefaultTitle(state.fieldName); (async () => { - const newIndexPatterns = await fetchIndexPatterns(); - const newAvailableIndexPatterns = newIndexPatterns.reduce( - (acc: { [key: string]: IIndexPattern }, curr) => ((acc[curr.title] = curr), acc), - {} - ); - const newIndexPatternSelectOptions = newIndexPatterns.map((indexPattern) => ({ - value: indexPattern.title, - inputDisplay: indexPattern.title, - })); - setState((currentState) => ({ - ...currentState, - availableIndexPatterns: newAvailableIndexPatterns, - indexPatternSelectOptions: newIndexPatternSelectOptions, - })); - })(); - }); - - useEffect(() => { - (async () => { - let newFieldSelectOptions: Array> = []; - let newAvailableFields: { [key: string]: IFieldType } = {}; - if (state.indexPattern) { - const newFields = await fetchFields(state.indexPattern); - newAvailableFields = newFields.reduce( - (acc: { [key: string]: IFieldType }, curr) => ((acc[curr.name] = curr), acc), - {} - ); - newFieldSelectOptions = newFields.map((field) => ({ - value: field.name, - inputDisplay: field.displayName ?? field.name, - })); + const dataViewListItems = await getIdsWithTitle(); + const initialId = initialInput?.dataViewId ?? (await getDefaultId()); + let dataView: DataView | undefined; + if (initialId) { + onChange({ dataViewId: initialId }); + dataView = await get(initialId); } - setState((currentState) => ({ - ...currentState, - fieldSelectOptions: newFieldSelectOptions, - availableFields: newAvailableFields, - })); + if (!mounted) return; + setState((s) => ({ ...s, dataView, dataViewListItems })); })(); - }, [state.indexPattern, fetchFields]); + return () => { + mounted = false; + }; + }); useEffect( - () => setValidState(Boolean(state.field) && Boolean(state.indexPattern)), - [state.field, setValidState, state.indexPattern] + () => setValidState(Boolean(state.fieldName) && Boolean(state.dataView)), + [state.fieldName, setValidState, state.dataView] ); + const { dataView, fieldName } = state; return ( <> - - - applySelection({ indexPattern: state.availableIndexPatterns?.[patternTitle] }) - } - valueOfSelected={state.indexPattern?.title} + + { + onChange({ dataViewId }); + get(dataViewId).then((newDataView) => + setState((s) => ({ ...s, dataView: newDataView })) + ); + }} + trigger={{ + label: state.dataView?.title ?? OptionsListStrings.editor.getNoDataViewTitle(), + }} /> - - applySelection({ field: state.availableFields?.[fieldName] })} - valueOfSelected={state.field?.name} + + + (field.aggregatable && field.type === 'string') || field.type === 'boolean' + } + selectedFieldName={fieldName} + dataView={dataView} + onSelectField={(field) => { + setDefaultTitle(field.displayName ?? field.name); + onChange({ fieldName: field.name }); + setState((s) => ({ ...s, fieldName: field.name })); + }} /> - + applySelection({ singleSelect: !e.target.checked })} + onChange={() => { + onChange({ singleSelect: !state.singleSelect }); + setState((s) => ({ ...s, singleSelect: !s.singleSelect })); + }} /> diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx index 93330772d7cad..b980ee10293e5 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable.tsx @@ -8,17 +8,29 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { isEqual } from 'lodash'; import deepEqual from 'fast-deep-equal'; -import { merge, Subject, Subscription } from 'rxjs'; +import { + buildEsQuery, + buildPhraseFilter, + buildPhrasesFilter, + compareFilters, + Filter, +} from '@kbn/es-query'; +import { merge, Subject, Subscription, BehaviorSubject } from 'rxjs'; import { tap, debounceTime, map, distinctUntilChanged, skip } from 'rxjs/operators'; -import { isEqual } from 'lodash'; import { ReduxEmbeddableWrapper } from '../../../redux_embeddables/redux_embeddable_wrapper'; -import { InputControlInput, InputControlOutput } from '../../../../services/controls'; -import { esFilters, IIndexPattern, IFieldType } from '../../../../../../data/public'; -import { Embeddable, IContainer } from '../../../../../../embeddable/public'; import { OptionsListComponent, OptionsListComponentState } from './options_list_component'; +import { PresentationDataViewsService } from '../../../../services/data_views'; +import { Embeddable, IContainer } from '../../../../../../embeddable/public'; +import { OptionsListEmbeddableInput, OPTIONS_LIST_CONTROL } from './types'; +import { PresentationDataService } from '../../../../services/data'; +import { DataView } from '../../../../../../data_views/public'; import { optionsListReducers } from './options_list_reducers'; +import { OptionsListStrings } from './options_list_strings'; +import { pluginServices } from '../../../../services'; +import { ControlInput, ControlOutput } from '../..'; const diffDataFetchProps = ( current?: OptionsListDataFetchProps, @@ -28,73 +40,64 @@ const diffDataFetchProps = ( const { filters: currentFilters, ...currentWithoutFilters } = current; const { filters: lastFilters, ...lastWithoutFilters } = last; if (!deepEqual(currentWithoutFilters, lastWithoutFilters)) return false; - if (!esFilters.compareFilters(lastFilters ?? [], currentFilters ?? [])) return false; + if (!compareFilters(lastFilters ?? [], currentFilters ?? [])) return false; return true; }; interface OptionsListDataFetchProps { search?: string; - field: IFieldType; - indexPattern: IIndexPattern; - query?: InputControlInput['query']; - filters?: InputControlInput['filters']; - timeRange?: InputControlInput['timeRange']; + fieldName: string; + dataViewId: string; + query?: ControlInput['query']; + filters?: ControlInput['filters']; } -export type OptionsListIndexPatternFetcher = () => Promise; -export type OptionsListFieldFetcher = (indexPattern: IIndexPattern) => Promise; - -export type OptionsListDataFetcher = (props: OptionsListDataFetchProps) => Promise; - -export const OPTIONS_LIST_CONTROL = 'optionsListControl'; -export interface OptionsListEmbeddableInput extends InputControlInput { - field: IFieldType; - indexPattern: IIndexPattern; - - selectedOptions?: string[]; - singleSelect?: boolean; - loading?: boolean; -} +const fieldMissingError = (fieldName: string) => + new Error(`field ${fieldName} not found in index pattern`); -export class OptionsListEmbeddable extends Embeddable< - OptionsListEmbeddableInput, - InputControlOutput -> { +export class OptionsListEmbeddable extends Embeddable { public readonly type = OPTIONS_LIST_CONTROL; + public deferEmbeddableLoad = true; + + private subscriptions: Subscription = new Subscription(); private node?: HTMLElement; - // internal state for this input control. + // Presentation Util services + private dataService: PresentationDataService; + private dataViewsService: PresentationDataViewsService; + + // Internal data fetching state for this input control. private typeaheadSubject: Subject = new Subject(); + private dataView?: DataView; private searchString = ''; + // State to be passed down to component private componentState: OptionsListComponentState; - private componentStateSubject$ = new Subject(); - private updateComponentState(changes: Partial) { - this.componentState = { - ...this.componentState, - ...changes, - }; - this.componentStateSubject$.next(this.componentState); - } + private componentStateSubject$ = new BehaviorSubject({ + loading: true, + }); - private subscriptions: Subscription = new Subscription(); + constructor(input: OptionsListEmbeddableInput, output: ControlOutput, parent?: IContainer) { + super(input, output, parent); // get filters for initial output... + + // Destructure presentation util services + ({ data: this.dataService, dataViews: this.dataViewsService } = pluginServices.getServices()); + + this.componentState = { loading: true }; + this.updateComponentState(this.componentState); - constructor( - input: OptionsListEmbeddableInput, - output: InputControlOutput, - private fetchData: OptionsListDataFetcher, - parent?: IContainer - ) { - super({ ...input, loading: true }, output, parent); - this.fetchData = fetchData; + this.initialize(); + } + private setupSubscriptions = () => { const dataFetchPipe = this.getInput$().pipe( map((newInput) => ({ - field: newInput.field, - indexPattern: newInput.indexPattern, - query: newInput.query, - filters: newInput.filters, + lastReloadRequestTime: newInput.lastReloadRequestTime, + dataViewId: newInput.dataViewId, + fieldName: newInput.fieldName, timeRange: newInput.timeRange, + filters: newInput.filters, + query: newInput.query, })), distinctUntilChanged(diffDataFetchProps) ); @@ -102,7 +105,8 @@ export class OptionsListEmbeddable extends Embeddable< // push searchString changes into a debounced typeahead subject this.typeaheadSubject = new Subject(); const typeaheadPipe = this.typeaheadSubject.pipe( - tap((newSearchString) => (this.searchString = newSearchString), debounceTime(100)) + tap((newSearchString) => (this.searchString = newSearchString)), + debounceTime(100) ); // fetch available options when input changes or when search string has changed @@ -110,45 +114,108 @@ export class OptionsListEmbeddable extends Embeddable< merge(dataFetchPipe, typeaheadPipe).subscribe(this.fetchAvailableOptions) ); - // clear all selections when field or index pattern change + // build filters when selectedOptions change this.subscriptions.add( this.getInput$() .pipe( - distinctUntilChanged( - (a, b) => isEqual(a.field, b.field) && isEqual(a.indexPattern, b.indexPattern) - ), - skip(1) // skip the first change to preserve default selections after init + debounceTime(400), + distinctUntilChanged((a, b) => isEqual(a.selectedOptions, b.selectedOptions)), + skip(1) // skip the first input update because initial filters will be built by initialize. ) - .subscribe(() => this.updateInput({ selectedOptions: [] })) + .subscribe(() => this.buildFilter()) ); + }; - this.componentState = { loading: true }; - this.updateComponentState(this.componentState); + private getCurrentDataView = async (): Promise => { + const { dataViewId } = this.getInput(); + if (this.dataView && this.dataView.id === dataViewId) return this.dataView; + this.dataView = await this.dataViewsService.get(dataViewId); + if (this.dataView === undefined) { + this.onFatalError(new Error(OptionsListStrings.errors.getDataViewNotFoundError(dataViewId))); + } + this.updateOutput({ dataViews: [this.dataView] }); + return this.dataView; + }; + + private updateComponentState(changes: Partial) { + this.componentState = { + ...this.componentState, + ...changes, + }; + this.componentStateSubject$.next(this.componentState); } private fetchAvailableOptions = async () => { this.updateComponentState({ loading: true }); - const { indexPattern, timeRange, filters, field, query } = this.getInput(); - const newOptions = await this.fetchData({ - search: this.searchString, - indexPattern, - timeRange, - filters, + const { ignoreParentSettings, filters, fieldName, query } = this.getInput(); + const dataView = await this.getCurrentDataView(); + const field = dataView.getFieldByName(fieldName); + + if (!field) throw fieldMissingError(fieldName); + + const boolFilter = [ + buildEsQuery( + dataView, + ignoreParentSettings?.ignoreQuery ? [] : query ?? [], + ignoreParentSettings?.ignoreFilters ? [] : filters ?? [] + ), + ]; + + // TODO Switch between `terms_agg` and `terms_enum` method depending on the value of ignoreParentSettings + // const method = Object.values(ignoreParentSettings || {}).includes(false) ? + + const newOptions = await this.dataService.autocomplete.getValueSuggestions({ + query: this.searchString, + indexPattern: dataView, + useTimeRange: !ignoreParentSettings?.ignoreTimerange, + method: 'terms_agg', // terms_agg method is required to use timeRange + boolFilter, field, - query, }); this.updateComponentState({ availableOptions: newOptions, loading: false }); }; - public destroy = () => { - super.destroy(); - this.subscriptions.unsubscribe(); + private initialize = async () => { + const initialSelectedOptions = this.getInput().selectedOptions; + if (initialSelectedOptions) { + await this.getCurrentDataView(); + await this.buildFilter(); + } + this.setInitializationFinished(); + this.setupSubscriptions(); + }; + + private buildFilter = async () => { + const { fieldName, selectedOptions } = this.getInput(); + if (!selectedOptions || selectedOptions.length === 0) { + this.updateOutput({ filters: [] }); + return; + } + const dataView = await this.getCurrentDataView(); + const field = dataView.getFieldByName(this.getInput().fieldName); + + if (!field) throw fieldMissingError(fieldName); + + let newFilter: Filter; + if (selectedOptions.length === 1) { + newFilter = buildPhraseFilter(field, selectedOptions[0], dataView); + } else { + newFilter = buildPhrasesFilter(field, selectedOptions, dataView); + } + + newFilter.meta.key = field?.name; + this.updateOutput({ filters: [newFilter] }); }; reload = () => { this.fetchAvailableOptions(); }; + public destroy = () => { + super.destroy(); + this.subscriptions.unsubscribe(); + }; + public render = (node: HTMLElement) => { if (this.node) { ReactDOM.unmountComponentAtNode(this.node); diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable_factory.tsx b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable_factory.tsx index 01c31a0bcbc51..cb53ac463be3f 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable_factory.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_embeddable_factory.tsx @@ -6,58 +6,51 @@ * Side Public License, v 1. */ -import React from 'react'; -import { EmbeddableFactoryDefinition, IContainer } from '../../../../../../embeddable/public'; -import { - ControlEditorProps, - GetControlEditorComponentProps, - IEditableControlFactory, -} from '../../types'; +import deepEqual from 'fast-deep-equal'; + import { OptionsListEditor } from './options_list_editor'; +import { ControlEmbeddable, IEditableControlFactory } from '../../types'; +import { OptionsListEmbeddableInput, OPTIONS_LIST_CONTROL } from './types'; +import { EmbeddableFactoryDefinition, IContainer } from '../../../../../../embeddable/public'; import { - OptionsListDataFetcher, - OptionsListEmbeddable, - OptionsListEmbeddableInput, - OptionsListFieldFetcher, - OptionsListIndexPatternFetcher, - OPTIONS_LIST_CONTROL, -} from './options_list_embeddable'; + createOptionsListExtract, + createOptionsListInject, +} from '../../../../../common/controls/control_types/options_list/options_list_persistable_state'; export class OptionsListEmbeddableFactory - implements EmbeddableFactoryDefinition, IEditableControlFactory + implements EmbeddableFactoryDefinition, IEditableControlFactory { public type = OPTIONS_LIST_CONTROL; + public canCreateNew = () => false; - constructor( - private fetchData: OptionsListDataFetcher, - private fetchIndexPatterns: OptionsListIndexPatternFetcher, - private fetchFields: OptionsListFieldFetcher - ) { - this.fetchIndexPatterns = fetchIndexPatterns; - this.fetchFields = fetchFields; - this.fetchData = fetchData; - } + constructor() {} - public create(initialInput: OptionsListEmbeddableInput, parent?: IContainer) { - return Promise.resolve(new OptionsListEmbeddable(initialInput, {}, this.fetchData, parent)); + public async create(initialInput: OptionsListEmbeddableInput, parent?: IContainer) { + const { OptionsListEmbeddable } = await import('./options_list_embeddable'); + return Promise.resolve(new OptionsListEmbeddable(initialInput, {}, parent)); } - public getControlEditor = ({ - onChange, - initialInput, - }: GetControlEditorComponentProps) => { - return ({ setValidState }: ControlEditorProps) => ( - - ); + public presaveTransformFunction = ( + newInput: Partial, + embeddable?: ControlEmbeddable + ) => { + if ( + embeddable && + (!deepEqual(newInput.fieldName, embeddable.getInput().fieldName) || + !deepEqual(newInput.dataViewId, embeddable.getInput().dataViewId)) + ) { + // if the field name or data view id has changed in this editing session, selected options are invalid, so reset them. + newInput.selectedOptions = []; + } + return newInput; }; + public controlEditorComponent = OptionsListEditor; + public isEditable = () => Promise.resolve(false); public getDisplayName = () => 'Options List Control'; + + public inject = createOptionsListInject(); + public extract = createOptionsListExtract(); } diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_popover_component.tsx b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_popover_component.tsx index 35dca40a26ab9..eb9829cd78840 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_popover_component.tsx +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_popover_component.tsx @@ -9,7 +9,6 @@ import React, { useMemo, useState } from 'react'; import { EuiFilterSelectItem, - EuiLoadingChart, EuiPopoverTitle, EuiFieldSearch, EuiButtonIcon, @@ -21,11 +20,11 @@ import { EuiIcon, } from '@elastic/eui'; +import { OptionsListEmbeddableInput } from './types'; import { OptionsListStrings } from './options_list_strings'; -import { useReduxEmbeddableContext } from '../../../redux_embeddables/redux_embeddable_context'; -import { OptionsListEmbeddableInput } from './options_list_embeddable'; import { optionsListReducers } from './options_list_reducers'; import { OptionsListComponentState } from './options_list_component'; +import { useReduxEmbeddableContext } from '../../../redux_embeddables/redux_embeddable_context'; export const OptionsListPopover = ({ loading, @@ -122,20 +121,9 @@ export const OptionsListPopover = ({ dispatch(selectOption(availableOption)); }} > - {availableOption} + {`${availableOption}`} ))} - {loading && ( -
-
-
- - -

{OptionsListStrings.popover.getLoadingMessage()}

-
-
-
- )} {!loading && (!availableOptions || availableOptions.length === 0) && (
@@ -157,7 +145,7 @@ export const OptionsListPopover = ({ key={index} onClick={() => dispatch(deselectOption(availableOption))} > - {availableOption} + {`${availableOption}`} ))} {(!selectedOptions || selectedOptions.length === 0) && ( diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_reducers.ts b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_reducers.ts index 3e4104f62f914..39f6281a11c6b 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_reducers.ts +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_reducers.ts @@ -9,7 +9,7 @@ import { PayloadAction } from '@reduxjs/toolkit'; import { WritableDraft } from 'immer/dist/types/types-external'; -import { OptionsListEmbeddableInput } from './options_list_embeddable'; +import { OptionsListEmbeddableInput } from './types'; export const optionsListReducers = { deselectOption: ( diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_strings.ts b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_strings.ts index 40828f9e335f2..52b5dc6d44910 100644 --- a/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_strings.ts +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/options_list_strings.ts @@ -11,21 +11,25 @@ import { i18n } from '@kbn/i18n'; export const OptionsListStrings = { summary: { getSeparator: () => - i18n.translate('presentationUtil.inputControls.optionsList.summary.separator', { + i18n.translate('presentationUtil.controls.optionsList.summary.separator', { defaultMessage: ', ', }), getPlaceholder: () => - i18n.translate('presentationUtil.inputControls.optionsList.summary.placeholder', { + i18n.translate('presentationUtil.controls.optionsList.summary.placeholder', { defaultMessage: 'Select...', }), }, editor: { getIndexPatternTitle: () => - i18n.translate('presentationUtil.inputControls.optionsList.editor.indexPatternTitle', { + i18n.translate('presentationUtil.controls.optionsList.editor.indexPatternTitle', { defaultMessage: 'Index pattern', }), + getNoDataViewTitle: () => + i18n.translate('presentationUtil.controls.optionsList.editor.noDataViewTitle', { + defaultMessage: 'Select data view', + }), getFieldTitle: () => - i18n.translate('presentationUtil.inputControls.optionsList.editor.fieldTitle', { + i18n.translate('presentationUtil.controls.optionsList.editor.fieldTitle', { defaultMessage: 'Field', }), getAllowMultiselectTitle: () => @@ -35,19 +39,19 @@ export const OptionsListStrings = { }, popover: { getLoadingMessage: () => - i18n.translate('presentationUtil.inputControls.optionsList.popover.loading', { + i18n.translate('presentationUtil.controls.optionsList.popover.loading', { defaultMessage: 'Loading filters', }), getEmptyMessage: () => - i18n.translate('presentationUtil.inputControls.optionsList.popover.empty', { + i18n.translate('presentationUtil.controls.optionsList.popover.empty', { defaultMessage: 'No filters found', }), getSelectionsEmptyMessage: () => - i18n.translate('presentationUtil.inputControls.optionsList.popover.selectionsEmpty', { + i18n.translate('presentationUtil.controls.optionsList.popover.selectionsEmpty', { defaultMessage: 'You have no selections', }), getAllOptionsButtonTitle: () => - i18n.translate('presentationUtil.inputControls.optionsList.popover.allOptionsTitle', { + i18n.translate('presentationUtil.controls.optionsList.popover.allOptionsTitle', { defaultMessage: 'Show all options', }), getSelectedOptionsButtonTitle: () => @@ -55,8 +59,15 @@ export const OptionsListStrings = { defaultMessage: 'Show only selected options', }), getClearAllSelectionsButtonTitle: () => - i18n.translate('presentationUtil.inputControls.optionsList.popover.clearAllSelectionsTitle', { + i18n.translate('presentationUtil.controls.optionsList.popover.clearAllSelectionsTitle', { defaultMessage: 'Clear selections', }), }, + errors: { + getDataViewNotFoundError: (dataViewId: string) => + i18n.translate('presentationUtil.controls.optionsList.errors.dataViewNotFound', { + defaultMessage: 'Could not locate data view: {dataViewId}', + values: { dataViewId }, + }), + }, }; diff --git a/src/plugins/presentation_util/public/components/controls/control_types/options_list/types.ts b/src/plugins/presentation_util/public/components/controls/control_types/options_list/types.ts new file mode 100644 index 0000000000000..06b6526f38db4 --- /dev/null +++ b/src/plugins/presentation_util/public/components/controls/control_types/options_list/types.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from '../../../../../common/controls/control_types/options_list/types'; diff --git a/src/plugins/presentation_util/public/components/controls/controls_service.ts b/src/plugins/presentation_util/public/components/controls/controls_service.ts index 82242946e4563..436d36fcc9db0 100644 --- a/src/plugins/presentation_util/public/components/controls/controls_service.ts +++ b/src/plugins/presentation_util/public/components/controls/controls_service.ts @@ -6,31 +6,26 @@ * Side Public License, v 1. */ +import { ControlEmbeddable, ControlFactory, ControlInput, ControlOutput } from '.'; import { EmbeddableFactory } from '../../../../embeddable/public'; -import { - InputControlEmbeddable, - ControlTypeRegistry, - InputControlFactory, - InputControlOutput, - InputControlInput, -} from '../../services/controls'; +import { ControlTypeRegistry } from '../../services/controls'; export class ControlsService { private controlsFactoriesMap: ControlTypeRegistry = {}; - public registerInputControlType = (factory: InputControlFactory) => { + public registerControlType = (factory: ControlFactory) => { this.controlsFactoriesMap[factory.type] = factory; }; public getControlFactory = < - I extends InputControlInput = InputControlInput, - O extends InputControlOutput = InputControlOutput, - E extends InputControlEmbeddable = InputControlEmbeddable + I extends ControlInput = ControlInput, + O extends ControlOutput = ControlOutput, + E extends ControlEmbeddable = ControlEmbeddable >( type: string ) => { return this.controlsFactoriesMap[type] as EmbeddableFactory; }; - public getInputControlTypes = () => Object.keys(this.controlsFactoriesMap); + public getControlTypes = () => Object.keys(this.controlsFactoriesMap); } diff --git a/src/plugins/presentation_util/public/components/controls/hooks/use_child_embeddable.ts b/src/plugins/presentation_util/public/components/controls/hooks/use_child_embeddable.ts index c4f700ec059d9..379dff97cc871 100644 --- a/src/plugins/presentation_util/public/components/controls/hooks/use_child_embeddable.ts +++ b/src/plugins/presentation_util/public/components/controls/hooks/use_child_embeddable.ts @@ -6,16 +6,16 @@ * Side Public License, v 1. */ import { useEffect, useState } from 'react'; -import { InputControlEmbeddable } from '../../../services/controls'; +import { ControlEmbeddable } from '../types'; export const useChildEmbeddable = ({ untilEmbeddableLoaded, embeddableId, }: { - untilEmbeddableLoaded: (embeddableId: string) => Promise; + untilEmbeddableLoaded: (embeddableId: string) => Promise; embeddableId: string; }) => { - const [embeddable, setEmbeddable] = useState(); + const [embeddable, setEmbeddable] = useState(); useEffect(() => { let mounted = true; diff --git a/src/plugins/presentation_util/public/components/controls/hooks/use_state_observable.ts b/src/plugins/presentation_util/public/components/controls/hooks/use_state_observable.ts index c317f11979f54..79decd14ba358 100644 --- a/src/plugins/presentation_util/public/components/controls/hooks/use_state_observable.ts +++ b/src/plugins/presentation_util/public/components/controls/hooks/use_state_observable.ts @@ -13,11 +13,11 @@ export const useStateObservable = ( stateObservable: Observable, initialState: T ) => { + const [innerState, setInnerState] = useState(initialState); useEffect(() => { const subscription = stateObservable.subscribe((newState) => setInnerState(newState)); return () => subscription.unsubscribe(); }, [stateObservable]); - const [innerState, setInnerState] = useState(initialState); return innerState; }; diff --git a/src/plugins/presentation_util/public/components/controls/index.ts b/src/plugins/presentation_util/public/components/controls/index.ts new file mode 100644 index 0000000000000..dbea24336699d --- /dev/null +++ b/src/plugins/presentation_util/public/components/controls/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './control_group'; +export * from './types'; diff --git a/src/plugins/presentation_util/public/components/controls/types.ts b/src/plugins/presentation_util/public/components/controls/types.ts index 0704a601640e6..9d530fefe7373 100644 --- a/src/plugins/presentation_util/public/components/controls/types.ts +++ b/src/plugins/presentation_util/public/components/controls/types.ts @@ -6,28 +6,43 @@ * Side Public License, v 1. */ -import { InputControlInput } from '../../services/controls'; +import { Filter } from '@kbn/es-query'; +import { DataView } from '../../../../data_views/public'; +import { ControlInput } from '../../../common/controls/types'; +import { EmbeddableFactory, EmbeddableOutput, IEmbeddable } from '../../../../embeddable/public'; -export type ControlWidth = 'auto' | 'small' | 'medium' | 'large'; -export type ControlStyle = 'twoLine' | 'oneLine'; +export interface CommonControlOutput { + filters?: Filter[]; + dataViews?: DataView[]; +} + +export type ControlOutput = EmbeddableOutput & CommonControlOutput; + +export type ControlFactory = EmbeddableFactory; + +export type ControlEmbeddable< + TControlEmbeddableInput extends ControlInput = ControlInput, + TControlEmbeddableOutput extends ControlOutput = ControlOutput +> = IEmbeddable; /** * Control embeddable editor types */ -export interface IEditableControlFactory { - getControlEditor?: GetControlEditorComponent; +export interface IEditableControlFactory { + controlEditorComponent?: (props: ControlEditorProps) => JSX.Element; + presaveTransformFunction?: ( + newState: Partial, + embeddable?: ControlEmbeddable + ) => Partial; } - -export type GetControlEditorComponent = ( - props: GetControlEditorComponentProps -) => ControlEditorComponent; -export interface GetControlEditorComponentProps { - onChange: (partial: Partial) => void; +export interface ControlEditorProps { initialInput?: Partial; -} - -export type ControlEditorComponent = (props: ControlEditorProps) => JSX.Element; - -export interface ControlEditorProps { + onChange: (partial: Partial) => void; setValidState: (valid: boolean) => void; + setDefaultTitle: (defaultTitle: string) => void; } + +/** + * Re-export control types from common + */ +export * from '../../../common/controls/types'; diff --git a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.stories.tsx b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.stories.tsx index 1a29d0536a290..b8b0c46e7823d 100644 --- a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.stories.tsx +++ b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.stories.tsx @@ -8,61 +8,12 @@ import React, { useState } from 'react'; -import { DataView, DataViewField, IIndexPatternFieldList } from '../../../../data_views/common'; - -import { StorybookParams } from '../../services/storybook'; +import useMount from 'react-use/lib/useMount'; import { DataViewPicker } from './data_view_picker'; - -// TODO: we probably should remove this once the PR is merged that has better data views for stories -const flightFieldNames: string[] = [ - 'AvgTicketPrice', - 'Cancelled', - 'Carrier', - 'dayOfWeek', - 'Dest', - 'DestAirportID', - 'DestCityName', - 'DestCountry', - 'DestLocation', - 'DestRegion', - 'DestWeather', - 'DistanceKilometers', - 'DistanceMiles', - 'FlightDelay', - 'FlightDelayMin', - 'FlightDelayType', - 'FlightNum', - 'FlightTimeHour', - 'FlightTimeMin', - 'Origin', - 'OriginAirportID', - 'OriginCityName', - 'OriginCountry', - 'OriginLocation', - 'OriginRegion', - 'OriginWeather', - 'timestamp', -]; -const flightFieldByName: { [key: string]: DataViewField } = {}; -flightFieldNames.forEach( - (flightFieldName) => - (flightFieldByName[flightFieldName] = { - name: flightFieldName, - type: 'string', - } as unknown as DataViewField) -); - -// Change some types manually for now -flightFieldByName.Cancelled = { name: 'Cancelled', type: 'boolean' } as DataViewField; -flightFieldByName.timestamp = { name: 'timestamp', type: 'date' } as DataViewField; - -const flightFields: DataViewField[] = Object.values(flightFieldByName); -const storybookFlightsDataView: DataView = { - id: 'demoDataFlights', - title: 'demo data flights', - fields: flightFields as unknown as IIndexPatternFieldList, - getFieldByName: (name: string) => flightFieldByName[name], -} as unknown as DataView; +import { DataView, DataViewListItem } from '../../../../data_views/common'; +import { injectStorybookDataView } from '../../services/storybook/data_views'; +import { storybookFlightsDataView } from '../controls/__stories__/fixtures/flights'; +import { pluginServices, registry, StorybookParams } from '../../services/storybook'; export default { component: DataViewPicker, @@ -70,15 +21,29 @@ export default { argTypes: {}, }; +injectStorybookDataView(storybookFlightsDataView); + export function Example({}: {} & StorybookParams) { - const dataViews = [storybookFlightsDataView]; + pluginServices.setRegistry(registry.start({})); + + const { + dataViews: { getIdsWithTitle, get }, + } = pluginServices.getServices(); + const [dataViews, setDataViews] = useState(); const [dataView, setDataView] = useState(undefined); - const onChange = (newId: string) => { - const newIndexPattern = dataViews.find((ip) => ip.id === newId); + useMount(() => { + (async () => { + const listItems = await getIdsWithTitle(); + setDataViews(listItems); + })(); + }); - setDataView(newIndexPattern); + const onChange = (newId: string) => { + get(newId).then((newDataView) => { + setDataView(newDataView); + }); }; const triggerLabel = dataView?.title || 'Choose Data View'; @@ -86,9 +51,9 @@ export function Example({}: {} & StorybookParams) { return ( ); } diff --git a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx index 38ec4f16f9432..237a9666deb30 100644 --- a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx +++ b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; import { EuiPopover, EuiPopoverTitle, EuiSelectable, EuiSelectableProps } from '@elastic/eui'; -import { DataView } from '../../../../data_views/common'; +import { DataViewListItem } from '../../../../data_views/common'; import { ToolbarButton, ToolbarButtonProps } from '../../../../kibana_react/public'; @@ -21,14 +21,14 @@ export type DataViewTriggerProps = ToolbarButtonProps & { export function DataViewPicker({ dataViews, selectedDataViewId, - onChangeIndexPattern, + onChangeDataViewId, trigger, selectableProps, }: { - dataViews: DataView[]; + dataViews: DataViewListItem[]; selectedDataViewId?: string; trigger: DataViewTriggerProps; - onChangeIndexPattern: (newId: string) => void; + onChangeDataViewId: (newId: string) => void; selectableProps?: EuiSelectableProps; }) { const [isPopoverOpen, setPopoverIsOpen] = useState(false); @@ -92,7 +92,7 @@ export function DataViewPicker({ const choice = choices.find(({ checked }) => checked) as unknown as { value: string; }; - onChangeIndexPattern(choice.value); + onChangeDataViewId(choice.value); setPopoverIsOpen(false); }} searchProps={{ diff --git a/src/plugins/presentation_util/public/components/field_picker/field_picker.scss b/src/plugins/presentation_util/public/components/field_picker/field_picker.scss index c07cf99ed03d6..eac1979fd003a 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_picker.scss +++ b/src/plugins/presentation_util/public/components/field_picker/field_picker.scss @@ -4,6 +4,10 @@ border: 1px dashed transparent; } +.presFieldPickerFieldButtonActive { + box-shadow: 0 0 0 2px $euiColorPrimary; +} + .presFieldPicker__fieldPanel { height: 300px; overflow-y: scroll; diff --git a/src/plugins/presentation_util/public/components/field_picker/field_picker.stories.tsx b/src/plugins/presentation_util/public/components/field_picker/field_picker.stories.tsx index c5654254ea70a..023d2be949a73 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_picker.stories.tsx +++ b/src/plugins/presentation_util/public/components/field_picker/field_picker.stories.tsx @@ -9,59 +9,8 @@ import React from 'react'; import { FieldPicker } from './field_picker'; - -import { DataView, DataViewField, IIndexPatternFieldList } from '../../../../data_views/common'; - -// TODO: we probably should remove this once the PR is merged that has better data views for stories -const flightFieldNames: string[] = [ - 'AvgTicketPrice', - 'Cancelled', - 'Carrier', - 'dayOfWeek', - 'Dest', - 'DestAirportID', - 'DestCityName', - 'DestCountry', - 'DestLocation', - 'DestRegion', - 'DestWeather', - 'DistanceKilometers', - 'DistanceMiles', - 'FlightDelay', - 'FlightDelayMin', - 'FlightDelayType', - 'FlightNum', - 'FlightTimeHour', - 'FlightTimeMin', - 'Origin', - 'OriginAirportID', - 'OriginCityName', - 'OriginCountry', - 'OriginLocation', - 'OriginRegion', - 'OriginWeather', - 'timestamp', -]; -const flightFieldByName: { [key: string]: DataViewField } = {}; -flightFieldNames.forEach( - (flightFieldName) => - (flightFieldByName[flightFieldName] = { - name: flightFieldName, - type: 'string', - } as unknown as DataViewField) -); - -// Change some types manually for now -flightFieldByName.Cancelled = { name: 'Cancelled', type: 'boolean' } as DataViewField; -flightFieldByName.timestamp = { name: 'timestamp', type: 'date' } as DataViewField; - -const flightFields: DataViewField[] = Object.values(flightFieldByName); -const storybookFlightsDataView: DataView = { - id: 'demoDataFlights', - title: 'demo data flights', - fields: flightFields as unknown as IIndexPatternFieldList, - getFieldByName: (name: string) => flightFieldByName[name], -} as unknown as DataView; +import { DataViewField } from '../../../../data_views/common'; +import { storybookFlightsDataView } from '../controls/__stories__/fixtures/flights'; export default { component: FieldPicker, @@ -85,5 +34,5 @@ export const FieldPickerWithFilter = () => { }; export const FieldPickerWithoutIndexPattern = () => { - return ; + return ; }; diff --git a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx index bbdf389ccee14..c9be9993c3ec1 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx +++ b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx @@ -6,27 +6,33 @@ * Side Public License, v 1. */ -import React, { useState } from 'react'; +import classNames from 'classnames'; import { sortBy, uniq } from 'lodash'; -import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle, EuiText } from '@elastic/eui'; +import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; +import { FieldSearch } from './field_search'; import { DataView, DataViewField } from '../../../../data_views/common'; import { FieldIcon, FieldButton } from '../../../../kibana_react/public'; -import { FieldSearch } from './field_search'; - import './field_picker.scss'; -export interface Props { - dataView: DataView | null; +export interface FieldPickerProps { + dataView?: DataView; + selectedFieldName?: string; filterPredicate?: (f: DataViewField) => boolean; + onSelectField?: (selectedField: DataViewField) => void; } -export const FieldPicker = ({ dataView, filterPredicate }: Props) => { +export const FieldPicker = ({ + dataView, + onSelectField, + filterPredicate, + selectedFieldName, +}: FieldPickerProps) => { const [nameFilter, setNameFilter] = useState(''); const [typesFilter, setTypesFilter] = useState([]); - const [selectedField, setSelectedField] = useState(null); // Retrieve, filter, and sort fields from data view const fields = dataView @@ -42,7 +48,13 @@ export const FieldPicker = ({ dataView, filterPredicate }: Props) => { ) : []; - const uniqueTypes = dataView ? uniq(dataView.fields.map((f) => f.type as string)) : []; + const uniqueTypes = dataView + ? uniq( + dataView.fields + .filter((f) => (filterPredicate ? filterPredicate(f) : true)) + .map((f) => f.type as string) + ) + : []; return ( { return ( setSelectedField(f)} - isActive={f.name === selectedField?.name} + className={classNames('presFieldPicker__fieldButton', { + presFieldPickerFieldButtonActive: f.name === selectedFieldName, + })} + onClick={() => { + onSelectField?.(f); + }} + isActive={f.name === selectedFieldName} fieldName={f.name} fieldIcon={} /> @@ -122,31 +138,6 @@ export const FieldPicker = ({ dataView, filterPredicate }: Props) => { )} - {selectedField && ( - - -

- -

-
-
- - } - /> -
-
- )}
); }; diff --git a/src/plugins/presentation_util/public/components/redux_embeddables/generic_embeddable_store.ts b/src/plugins/presentation_util/public/components/redux_embeddables/generic_embeddable_store.ts index 36ba1fcaa49b9..fe5a647e7e327 100644 --- a/src/plugins/presentation_util/public/components/redux_embeddables/generic_embeddable_store.ts +++ b/src/plugins/presentation_util/public/components/redux_embeddables/generic_embeddable_store.ts @@ -18,7 +18,7 @@ type ManagedEmbeddableReduxStore = EnhancedStore & { asyncReducers: { [key: string]: Reducer }; injectReducer: (props: InjectReducerProps) => void; }; -const embeddablesStore = configureStore({ reducer: {} as { [key: string]: Reducer } }); +const embeddablesStore = configureStore({ reducer: (state) => state }); // store with blank reducers const managedEmbeddablesStore = embeddablesStore as ManagedEmbeddableReduxStore; managedEmbeddablesStore.asyncReducers = {}; @@ -27,10 +27,12 @@ managedEmbeddablesStore.injectReducer = ({ key, asyncReducer, }: InjectReducerProps) => { - managedEmbeddablesStore.asyncReducers[key] = asyncReducer as Reducer; - managedEmbeddablesStore.replaceReducer( - combineReducers({ ...managedEmbeddablesStore.asyncReducers }) - ); + if (!managedEmbeddablesStore.asyncReducers[key]) { + managedEmbeddablesStore.asyncReducers[key] = asyncReducer as Reducer; + managedEmbeddablesStore.replaceReducer( + combineReducers({ ...managedEmbeddablesStore.asyncReducers }) + ); + } }; /** diff --git a/src/plugins/presentation_util/public/components/redux_embeddables/redux_embeddable_wrapper.tsx b/src/plugins/presentation_util/public/components/redux_embeddables/redux_embeddable_wrapper.tsx index 4a112f7d6e574..9e7b53fb21c3b 100644 --- a/src/plugins/presentation_util/public/components/redux_embeddables/redux_embeddable_wrapper.tsx +++ b/src/plugins/presentation_util/public/components/redux_embeddables/redux_embeddable_wrapper.tsx @@ -10,6 +10,8 @@ import { Provider, TypedUseSelectorHook, useDispatch, useSelector } from 'react- import { SliceCaseReducers, PayloadAction, createSlice } from '@reduxjs/toolkit'; import React, { PropsWithChildren, useEffect, useMemo, useRef } from 'react'; import { Draft } from 'immer/dist/types/types-external'; +import { debounceTime, finalize } from 'rxjs/operators'; +import { Filter } from '@kbn/es-query'; import { isEqual } from 'lodash'; import { @@ -18,14 +20,30 @@ import { ReduxEmbeddableWrapperProps, } from './types'; import { + IContainer, IEmbeddable, EmbeddableInput, EmbeddableOutput, - IContainer, + isErrorEmbeddable, } from '../../../../embeddable/public'; import { getManagedEmbeddablesStore } from './generic_embeddable_store'; import { ReduxEmbeddableContext, useReduxEmbeddableContext } from './redux_embeddable_context'; +type InputWithFilters = Partial & { filters: Filter[] }; +export const stateContainsFilters = ( + state: Partial +): state is InputWithFilters => { + if ((state as InputWithFilters).filters) return true; + return false; +}; + +export const cleanFiltersForSerialize = (filters: Filter[]): Filter[] => { + return filters.map((filter) => { + if (filter.meta.value) delete filter.meta.value; + return filter; + }); +}; + const getDefaultProps = (): Required< Pick, 'diffInput'> > => ({ @@ -43,6 +61,17 @@ const embeddableIsContainer = ( embeddable: IEmbeddable ): embeddable is IContainer => embeddable.isContainer; +export const getExplicitInput = ( + embeddable: IEmbeddable +): InputType => { + const root = embeddable.getRoot(); + if (!embeddableIsContainer(embeddable) && embeddableIsContainer(root)) { + return (root.getInput().panels[embeddable.id]?.explicitInput ?? + embeddable.getInput()) as InputType; + } + return embeddable.getInput() as InputType; +}; + /** * Place this wrapper around the react component when rendering an embeddable to automatically set up * redux for use with the embeddable via the supplied reducers. Any child components can then use ReduxEmbeddableContext @@ -72,6 +101,12 @@ export const ReduxEmbeddableWrapper = { const key = `${embeddable.type}_${embeddable.id}`; + const store = getManagedEmbeddablesStore(); + + const initialState = getExplicitInput(embeddable); + if (stateContainsFilters(initialState)) { + initialState.filters = cleanFiltersForSerialize(initialState.filters); + } // A generic reducer used to update redux state when the embeddable input changes const updateEmbeddableReduxState = ( @@ -81,17 +116,28 @@ export const ReduxEmbeddableWrapper = { + return undefined; + }; + const slice = createSlice>({ - initialState: embeddable.getInput(), + initialState, name: key, - reducers: { ...reducers, updateEmbeddableReduxState }, + reducers: { ...reducers, updateEmbeddableReduxState, clearEmbeddableReduxState }, }); - const store = getManagedEmbeddablesStore(); - store.injectReducer({ - key, - asyncReducer: slice.reducer, - }); + if (store.asyncReducers[key]) { + // if the store already has reducers set up for this embeddable type & id, update the existing state. + const updateExistingState = (slice.actions as ReduxEmbeddableContextServices['actions']) + .updateEmbeddableReduxState; + store.dispatch(updateExistingState(initialState)); + } else { + store.injectReducer({ + key, + asyncReducer: slice.reducer, + }); + } const useEmbeddableSelector: TypedUseSelectorHook = () => useSelector((state: ReturnType) => state[key]); @@ -132,32 +178,47 @@ const ReduxEmbeddableSync = (); const dispatch = useEmbeddableDispatch(); const currentState = useEmbeddableSelector((state) => state); const stateRef = useRef(currentState); + const destroyedRef = useRef(false); useEffect(() => { // When Embeddable Input changes, push differences to redux. const inputSubscription = embeddable .getInput$() - // .pipe(debounceTime(0)) // debounce input changes to ensure that when many updates are made in one render the latest wins out + .pipe( + finalize(() => { + // empty redux store, when embeddable is destroyed. + destroyedRef.current = true; + dispatch(clearEmbeddableReduxState(undefined)); + }), + debounceTime(0) + ) // debounce input changes to ensure that when many updates are made in one render the latest wins out .subscribe(() => { - const differences = diffInput(embeddable.getInput(), stateRef.current); + const differences = diffInput(getExplicitInput(embeddable), stateRef.current); if (differences && Object.keys(differences).length > 0) { + if (stateContainsFilters(differences)) { + differences.filters = cleanFiltersForSerialize(differences.filters); + } dispatch(updateEmbeddableReduxState(differences)); } }); return () => inputSubscription.unsubscribe(); - }, [diffInput, dispatch, embeddable, updateEmbeddableReduxState]); + }, [diffInput, dispatch, embeddable, updateEmbeddableReduxState, clearEmbeddableReduxState]); useEffect(() => { + if (isErrorEmbeddable(embeddable) || destroyedRef.current) return; // When redux state changes, push differences to Embeddable Input. stateRef.current = currentState; - const differences = diffInput(currentState, embeddable.getInput()); + const differences = diffInput(currentState, getExplicitInput(embeddable)); if (differences && Object.keys(differences).length > 0) { + if (stateContainsFilters(differences)) { + differences.filters = cleanFiltersForSerialize(differences.filters); + } embeddable.updateInput(differences); } }, [currentState, diffInput, embeddable]); diff --git a/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss b/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss index 535570a51d777..c70e317546d40 100644 --- a/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss +++ b/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss @@ -1,11 +1,31 @@ .quickButtonGroup { - .quickButtonGroup__button { - background-color: $euiColorEmptyShade; - @include kbnThemeStyle('v8') { - // sass-lint:disable-block no-important - border-width: $euiBorderWidthThin !important; - border-style: solid !important; - border-color: $euiBorderColor !important; + .euiButtonGroup__buttons { + border-radius: $euiBorderRadius; + + .quickButtonGroup__button { + background-color: $euiColorEmptyShade; + @include kbnThemeStyle('v8') { + // sass-lint:disable-block no-important + border-width: $euiBorderWidthThin !important; + border-style: solid !important; + border-color: $euiBorderColor !important; + } + } + + .quickButtonGroup__button:first-of-type { + @include kbnThemeStyle('v8') { + // sass-lint:disable-block no-important + border-top-left-radius: $euiBorderRadius !important; + border-bottom-left-radius: $euiBorderRadius !important; + } + } + + .quickButtonGroup__button:last-of-type { + @include kbnThemeStyle('v8') { + // sass-lint:disable-block no-important + border-top-right-radius: $euiBorderRadius !important; + border-bottom-right-radius: $euiBorderRadius !important; + } } } } diff --git a/src/plugins/presentation_util/public/index.ts b/src/plugins/presentation_util/public/index.ts index 6628124717a1c..478e8a7cda032 100644 --- a/src/plugins/presentation_util/public/index.ts +++ b/src/plugins/presentation_util/public/index.ts @@ -54,6 +54,8 @@ export { SolutionToolbarPopover, } from './components/solution_toolbar'; +export * from './components/controls'; + export function plugin() { return new PresentationUtilPlugin(); } diff --git a/src/plugins/presentation_util/public/mocks.ts b/src/plugins/presentation_util/public/mocks.ts index ddb02ce464e22..8b81890c51e2a 100644 --- a/src/plugins/presentation_util/public/mocks.ts +++ b/src/plugins/presentation_util/public/mocks.ts @@ -12,7 +12,9 @@ import { pluginServices } from './services'; import { registry } from './services/kibana'; const createStartContract = (coreStart: CoreStart): PresentationUtilPluginStart => { - pluginServices.setRegistry(registry.start({ coreStart, startPlugins: {} as any })); + pluginServices.setRegistry( + registry.start({ coreStart, startPlugins: { dataViews: {}, data: {} } as any }) + ); const startContract: PresentationUtilPluginStart = { ContextProvider: pluginServices.getContextProvider(), diff --git a/src/plugins/presentation_util/public/plugin.ts b/src/plugins/presentation_util/public/plugin.ts index f697f1a29eb82..f531d99dfb99c 100644 --- a/src/plugins/presentation_util/public/plugin.ts +++ b/src/plugins/presentation_util/public/plugin.ts @@ -10,11 +10,18 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { pluginServices } from './services'; import { registry } from './services/kibana'; import { - PresentationUtilPluginSetup, - PresentationUtilPluginStart, PresentationUtilPluginSetupDeps, PresentationUtilPluginStartDeps, + ControlGroupContainerFactory, + PresentationUtilPluginSetup, + PresentationUtilPluginStart, + IEditableControlFactory, + ControlEditorProps, + ControlInput, + ControlEmbeddable, } from './types'; +import { OptionsListEmbeddableFactory } from './components/controls/control_types/options_list'; +import { CONTROL_GROUP_TYPE, OPTIONS_LIST_CONTROL } from '.'; export class PresentationUtilPlugin implements @@ -25,10 +32,39 @@ export class PresentationUtilPlugin PresentationUtilPluginStartDeps > { + private inlineEditors: { + [key: string]: { + controlEditorComponent?: (props: ControlEditorProps) => JSX.Element; + presaveTransformFunction?: ( + newInput: Partial, + embeddable?: ControlEmbeddable + ) => Partial; + }; + } = {}; + public setup( - _coreSetup: CoreSetup, + _coreSetup: CoreSetup, _setupPlugins: PresentationUtilPluginSetupDeps ): PresentationUtilPluginSetup { + _coreSetup.getStartServices().then(([coreStart, deps]) => { + // register control group embeddable factory + embeddable.registerEmbeddableFactory( + CONTROL_GROUP_TYPE, + new ControlGroupContainerFactory(deps.embeddable) + ); + }); + + const { embeddable } = _setupPlugins; + + // create control type embeddable factories. + const optionsListFactory = new OptionsListEmbeddableFactory(); + const editableOptionsListFactory = optionsListFactory as IEditableControlFactory; + this.inlineEditors[OPTIONS_LIST_CONTROL] = { + controlEditorComponent: editableOptionsListFactory.controlEditorComponent, + presaveTransformFunction: editableOptionsListFactory.presaveTransformFunction, + }; + embeddable.registerEmbeddableFactory(OPTIONS_LIST_CONTROL, optionsListFactory); + return {}; } @@ -37,9 +73,25 @@ export class PresentationUtilPlugin startPlugins: PresentationUtilPluginStartDeps ): PresentationUtilPluginStart { pluginServices.setRegistry(registry.start({ coreStart, startPlugins })); + const { controls: controlsService } = pluginServices.getServices(); + const { embeddable } = startPlugins; + + // register control types with controls service. + const optionsListFactory = embeddable.getEmbeddableFactory(OPTIONS_LIST_CONTROL); + // Temporarily pass along inline editors - inline editing should be made a first-class feature of embeddables + const editableOptionsListFactory = optionsListFactory as IEditableControlFactory; + const { + controlEditorComponent: optionsListControlEditor, + presaveTransformFunction: optionsListPresaveTransform, + } = this.inlineEditors[OPTIONS_LIST_CONTROL]; + editableOptionsListFactory.controlEditorComponent = optionsListControlEditor; + editableOptionsListFactory.presaveTransformFunction = optionsListPresaveTransform; + + if (optionsListFactory) controlsService.registerControlType(optionsListFactory); + return { ContextProvider: pluginServices.getContextProvider(), - controlsService: pluginServices.getServices().controls, + controlsService, labsService: pluginServices.getServices().labs, }; } diff --git a/src/plugins/presentation_util/public/services/controls.ts b/src/plugins/presentation_util/public/services/controls.ts index 197e986381b10..76af24960bfe3 100644 --- a/src/plugins/presentation_util/public/services/controls.ts +++ b/src/plugins/presentation_util/public/services/controls.ts @@ -6,80 +6,54 @@ * Side Public License, v 1. */ -import { Filter } from '@kbn/es-query'; -import { Query, TimeRange } from '../../../data/public'; +import { EmbeddableFactory } from '../../../embeddable/public'; import { - EmbeddableFactory, - EmbeddableInput, - EmbeddableOutput, - IEmbeddable, -} from '../../../embeddable/public'; - -/** - * Control embeddable types - */ -export type InputControlFactory = EmbeddableFactory< - InputControlInput, - InputControlOutput, - InputControlEmbeddable ->; - -export type InputControlInput = EmbeddableInput & { - query?: Query; - filters?: Filter[]; - timeRange?: TimeRange; - twoLineLayout?: boolean; -}; - -export type InputControlOutput = EmbeddableOutput & { - filters?: Filter[]; -}; - -export type InputControlEmbeddable< - TInputControlEmbeddableInput extends InputControlInput = InputControlInput, - TInputControlEmbeddableOutput extends InputControlOutput = InputControlOutput -> = IEmbeddable; + ControlEmbeddable, + ControlFactory, + ControlOutput, + ControlInput, +} from '../components/controls/types'; export interface ControlTypeRegistry { - [key: string]: InputControlFactory; + [key: string]: ControlFactory; } export interface PresentationControlsService { - registerInputControlType: (factory: InputControlFactory) => void; + registerControlType: (factory: ControlFactory) => void; getControlFactory: < - I extends InputControlInput = InputControlInput, - O extends InputControlOutput = InputControlOutput, - E extends InputControlEmbeddable = InputControlEmbeddable + I extends ControlInput = ControlInput, + O extends ControlOutput = ControlOutput, + E extends ControlEmbeddable = ControlEmbeddable >( type: string ) => EmbeddableFactory; - getInputControlTypes: () => string[]; + getControlTypes: () => string[]; } export const getCommonControlsService = () => { const controlsFactoriesMap: ControlTypeRegistry = {}; - const registerInputControlType = (factory: InputControlFactory) => { + const registerControlType = (factory: ControlFactory) => { controlsFactoriesMap[factory.type] = factory; }; const getControlFactory = < - I extends InputControlInput = InputControlInput, - O extends InputControlOutput = InputControlOutput, - E extends InputControlEmbeddable = InputControlEmbeddable + I extends ControlInput = ControlInput, + O extends ControlOutput = ControlOutput, + E extends ControlEmbeddable = ControlEmbeddable >( type: string ) => { return controlsFactoriesMap[type] as EmbeddableFactory; }; - const getInputControlTypes = () => Object.keys(controlsFactoriesMap); + const getControlTypes = () => Object.keys(controlsFactoriesMap); return { - registerInputControlType, + registerControlType, getControlFactory, - getInputControlTypes, + getControlTypes, }; }; diff --git a/src/plugins/presentation_util/public/services/data.ts b/src/plugins/presentation_util/public/services/data.ts new file mode 100644 index 0000000000000..44f29dcd2d3ad --- /dev/null +++ b/src/plugins/presentation_util/public/services/data.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataPublicPluginStart } from '../../../data/public'; + +export interface PresentationDataService { + autocomplete: DataPublicPluginStart['autocomplete']; +} diff --git a/src/plugins/presentation_util/public/services/data_views.ts b/src/plugins/presentation_util/public/services/data_views.ts new file mode 100644 index 0000000000000..9ab260034a1db --- /dev/null +++ b/src/plugins/presentation_util/public/services/data_views.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataViewsPublicPluginStart } from '../../../data_views/public'; + +export interface PresentationDataViewsService { + get: DataViewsPublicPluginStart['get']; + getDefaultId: DataViewsPublicPluginStart['getDefaultId']; + getIdsWithTitle: DataViewsPublicPluginStart['getIdsWithTitle']; +} diff --git a/src/plugins/presentation_util/public/services/index.ts b/src/plugins/presentation_util/public/services/index.ts index 21012971ca86d..c7d8d2617888a 100644 --- a/src/plugins/presentation_util/public/services/index.ts +++ b/src/plugins/presentation_util/public/services/index.ts @@ -14,12 +14,16 @@ import { PresentationLabsService } from './labs'; import { registry as stubRegistry } from './stub'; import { PresentationOverlaysService } from './overlays'; import { PresentationControlsService } from './controls'; +import { PresentationDataViewsService } from './data_views'; +import { PresentationDataService } from './data'; export { PresentationCapabilitiesService } from './capabilities'; export { PresentationDashboardsService } from './dashboards'; export { PresentationLabsService } from './labs'; export interface PresentationUtilServices { dashboards: PresentationDashboardsService; + dataViews: PresentationDataViewsService; + data: PresentationDataService; capabilities: PresentationCapabilitiesService; overlays: PresentationOverlaysService; controls: PresentationControlsService; diff --git a/src/plugins/presentation_util/public/services/kibana/data.ts b/src/plugins/presentation_util/public/services/kibana/data.ts new file mode 100644 index 0000000000000..408e59fd4906c --- /dev/null +++ b/src/plugins/presentation_util/public/services/kibana/data.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PresentationUtilPluginStartDeps } from '../../types'; +import { KibanaPluginServiceFactory } from '../create'; +import { PresentationDataService } from '../data'; + +export type DataServiceFactory = KibanaPluginServiceFactory< + PresentationDataService, + PresentationUtilPluginStartDeps +>; + +export const dataServiceFactory: DataServiceFactory = ({ startPlugins }) => { + const { + data: { autocomplete }, + } = startPlugins; + return { + autocomplete, + }; +}; diff --git a/src/plugins/presentation_util/public/services/kibana/data_views.ts b/src/plugins/presentation_util/public/services/kibana/data_views.ts new file mode 100644 index 0000000000000..ecebecce3b3c0 --- /dev/null +++ b/src/plugins/presentation_util/public/services/kibana/data_views.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PresentationUtilPluginStartDeps } from '../../types'; +import { PresentationDataViewsService } from '../data_views'; +import { KibanaPluginServiceFactory } from '../create'; + +export type DataViewsServiceFactory = KibanaPluginServiceFactory< + PresentationDataViewsService, + PresentationUtilPluginStartDeps +>; + +export const dataViewsServiceFactory: DataViewsServiceFactory = ({ startPlugins }) => { + const { + dataViews: { get, getIdsWithTitle, getDefaultId }, + } = startPlugins; + + return { + get, + getDefaultId, + getIdsWithTitle, + }; +}; diff --git a/src/plugins/presentation_util/public/services/kibana/index.ts b/src/plugins/presentation_util/public/services/kibana/index.ts index 48c921bff1efd..3820442555c26 100644 --- a/src/plugins/presentation_util/public/services/kibana/index.ts +++ b/src/plugins/presentation_util/public/services/kibana/index.ts @@ -6,10 +6,6 @@ * Side Public License, v 1. */ -import { capabilitiesServiceFactory } from './capabilities'; -import { dashboardsServiceFactory } from './dashboards'; -import { overlaysServiceFactory } from './overlays'; -import { labsServiceFactory } from './labs'; import { PluginServiceProviders, KibanaPluginServiceParams, @@ -18,12 +14,14 @@ import { } from '../create'; import { PresentationUtilPluginStartDeps } from '../../types'; import { PresentationUtilServices } from '..'; -import { controlsServiceFactory } from './controls'; -export { capabilitiesServiceFactory } from './capabilities'; -export { dashboardsServiceFactory } from './dashboards'; -export { overlaysServiceFactory } from './overlays'; -export { labsServiceFactory } from './labs'; +import { capabilitiesServiceFactory } from './capabilities'; +import { dataViewsServiceFactory } from './data_views'; +import { dashboardsServiceFactory } from './dashboards'; +import { controlsServiceFactory } from './controls'; +import { overlaysServiceFactory } from './overlays'; +import { dataServiceFactory } from './data'; +import { labsServiceFactory } from './labs'; export const providers: PluginServiceProviders< PresentationUtilServices, @@ -31,6 +29,8 @@ export const providers: PluginServiceProviders< > = { capabilities: new PluginServiceProvider(capabilitiesServiceFactory), labs: new PluginServiceProvider(labsServiceFactory), + dataViews: new PluginServiceProvider(dataViewsServiceFactory), + data: new PluginServiceProvider(dataServiceFactory), dashboards: new PluginServiceProvider(dashboardsServiceFactory), overlays: new PluginServiceProvider(overlaysServiceFactory), controls: new PluginServiceProvider(controlsServiceFactory), diff --git a/src/plugins/presentation_util/public/services/storybook/data.ts b/src/plugins/presentation_util/public/services/storybook/data.ts new file mode 100644 index 0000000000000..841ee1bd9be71 --- /dev/null +++ b/src/plugins/presentation_util/public/services/storybook/data.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataPublicPluginStart } from '../../../../data/public'; +import { DataViewField } from '../../../../data_views/common'; +import { PresentationDataService } from '../data'; +import { PluginServiceFactory } from '../create'; + +let valueSuggestionMethod = ({ field, query }: { field: DataViewField; query: string }) => + Promise.resolve(['storybook', 'default', 'values']); +export const replaceValueSuggestionMethod = ( + newMethod: ({ field, query }: { field: DataViewField; query: string }) => Promise +) => (valueSuggestionMethod = newMethod); + +export type DataServiceFactory = PluginServiceFactory; +export const dataServiceFactory: DataServiceFactory = () => ({ + autocomplete: { + getValueSuggestions: valueSuggestionMethod, + } as unknown as DataPublicPluginStart['autocomplete'], +}); diff --git a/src/plugins/presentation_util/public/services/storybook/data_views.ts b/src/plugins/presentation_util/public/services/storybook/data_views.ts new file mode 100644 index 0000000000000..ecdd3d48c4658 --- /dev/null +++ b/src/plugins/presentation_util/public/services/storybook/data_views.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginServiceFactory } from '../create'; +import { PresentationDataViewsService } from '../data_views'; +import { DataViewsPublicPluginStart } from '../../../../data_views/public'; +import { DataView } from '../../../../data_views/common'; + +export type DataViewsServiceFactory = PluginServiceFactory; + +let currentDataView: DataView; +export const injectStorybookDataView = (dataView: DataView) => (currentDataView = dataView); + +export const dataViewsServiceFactory: DataViewsServiceFactory = () => ({ + get: (() => + new Promise((r) => + setTimeout(() => r(currentDataView), 100) + ) as unknown) as DataViewsPublicPluginStart['get'], + getIdsWithTitle: (() => + new Promise((r) => + setTimeout(() => r([{ id: currentDataView.id, title: currentDataView.title }]), 100) + ) as unknown) as DataViewsPublicPluginStart['getIdsWithTitle'], + getDefaultId: () => Promise.resolve(currentDataView?.id ?? null), +}); diff --git a/src/plugins/presentation_util/public/services/storybook/index.ts b/src/plugins/presentation_util/public/services/storybook/index.ts index 9de4934d51300..1639316a1fe19 100644 --- a/src/plugins/presentation_util/public/services/storybook/index.ts +++ b/src/plugins/presentation_util/public/services/storybook/index.ts @@ -18,6 +18,8 @@ import { capabilitiesServiceFactory } from './capabilities'; import { PresentationUtilServices } from '..'; import { overlaysServiceFactory } from './overlays'; import { controlsServiceFactory } from './controls'; +import { dataViewsServiceFactory } from './data_views'; +import { dataServiceFactory } from './data'; export { PluginServiceProviders, PluginServiceProvider, PluginServiceRegistry } from '../create'; export { PresentationUtilServices } from '..'; @@ -32,6 +34,8 @@ export interface StorybookParams { export const providers: PluginServiceProviders = { capabilities: new PluginServiceProvider(capabilitiesServiceFactory), dashboards: new PluginServiceProvider(dashboardsServiceFactory), + dataViews: new PluginServiceProvider(dataViewsServiceFactory), + data: new PluginServiceProvider(dataServiceFactory), overlays: new PluginServiceProvider(overlaysServiceFactory), controls: new PluginServiceProvider(controlsServiceFactory), labs: new PluginServiceProvider(labsServiceFactory), diff --git a/src/plugins/presentation_util/public/services/stub/index.ts b/src/plugins/presentation_util/public/services/stub/index.ts index 35aabdb465b14..2e312ff682927 100644 --- a/src/plugins/presentation_util/public/services/stub/index.ts +++ b/src/plugins/presentation_util/public/services/stub/index.ts @@ -16,12 +16,17 @@ import { controlsServiceFactory } from './controls'; export { dashboardsServiceFactory } from './dashboards'; export { capabilitiesServiceFactory } from './capabilities'; +import { dataServiceFactory } from '../storybook/data'; +import { dataViewsServiceFactory } from '../storybook/data_views'; + export const providers: PluginServiceProviders = { dashboards: new PluginServiceProvider(dashboardsServiceFactory), capabilities: new PluginServiceProvider(capabilitiesServiceFactory), overlays: new PluginServiceProvider(overlaysServiceFactory), controls: new PluginServiceProvider(controlsServiceFactory), labs: new PluginServiceProvider(labsServiceFactory), + data: new PluginServiceProvider(dataServiceFactory), + dataViews: new PluginServiceProvider(dataViewsServiceFactory), }; export const registry = new PluginServiceRegistry(providers); diff --git a/src/plugins/presentation_util/public/types.ts b/src/plugins/presentation_util/public/types.ts index 3903d1bc2786e..63690901b9be6 100644 --- a/src/plugins/presentation_util/public/types.ts +++ b/src/plugins/presentation_util/public/types.ts @@ -6,8 +6,11 @@ * Side Public License, v 1. */ -import { PresentationControlsService } from './services/controls'; +import { DataPublicPluginStart } from '../../data/public'; import { PresentationLabsService } from './services/labs'; +import { PresentationControlsService } from './services/controls'; +import { DataViewsPublicPluginStart } from '../../data_views/public'; +import { EmbeddableSetup, EmbeddableStart } from '../../embeddable/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PresentationUtilPluginSetup {} @@ -18,7 +21,13 @@ export interface PresentationUtilPluginStart { controlsService: PresentationControlsService; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PresentationUtilPluginSetupDeps {} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PresentationUtilPluginStartDeps {} +export interface PresentationUtilPluginSetupDeps { + embeddable: EmbeddableSetup; +} +export interface PresentationUtilPluginStartDeps { + data: DataPublicPluginStart; + embeddable: EmbeddableStart; + dataViews: DataViewsPublicPluginStart; +} + +export * from './components/controls'; diff --git a/src/plugins/presentation_util/server/controls/control_group/control_group_container_factory.ts b/src/plugins/presentation_util/server/controls/control_group/control_group_container_factory.ts new file mode 100644 index 0000000000000..17dcbbd249435 --- /dev/null +++ b/src/plugins/presentation_util/server/controls/control_group/control_group_container_factory.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EmbeddablePersistableStateService } from 'src/plugins/embeddable/common'; +import { EmbeddableRegistryDefinition } from '../../../../embeddable/server'; +import { CONTROL_GROUP_TYPE } from '../../../common/controls'; +import { + createControlGroupExtract, + createControlGroupInject, +} from '../../../common/controls/control_group/control_group_persistable_state'; + +export const controlGroupContainerPersistableStateServiceFactory = ( + persistableStateService: EmbeddablePersistableStateService +): EmbeddableRegistryDefinition => { + return { + id: CONTROL_GROUP_TYPE, + extract: createControlGroupExtract(persistableStateService), + inject: createControlGroupInject(persistableStateService), + }; +}; diff --git a/src/plugins/presentation_util/server/controls/control_types/options_list/options_list_embeddable_factory.ts b/src/plugins/presentation_util/server/controls/control_types/options_list/options_list_embeddable_factory.ts new file mode 100644 index 0000000000000..b9d69ea489274 --- /dev/null +++ b/src/plugins/presentation_util/server/controls/control_types/options_list/options_list_embeddable_factory.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EmbeddableRegistryDefinition } from '../../../../../embeddable/server'; +import { OPTIONS_LIST_CONTROL } from '../../../../common/controls'; +import { + createOptionsListExtract, + createOptionsListInject, +} from '../../../../common/controls/control_types/options_list/options_list_persistable_state'; + +export const optionsListPersistableStateServiceFactory = (): EmbeddableRegistryDefinition => { + return { + id: OPTIONS_LIST_CONTROL, + extract: createOptionsListExtract(), + inject: createOptionsListInject(), + }; +}; diff --git a/src/plugins/presentation_util/server/plugin.ts b/src/plugins/presentation_util/server/plugin.ts index eb55373920625..2c52fa1f6c2d8 100644 --- a/src/plugins/presentation_util/server/plugin.ts +++ b/src/plugins/presentation_util/server/plugin.ts @@ -7,11 +7,24 @@ */ import { CoreSetup, Plugin } from 'kibana/server'; +import { EmbeddableSetup } from '../../embeddable/server'; +import { controlGroupContainerPersistableStateServiceFactory } from './controls/control_group/control_group_container_factory'; +import { optionsListPersistableStateServiceFactory } from './controls/control_types/options_list/options_list_embeddable_factory'; import { getUISettings } from './ui_settings'; -export class PresentationUtilPlugin implements Plugin { - public setup(core: CoreSetup) { +interface SetupDeps { + embeddable: EmbeddableSetup; +} + +export class PresentationUtilPlugin implements Plugin { + public setup(core: CoreSetup, plugins: SetupDeps) { core.uiSettings.register(getUISettings()); + + plugins.embeddable.registerEmbeddableFactory(optionsListPersistableStateServiceFactory()); + + plugins.embeddable.registerEmbeddableFactory( + controlGroupContainerPersistableStateServiceFactory(plugins.embeddable) + ); return {}; } diff --git a/src/plugins/presentation_util/tsconfig.json b/src/plugins/presentation_util/tsconfig.json index caff10a90e84c..caabd0b18af71 100644 --- a/src/plugins/presentation_util/tsconfig.json +++ b/src/plugins/presentation_util/tsconfig.json @@ -22,6 +22,7 @@ { "path": "../saved_objects/tsconfig.json" }, { "path": "../kibana_react/tsconfig.json" }, { "path": "../embeddable/tsconfig.json" }, + { "path": "../kibana_react/tsconfig.json"}, { "path": "../data/tsconfig.json" } ] } diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index e60191589b009..4ac0153b1f80f 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -5149,7 +5149,7 @@ } } }, - "securitySolution": { + "securitySolutionUI": { "properties": { "appId": { "type": "keyword", @@ -7802,6 +7802,12 @@ "description": "Non-default value of setting." } }, + "labs:canvas:byValueEmbeddable": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "labs:canvas:useDataService": { "type": "boolean", "_meta": { @@ -7820,6 +7826,12 @@ "description": "Non-default value of setting." } }, + "labs:dashboard:dashboardControls": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "discover:showFieldStatistics": { "type": "boolean", "_meta": { diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 02ac428b07667..97180f351986e 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -230,6 +230,7 @@ export class FetcherTask { method: 'post', body: stats, headers: { + 'Content-Type': 'application/json', 'X-Elastic-Stack-Version': this.currentKibanaVersion, 'X-Elastic-Cluster-ID': clusterUuid, 'X-Elastic-Content-Encoding': PAYLOAD_CONTENT_ENCODING, diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts index 1a00d0e428016..191e857c777d2 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts @@ -7,7 +7,7 @@ */ import { merge, omit } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getLocalStats, handleLocalStats } from './get_local_stats'; import { diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts index 7860949e098aa..ae2a849ccfa19 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { StatsGetter, StatsCollectionContext, diff --git a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts index 0d58d80ed5965..a5d4f32b3a62f 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts @@ -7,7 +7,7 @@ */ import type { ElasticsearchClient } from 'src/core/server'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { TIMEOUT } from './constants'; /** diff --git a/src/plugins/usage_collection/server/plugin.ts b/src/plugins/usage_collection/server/plugin.ts index 1c537ccfbb22b..12b2db43016e4 100644 --- a/src/plugins/usage_collection/server/plugin.ts +++ b/src/plugins/usage_collection/server/plugin.ts @@ -113,6 +113,7 @@ export class UsageCollectionPlugin implements Plugin { public setup(core: CoreSetup): UsageCollectionSetup { const config = this.initializerContext.config.get(); + const kibanaIndex = core.savedObjects.getKibanaIndex(); const collectorSet = new CollectorSet({ logger: this.logger.get('usage-collection', 'collector-set'), @@ -128,7 +129,6 @@ export class UsageCollectionPlugin implements Plugin { const { createUsageCounter, getUsageCounterByType } = this.usageCountersService.setup(core); const uiCountersUsageCounter = createUsageCounter('uiCounter'); - const globalConfig = this.initializerContext.config.legacy.get(); const router = core.http.createRouter(); setupRoutes({ router, @@ -137,7 +137,7 @@ export class UsageCollectionPlugin implements Plugin { collectorSet, config: { allowAnonymous: core.status.isStatusPageAnonymous(), - kibanaIndex: globalConfig.kibana.index, + kibanaIndex, kibanaVersion: this.initializerContext.env.packageInfo.version, server: core.http.getServerInfo(), uuid: this.initializerContext.env.instanceUuid, diff --git a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap index bc6d28bd5c1c4..b25444d16c46a 100644 --- a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap +++ b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap @@ -12,8 +12,10 @@ exports[`DefaultEditorAgg component should init with the default set of props 1` } buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate" + buttonElement="button" className="visEditorSidebar__section visEditorSidebar__collapsible visEditorSidebar__collapsible--marginBottom" data-test-subj="visEditorAggAccordion1" + element="div" extraAction={
)} - + + +
+ } + > + + ); diff --git a/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx b/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx index 34cc1dc347ef8..ad069a4d7e2cc 100644 --- a/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx +++ b/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx @@ -13,6 +13,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; import { IUiSettingsClient } from 'kibana/public'; +import { EuiLoadingChart } from '@elastic/eui'; import { fetchIndexPattern } from '../common/index_patterns_utils'; import { VisualizationContainer, PersistedState } from '../../../visualizations/public'; @@ -43,10 +44,6 @@ export const getTimeseriesVisRenderer: (deps: { name: 'timeseries_vis', reuseDomNode: true, render: async (domNode, config, handlers) => { - // Build optimization. Move app styles from main bundle - // @ts-expect-error TS error, cannot find type declaration for scss - await import('./application/index.scss'); - handlers.onDestroy(() => { unmountComponentAtNode(domNode); }); @@ -55,33 +52,49 @@ export const getTimeseriesVisRenderer: (deps: { const { indexPatterns } = getDataStart(); const showNoResult = !checkIfDataExists(visData, model); - const [palettesService, { indexPattern }] = await Promise.all([ + + let servicesLoaded; + + Promise.all([ palettes.getPalettes(), fetchIndexPattern(model.index_pattern, indexPatterns), - ]); + ]).then(([palettesService, { indexPattern }]) => { + servicesLoaded = true; - render( - - - + - - , - domNode - ); + showNoResult={showNoResult} + error={get(visData, [model.id, 'error'])} + > + + + , + domNode + ); + }); + + if (!servicesLoaded) { + render( +
+ +
, + domNode + ); + } }, }); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts index b7a22abd825e0..7c17f003dfbab 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts @@ -24,10 +24,15 @@ export function getIntervalAndTimefield( { min, max, maxBuckets }: IntervalParams, series?: Series ) { - const timeField = + let timeField = (series?.override_index_pattern ? series.series_time_field : panel.time_field) || index.indexPattern?.timeFieldName; + // should use @timestamp as default timeField for es indeces if user doesn't provide timeField + if (!panel.use_kibana_indexes && !timeField) { + timeField = '@timestamp'; + } + if (panel.use_kibana_indexes) { validateField(timeField!, index); } diff --git a/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts b/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts index 7f6ca05df3d7a..f52101212662d 100644 --- a/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts +++ b/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { cloneDeep, isPlainObject } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Assign } from 'utility-types'; import { TimeCache } from './time_cache'; import { SearchAPI } from './search_api'; diff --git a/src/plugins/vis_types/vega/public/data_model/types.ts b/src/plugins/vis_types/vega/public/data_model/types.ts index d1568bba6c98c..19efe5a9a4b7d 100644 --- a/src/plugins/vis_types/vega/public/data_model/types.ts +++ b/src/plugins/vis_types/vega/public/data_model/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Assign } from '@kbn/utility-types'; import { Spec } from 'vega'; import { EsQueryParser } from './es_query_parser'; diff --git a/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap index f50836e6ca8af..1dd916f827fe6 100644 --- a/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap @@ -66,8 +66,10 @@ exports[`ValueAxesPanel component should init with the default set of props 1`] } buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate" + buttonElement="button" className="visEditorSidebar__section visEditorSidebar__collapsible" data-test-subj="toggleYAxisOptions-ValueAxis-1" + element="div" extraAction={ } buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate" + buttonElement="button" className="visEditorSidebar__section visEditorSidebar__collapsible" data-test-subj="toggleYAxisOptions-ValueAxis-2" + element="div" extraAction={ + +
, + this.domNode + ); + const expressions = getExpressions(); this.handler = await expressions.loader(this.domNode, undefined, { onRenderError: (element: HTMLElement, error: ExpressionRenderError) => { diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts index c7480844adbea..2fa22cfe8d80b 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts @@ -12,10 +12,12 @@ export const createVisualizeEmbeddableAsync = async ( ...args: ConstructorParameters ) => { // Build optimization. Move app styles from main bundle - // @ts-expect-error TS error, cannot find type declaration for scss - await import('./embeddables.scss'); - const { VisualizeEmbeddable } = await import('./visualize_embeddable'); + const [{ VisualizeEmbeddable }] = await Promise.all([ + import('./visualize_embeddable'), + // @ts-expect-error TS error, cannot find type declaration for scss + import('./embeddables.scss'), + ]); return new VisualizeEmbeddable(...args); }; diff --git a/test/accessibility/apps/filter_panel.ts b/test/accessibility/apps/filter_panel.ts index 78e776ce3a482..deb1e9512cd81 100644 --- a/test/accessibility/apps/filter_panel.ts +++ b/test/accessibility/apps/filter_panel.ts @@ -24,6 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('a11y test on add filter panel', async () => { await PageObjects.discover.openAddFilterPanel(); await a11y.testAppSnapshot(); + await PageObjects.discover.closeAddFilterPanel(); await filterBar.addFilter('OriginCityName', 'is', 'Rome'); }); diff --git a/test/api_integration/apis/custom_integration/integrations.ts b/test/api_integration/apis/custom_integration/integrations.ts index e4797b334a866..0784a86e4b546 100644 --- a/test/api_integration/apis/custom_integration/integrations.ts +++ b/test/api_integration/apis/custom_integration/integrations.ts @@ -22,7 +22,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.body).to.be.an('array'); - expect(resp.body.length).to.be(12); + expect(resp.body.length).to.be(33); // Test for sample data card expect(resp.body.findIndex((c: { id: string }) => c.id === 'sample_data_all')).to.be.above( diff --git a/test/api_integration/apis/home/sample_data.ts b/test/api_integration/apis/home/sample_data.ts index 1e029bc1e04d7..2525cbe330044 100644 --- a/test/api_integration/apis/home/sample_data.ts +++ b/test/api_integration/apis/home/sample_data.ts @@ -48,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('should load elasticsearch index containing sample data with dates relative to current time', async () => { - const { body: resp } = await es.search<{ timestamp: string }>({ + const resp = await es.search<{ timestamp: string }>({ index: 'kibana_sample_data_flights', }); @@ -66,7 +66,7 @@ export default function ({ getService }: FtrProviderContext) { .post(`/api/sample_data/flights?now=${nowString}`) .set('kbn-xsrf', 'kibana'); - const { body: resp } = await es.search<{ timestamp: string }>({ + const resp = await es.search<{ timestamp: string }>({ index: 'kibana_sample_data_flights', }); @@ -85,7 +85,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('should remove elasticsearch index containing sample data', async () => { - const { body: resp } = await es.indices.exists({ + const resp = await es.indices.exists({ index: 'kibana_sample_data_flights', }); expect(resp).to.be(false); diff --git a/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts b/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts index 8dfb892acfd90..8fc4e860e5d9c 100644 --- a/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts +++ b/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts @@ -17,11 +17,11 @@ export default function ({ getService }: FtrProviderContext) { describe('has user index pattern API', () => { beforeEach(async () => { await esArchiver.emptyKibanaIndex(); - if ((await es.indices.exists({ index: 'metrics-test' })).body) { + if (await es.indices.exists({ index: 'metrics-test' })) { await es.indices.delete({ index: 'metrics-test' }); } - if ((await es.indices.exists({ index: 'logs-test' })).body) { + if (await es.indices.exists({ index: 'logs-test' })) { await es.indices.delete({ index: 'logs-test' }); } }); diff --git a/test/api_integration/apis/kql_telemetry/kql_telemetry.ts b/test/api_integration/apis/kql_telemetry/kql_telemetry.ts index 5770ed0866a90..4825b454bc42f 100644 --- a/test/api_integration/apis/kql_telemetry/kql_telemetry.ts +++ b/test/api_integration/apis/kql_telemetry/kql_telemetry.ts @@ -40,7 +40,7 @@ export default function ({ getService }: FtrProviderContext) { index: '.kibana', q: 'type:kql-telemetry', }) - .then(({ body: response }) => { + .then((response) => { const kqlTelemetryDoc = get(response, 'hits.hits[0]._source.kql-telemetry'); expect(kqlTelemetryDoc.optInCount).to.be(1); }); @@ -58,7 +58,7 @@ export default function ({ getService }: FtrProviderContext) { index: '.kibana', q: 'type:kql-telemetry', }) - .then(({ body: response }) => { + .then((response) => { const kqlTelemetryDoc = get(response, 'hits.hits[0]._source.kql-telemetry'); expect(kqlTelemetryDoc.optOutCount).to.be(1); }); diff --git a/test/api_integration/apis/saved_objects/delete_unknown_types.ts b/test/api_integration/apis/saved_objects/delete_unknown_types.ts index 42caa753683e1..af9e413de0279 100644 --- a/test/api_integration/apis/saved_objects/delete_unknown_types.ts +++ b/test/api_integration/apis/saved_objects/delete_unknown_types.ts @@ -31,7 +31,7 @@ export default function ({ getService }: FtrProviderContext) { }); const fetchIndexContent = async () => { - const { body } = await es.search<{ type: string }>({ + const body = await es.search<{ type: string }>({ index: '.kibana', body: { size: 100, diff --git a/test/api_integration/apis/saved_objects/migrations.ts b/test/api_integration/apis/saved_objects/migrations.ts index 0877998ca6c1f..cba62ee51763d 100644 --- a/test/api_integration/apis/saved_objects/migrations.ts +++ b/test/api_integration/apis/saved_objects/migrations.ts @@ -14,7 +14,8 @@ import uuidv5 from 'uuid/v5'; import { set } from '@elastic/safer-lodash-set'; import _ from 'lodash'; import expect from '@kbn/expect'; -import { ElasticsearchClient, SavedObjectsType } from 'src/core/server'; +import { SavedObjectsType } from 'src/core/server'; +import { Client as ElasticsearchClient } from '@elastic/elasticsearch'; import { DocumentMigrator, @@ -136,7 +137,7 @@ export default ({ getService }: FtrProviderContext) => { const migrationATemplate = await esClient.indices.existsTemplate({ name: 'migration_a_template', }); - expect(migrationATemplate.body).to.be.ok(); + expect(migrationATemplate).to.be.ok(); const result = await migrateIndex({ esClient, @@ -150,12 +151,12 @@ export default ({ getService }: FtrProviderContext) => { name: 'migration_a_template', }); - expect(migrationATemplateAfter.body).not.to.be.ok(); + expect(migrationATemplateAfter).not.to.be.ok(); const migrationTestATemplateAfter = await esClient.indices.existsTemplate({ name: 'migration_test_a_template', }); - expect(migrationTestATemplateAfter.body).to.be.ok(); + expect(migrationTestATemplateAfter).to.be.ok(); expect(_.omit(result, 'elapsedMs')).to.eql({ destIndex: '.migration-a_2', sourceIndex: '.migration-a_1', @@ -451,7 +452,7 @@ export default ({ getService }: FtrProviderContext) => { { status: 'skipped', destIndex: undefined }, ]); - const { body } = await esClient.cat.indices({ index: '.migration-c*', format: 'json' }); + const body = await esClient.cat.indices({ index: '.migration-c*', format: 'json' }); // It only created the original and the dest expect(_.map(body, 'index').sort()).to.eql(['.migration-c_1', '.migration-c_2']); @@ -747,7 +748,7 @@ async function migrateIndex({ } async function fetchDocs(esClient: ElasticsearchClient, index: string) { - const { body } = await esClient.search({ index }); + const body = await esClient.search({ index }); return body.hits.hits .map((h) => ({ diff --git a/test/api_integration/apis/saved_objects_management/find.ts b/test/api_integration/apis/saved_objects_management/find.ts index 0b744b7991b38..d877a62eedc82 100644 --- a/test/api_integration/apis/saved_objects_management/find.ts +++ b/test/api_integration/apis/saved_objects_management/find.ts @@ -202,7 +202,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'dashboard.show', }, - namespaceType: 'single', + namespaceType: 'multiple-isolated', }); })); @@ -249,7 +249,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/app/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'management.kibana.indexPatterns', }, - namespaceType: 'single', + namespaceType: 'multiple-isolated', }); })); }); diff --git a/test/api_integration/apis/saved_objects_management/relationships.ts b/test/api_integration/apis/saved_objects_management/relationships.ts index 518ec29947016..cc14ce0c76068 100644 --- a/test/api_integration/apis/saved_objects_management/relationships.ts +++ b/test/api_integration/apis/saved_objects_management/relationships.ts @@ -91,7 +91,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/app/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'management.kibana.indexPatterns', }, - namespaceType: 'single', + namespaceType: 'multiple-isolated', hiddenType: false, }, }, @@ -132,7 +132,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/app/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'management.kibana.indexPatterns', }, - namespaceType: 'single', + namespaceType: 'multiple-isolated', hiddenType: false, }, relationship: 'child', @@ -301,7 +301,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'dashboard.show', }, - namespaceType: 'single', + namespaceType: 'multiple-isolated', hiddenType: false, }, }, diff --git a/test/api_integration/apis/status/status.js b/test/api_integration/apis/status/status.js index e1545c448fce8..967d0290ad131 100644 --- a/test/api_integration/apis/status/status.js +++ b/test/api_integration/apis/status/status.js @@ -11,7 +11,8 @@ import expect from '@kbn/expect'; export default function ({ getService }) { const supertest = getService('supertest'); - describe('kibana status api', () => { + // Failing: See https://github.com/elastic/kibana/issues/116060 + describe.skip('kibana status api', () => { it('returns version, status and metrics fields', () => { return supertest .get('/api/status') diff --git a/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts b/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts index a76d09481eca1..a2c48996069b2 100644 --- a/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts +++ b/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts @@ -25,9 +25,7 @@ export default function optInTest({ getService }: FtrProviderContext) { await supertest.put('/api/telemetry/v2/userHasSeenNotice').set('kbn-xsrf', 'xxx').expect(200); - const { - body: { _source }, - } = await client.get<{ telemetry: { userHasSeenNotice: boolean } }>({ + const { _source } = await client.get<{ telemetry: { userHasSeenNotice: boolean } }>({ index: '.kibana', id: 'telemetry:telemetry', }); diff --git a/test/api_integration/apis/ui_metric/ui_metric.ts b/test/api_integration/apis/ui_metric/ui_metric.ts index 3f0a4c0778911..83f84af4eb9bd 100644 --- a/test/api_integration/apis/ui_metric/ui_metric.ts +++ b/test/api_integration/apis/ui_metric/ui_metric.ts @@ -50,7 +50,7 @@ export default function ({ getService }: FtrProviderContext) { .send({ report }) .expect(200); - const { body: response } = await es.search({ index: '.kibana', q: 'type:ui-metric' }); + const response = await es.search({ index: '.kibana', q: 'type:ui-metric' }); const ids = response.hits.hits.map(({ _id }: { _id: string }) => _id); expect(ids.includes('ui-metric:myApp:myEvent')).to.eql(true); }); @@ -75,7 +75,7 @@ export default function ({ getService }: FtrProviderContext) { .send({ report }) .expect(200); - const { body: response } = await es.search({ index: '.kibana', q: 'type:ui-metric' }); + const response = await es.search({ index: '.kibana', q: 'type:ui-metric' }); const ids = response.hits.hits.map(({ _id }: { _id: string }) => _id); expect(ids.includes('ui-metric:myApp:myEvent')).to.eql(true); expect(ids.includes(`ui-metric:myApp:${uniqueEventName}`)).to.eql(true); @@ -99,9 +99,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); const { - body: { - hits: { hits }, - }, + hits: { hits }, } = await es.search({ index: '.kibana', q: 'type:ui-metric' }); const countTypeEvent = hits.find( diff --git a/test/common/services/elasticsearch.ts b/test/common/services/elasticsearch.ts index 7b8ff6bd6c8f4..384f98e31bf3c 100644 --- a/test/common/services/elasticsearch.ts +++ b/test/common/services/elasticsearch.ts @@ -8,30 +8,31 @@ import { format as formatUrl } from 'url'; import fs from 'fs'; -import { Client } from '@elastic/elasticsearch'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; import { CA_CERT_PATH } from '@kbn/dev-utils'; -import type { KibanaClient } from '@elastic/elasticsearch/api/kibana'; import { FtrProviderContext } from '../ftr_provider_context'; /* registers Kibana-specific @elastic/elasticsearch client instance. */ -export function ElasticsearchProvider({ getService }: FtrProviderContext): KibanaClient { +export function ElasticsearchProvider({ getService }: FtrProviderContext): Client { const config = getService('config'); if (process.env.TEST_CLOUD) { return new Client({ nodes: [formatUrl(config.get('servers.elasticsearch'))], requestTimeout: config.get('timeouts.esRequestTimeout'), + Connection: HttpConnection, }); } else { return new Client({ - ssl: { + tls: { ca: fs.readFileSync(CA_CERT_PATH, 'utf-8'), }, nodes: [formatUrl(config.get('servers.elasticsearch'))], requestTimeout: config.get('timeouts.esRequestTimeout'), + Connection: HttpConnection, }); } } diff --git a/test/common/services/es_delete_all_indices.ts b/test/common/services/es_delete_all_indices.ts index 3443ef23c8ed0..c0ffa44c2e2c3 100644 --- a/test/common/services/es_delete_all_indices.ts +++ b/test/common/services/es_delete_all_indices.ts @@ -37,6 +37,7 @@ export function EsDeleteAllIndicesProvider({ getService }: FtrProviderContext) { }, { ignore: [404], + meta: true, } ); const indices = Object.keys(resp.body) as string[]; diff --git a/test/common/services/saved_object_info/saved_object_info.ts b/test/common/services/saved_object_info/saved_object_info.ts index 61472ea98d879..3442efcc98438 100644 --- a/test/common/services/saved_object_info/saved_object_info.ts +++ b/test/common/services/saved_object_info/saved_object_info.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Client } from '@elastic/elasticsearch'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; import url from 'url'; import { Either, fromNullable, chain, getOrElse, toError } from 'fp-ts/Either'; import { flow, pipe } from 'fp-ts/function'; @@ -37,7 +37,7 @@ export const types = await pipe( TE.tryCatch( async () => { - const { body } = await new Client({ node }).search({ + const body = await new Client({ node, Connection: HttpConnection }).search({ index, size: 0, body: query, diff --git a/test/common/services/security/test_user.ts b/test/common/services/security/test_user.ts index 695294f08b02d..1161e7b493f41 100644 --- a/test/common/services/security/test_user.ts +++ b/test/common/services/security/test_user.ts @@ -71,13 +71,12 @@ export class TestUser extends FtrService { export async function createTestUserService(ctx: FtrProviderContext, role: Role, user: User) { const log = ctx.getService('log'); const config = ctx.getService('config'); - const kibanaServer = ctx.getService('kibanaServer'); - const enabledPlugins = config.get('security.disableTestUser') - ? [] - : await kibanaServer.plugins.getEnabledIds(); - - const enabled = enabledPlugins.includes('security') && !config.get('security.disableTestUser'); + const enabled = + !config + .get('esTestCluster.serverArgs') + .some((arg: string) => arg === 'xpack.security.enabled=false') && + !config.get('security.disableTestUser'); if (enabled) { log.debug('===============creating roles and users==============='); diff --git a/test/functional/apps/context/_discover_navigation.ts b/test/functional/apps/context/_discover_navigation.ts index 1b8300f3345b1..60745bd64b8be 100644 --- a/test/functional/apps/context/_discover_navigation.ts +++ b/test/functional/apps/context/_discover_navigation.ts @@ -74,7 +74,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should open the context view with the same columns', async () => { const columnNames = await docTable.getHeaderFields(); - expect(columnNames).to.eql(['Time', ...TEST_COLUMN_NAMES]); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); }); it('should open the context view with the filters disabled', async () => { diff --git a/test/functional/apps/discover/_data_grid.ts b/test/functional/apps/discover/_data_grid.ts index 4a343fb30384e..198691f3b8477 100644 --- a/test/functional/apps/discover/_data_grid.ts +++ b/test/functional/apps/discover/_data_grid.ts @@ -39,19 +39,19 @@ export default function ({ const getTitles = async () => (await testSubjects.getVisibleText('dataGridHeader')).replace(/\s|\r?\n|\r/g, ' '); - expect(await getTitles()).to.be('Time (@timestamp) Document'); + expect(await getTitles()).to.be('@timestamp Document'); await PageObjects.discover.clickFieldListItemAdd('bytes'); - expect(await getTitles()).to.be('Time (@timestamp) bytes'); + expect(await getTitles()).to.be('@timestamp bytes'); await PageObjects.discover.clickFieldListItemAdd('agent'); - expect(await getTitles()).to.be('Time (@timestamp) bytes agent'); + expect(await getTitles()).to.be('@timestamp bytes agent'); await PageObjects.discover.clickFieldListItemRemove('bytes'); - expect(await getTitles()).to.be('Time (@timestamp) agent'); + expect(await getTitles()).to.be('@timestamp agent'); await PageObjects.discover.clickFieldListItemRemove('agent'); - expect(await getTitles()).to.be('Time (@timestamp) Document'); + expect(await getTitles()).to.be('@timestamp Document'); }); }); } diff --git a/test/functional/apps/discover/_data_grid_context.ts b/test/functional/apps/discover/_data_grid_context.ts index 3d9e01e1dee19..d12ada2070cff 100644 --- a/test/functional/apps/discover/_data_grid_context.ts +++ b/test/functional/apps/discover/_data_grid_context.ts @@ -76,7 +76,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should open the context view with the same columns', async () => { const columnNames = await dataGrid.getHeaderFields(); - expect(columnNames).to.eql(['Time (@timestamp)', ...TEST_COLUMN_NAMES]); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); }); it('should open the context view with the filters disabled', async () => { diff --git a/test/functional/apps/discover/_data_grid_field_data.ts b/test/functional/apps/discover/_data_grid_field_data.ts index 94e8e942f86ba..91c2d5914732d 100644 --- a/test/functional/apps/discover/_data_grid_field_data.ts +++ b/test/functional/apps/discover/_data_grid_field_data.ts @@ -59,8 +59,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('doc view should show Time and _source columns', async function () { - const expectedHeader = 'Time (@timestamp) Document'; + it('doc view should show @timestamp and _source columns', async function () { + const expectedHeader = '@timestamp Document'; const DocHeader = await dataGrid.getHeaderFields(); expect(DocHeader.join(' ')).to.be(expectedHeader); }); diff --git a/test/functional/apps/discover/_field_data.ts b/test/functional/apps/discover/_field_data.ts index 27407e9a0bc4d..28f147eeab55f 100644 --- a/test/functional/apps/discover/_field_data.ts +++ b/test/functional/apps/discover/_field_data.ts @@ -107,8 +107,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async function () { await kibanaServer.uiSettings.replace({}); }); - it('doc view should show Time and _source columns', async function () { - const expectedHeader = 'Time\n_source'; + it('doc view should show @timestamp and _source columns', async function () { + const expectedHeader = '@timestamp\n_source'; const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); const docHeaderText = await docHeader.getVisibleText(); expect(docHeaderText).to.be(expectedHeader); diff --git a/test/functional/apps/discover/_field_data_with_fields_api.ts b/test/functional/apps/discover/_field_data_with_fields_api.ts index 666377ae7f794..f0dedb155fc9b 100644 --- a/test/functional/apps/discover/_field_data_with_fields_api.ts +++ b/test/functional/apps/discover/_field_data_with_fields_api.ts @@ -64,9 +64,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('doc view should show Time and Document columns', async function () { + it('doc view should show @timestamp and Document columns', async function () { const Docheader = await PageObjects.discover.getDocHeader(); - expect(Docheader).to.contain('Time'); + expect(Docheader).to.contain('@timestamp'); expect(Docheader).to.contain('Document'); }); diff --git a/test/functional/apps/management/_field_formatter.ts b/test/functional/apps/management/_field_formatter.ts index 2377e714418ee..838d20ccdfb50 100644 --- a/test/functional/apps/management/_field_formatter.ts +++ b/test/functional/apps/management/_field_formatter.ts @@ -423,7 +423,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { let testDocumentId: string; before(async () => { - if ((await es.indices.exists({ index: indexTitle })).body) { + if (await es.indices.exists({ index: indexTitle })) { await es.indices.delete({ index: indexTitle }); } @@ -447,7 +447,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }, {} as Record), refresh: 'wait_for', }); - testDocumentId = docResult.body._id; + testDocumentId = docResult._id; const indexPatternResult = await indexPatterns.create( { title: indexTitle }, diff --git a/test/functional/apps/management/_handle_version_conflict.js b/test/functional/apps/management/_handle_version_conflict.js index 89426805bd503..a04c5d34b2d35 100644 --- a/test/functional/apps/management/_handle_version_conflict.js +++ b/test/functional/apps/management/_handle_version_conflict.js @@ -45,13 +45,16 @@ export default function ({ getService, getPageObjects }) { await PageObjects.settings.clickAddScriptedField(); await PageObjects.settings.setScriptedFieldName(scriptedFiledName); await PageObjects.settings.setScriptedFieldScript(`doc['bytes'].value`); - const response = await es.update({ - index: '.kibana', - id: 'index-pattern:logstash-*', - body: { - doc: { 'index-pattern': { fieldFormatMap: '{"geo.src":{"id":"number"}}' } }, + const response = await es.update( + { + index: '.kibana', + id: 'index-pattern:logstash-*', + body: { + doc: { 'index-pattern': { fieldFormatMap: '{"geo.src":{"id":"number"}}' } }, + }, }, - }); + { meta: true } + ); log.debug(JSON.stringify(response)); expect(response.body.result).to.be('updated'); await PageObjects.settings.setFieldFormat('url'); @@ -76,13 +79,16 @@ export default function ({ getService, getPageObjects }) { ).findAllByCssSelector('[data-test-subj="toggle"]') )[0].click(); await PageObjects.settings.setFieldFormat('url'); - const response = await es.update({ - index: '.kibana', - id: 'index-pattern:logstash-*', - body: { - doc: { 'index-pattern': { fieldFormatMap: '{"geo.dest":{"id":"number"}}' } }, + const response = await es.update( + { + index: '.kibana', + id: 'index-pattern:logstash-*', + body: { + doc: { 'index-pattern': { fieldFormatMap: '{"geo.dest":{"id":"number"}}' } }, + }, }, - }); + { meta: true } + ); log.debug(JSON.stringify(response)); expect(response.body.result).to.be('updated'); await PageObjects.settings.controlChangeSave(); diff --git a/test/functional/apps/visualize/_timelion.ts b/test/functional/apps/visualize/_timelion.ts index bb85b6821df31..c531ada8a2573 100644 --- a/test/functional/apps/visualize/_timelion.ts +++ b/test/functional/apps/visualize/_timelion.ts @@ -257,7 +257,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(value).to.eql('.es()'); }); - describe('dynamic suggestions for argument values', () => { + // FLAKY: https://github.com/elastic/kibana/issues/116033 + describe.skip('dynamic suggestions for argument values', () => { describe('.es()', () => { it('should show index pattern suggestions for index argument', async () => { await monacoEditor.setCodeEditorValue(''); diff --git a/test/functional/config.js b/test/functional/config.js index e0195c4dadc8d..5b0b79e84e8df 100644 --- a/test/functional/config.js +++ b/test/functional/config.js @@ -45,7 +45,6 @@ export default async function ({ readConfigFile }) { '--savedObjects.maxImportPayloadBytes=10485760', // to be re-enabled once kibana/issues/102552 is completed - '--xpack.security.enabled=false', '--xpack.reporting.enabled=false', ], }, diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index a45c1a23ed3a5..fa7aee4e3c54c 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -83,6 +83,10 @@ export class DiscoverPageObject extends FtrService { await this.testSubjects.click('addFilter'); } + public async closeAddFilterPanel() { + await this.testSubjects.click('addFilter'); + } + public async waitUntilSearchingHasFinished() { await this.testSubjects.missingOrFail('loadingSpinner', { timeout: this.defaultFindTimeout * 10, diff --git a/test/functional/services/filter_bar.ts b/test/functional/services/filter_bar.ts index 1d0b85eed3a9c..5d189506c314d 100644 --- a/test/functional/services/filter_bar.ts +++ b/test/functional/services/filter_bar.ts @@ -199,5 +199,6 @@ export class FilterBarService extends FtrService { public async selectIndexPattern(indexPatternTitle: string): Promise { await this.testSubjects.click('addFilter'); await this.comboBox.set('filterIndexPatternsSelect', indexPatternTitle); + await this.testSubjects.click('addFilter'); } } diff --git a/test/interactive_setup_api_integration/manual_configuration_flow_without_tls.config.ts b/test/interactive_setup_api_integration/manual_configuration_flow_without_tls.config.ts index 5317026a1d8dc..16d98c00768c0 100644 --- a/test/interactive_setup_api_integration/manual_configuration_flow_without_tls.config.ts +++ b/test/interactive_setup_api_integration/manual_configuration_flow_without_tls.config.ts @@ -46,7 +46,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { .filter((arg: string) => !arg.startsWith('--elasticsearch.')), `--plugin-path=${testEndpointsPlugin}`, `--config=${tempKibanaYamlFile}`, - '--interactiveSetup.enabled=true', ], runOptions: { ...xPackAPITestsConfig.get('kbnTestServer.runOptions'), diff --git a/test/interactive_setup_api_integration/tests/enrollment_flow.ts b/test/interactive_setup_api_integration/tests/enrollment_flow.ts index 9f61529cc3439..53454207b73ed 100644 --- a/test/interactive_setup_api_integration/tests/enrollment_flow.ts +++ b/test/interactive_setup_api_integration/tests/enrollment_flow.ts @@ -38,9 +38,7 @@ export default function (context: FtrProviderContext) { let enrollmentAPIKey: string; beforeEach(async () => { const apiResponse = await es.security.createApiKey({ body: { name: 'enrollment_api_key' } }); - enrollmentAPIKey = Buffer.from(`${apiResponse.body.id}:${apiResponse.body.api_key}`).toString( - 'base64' - ); + enrollmentAPIKey = Buffer.from(`${apiResponse.id}:${apiResponse.api_key}`).toString('base64'); }); afterEach(async () => { diff --git a/test/interactive_setup_functional/enrollment_token.config.ts b/test/interactive_setup_functional/enrollment_token.config.ts new file mode 100644 index 0000000000000..9c9f270ed0fc1 --- /dev/null +++ b/test/interactive_setup_functional/enrollment_token.config.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { join, resolve } from 'path'; + +import type { FtrConfigProviderContext } from '@kbn/test'; +import { getDataPath } from '@kbn/utils'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const manualConfigurationConfig = await readConfigFile( + require.resolve('./manual_configuration.config.ts') + ); + + const tempKibanaYamlFile = join(getDataPath(), `interactive_setup_kibana_${Date.now()}.yml`); + await fs.writeFile(tempKibanaYamlFile, ''); + + const caPath = resolve( + __dirname, + '../interactive_setup_api_integration/fixtures/elasticsearch.p12' + ); + + return { + ...manualConfigurationConfig.getAll(), + + testFiles: [require.resolve('./tests/enrollment_token')], + + junit: { + reportName: 'Interactive Setup Functional Tests (Enrollment token)', + }, + + esTestCluster: { + ...manualConfigurationConfig.get('esTestCluster'), + serverArgs: [ + ...manualConfigurationConfig.get('esTestCluster.serverArgs'), + 'xpack.security.enrollment.enabled=true', + `xpack.security.http.ssl.keystore.path=${caPath}`, + 'xpack.security.http.ssl.keystore.password=storepass', + ], + }, + + kbnTestServer: { + ...manualConfigurationConfig.get('kbnTestServer'), + serverArgs: [ + ...manualConfigurationConfig + .get('kbnTestServer.serverArgs') + .filter((arg: string) => !arg.startsWith('--config')), + `--config=${tempKibanaYamlFile}`, + ], + }, + }; +} diff --git a/test/interactive_setup_functional/manual_configuration.config.ts b/test/interactive_setup_functional/manual_configuration.config.ts new file mode 100644 index 0000000000000..6199e918c3608 --- /dev/null +++ b/test/interactive_setup_functional/manual_configuration.config.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { join } from 'path'; + +import type { FtrConfigProviderContext } from '@kbn/test'; +import { getDataPath } from '@kbn/utils'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const withoutTlsConfig = await readConfigFile( + require.resolve('./manual_configuration_without_tls.config.ts') + ); + + const tempKibanaYamlFile = join(getDataPath(), `interactive_setup_kibana_${Date.now()}.yml`); + await fs.writeFile(tempKibanaYamlFile, ''); + + return { + ...withoutTlsConfig.getAll(), + + testFiles: [require.resolve('./tests/manual_configuration')], + + servers: { + ...withoutTlsConfig.get('servers'), + elasticsearch: { + ...withoutTlsConfig.get('servers.elasticsearch'), + protocol: 'https', + }, + }, + + junit: { + reportName: 'Interactive Setup Functional Tests (Manual configuration)', + }, + + esTestCluster: { + ...withoutTlsConfig.get('esTestCluster'), + ssl: true, + }, + + kbnTestServer: { + ...withoutTlsConfig.get('kbnTestServer'), + serverArgs: [ + ...withoutTlsConfig + .get('kbnTestServer.serverArgs') + .filter((arg: string) => !arg.startsWith('--config')), + `--config=${tempKibanaYamlFile}`, + ], + }, + }; +} diff --git a/test/interactive_setup_functional/manual_configuration_without_security.config.ts b/test/interactive_setup_functional/manual_configuration_without_security.config.ts new file mode 100644 index 0000000000000..953b33d4e2077 --- /dev/null +++ b/test/interactive_setup_functional/manual_configuration_without_security.config.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { join, resolve } from 'path'; + +import type { FtrConfigProviderContext } from '@kbn/test'; +import { getDataPath } from '@kbn/utils'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../functional/config')); + + const testEndpointsPlugin = resolve( + __dirname, + '../interactive_setup_api_integration/fixtures/test_endpoints' + ); + + const tempKibanaYamlFile = join(getDataPath(), `interactive_setup_kibana_${Date.now()}.yml`); + await fs.writeFile(tempKibanaYamlFile, ''); + + return { + ...functionalConfig.getAll(), + + testFiles: [require.resolve('./tests/manual_configuration_without_security')], + + junit: { + reportName: 'Interactive Setup Functional Tests (Manual configuration without Security)', + }, + + security: { disableTestUser: true }, + + esTestCluster: { + ...functionalConfig.get('esTestCluster'), + serverArgs: [ + ...functionalConfig + .get('esTestCluster.serverArgs') + .filter((arg: string) => !arg.startsWith('xpack.security.')), + 'xpack.security.enabled=false', + ], + }, + + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig + .get('kbnTestServer.serverArgs') + .filter((arg: string) => !arg.startsWith('--elasticsearch.')), + `--plugin-path=${testEndpointsPlugin}`, + `--config=${tempKibanaYamlFile}`, + ], + runOptions: { + ...functionalConfig.get('kbnTestServer.runOptions'), + wait: /Kibana has not been configured/, + }, + }, + + uiSettings: {}, // UI settings can't be set during `preboot` stage + }; +} diff --git a/test/interactive_setup_functional/manual_configuration_without_tls.config.ts b/test/interactive_setup_functional/manual_configuration_without_tls.config.ts new file mode 100644 index 0000000000000..306e1128d5f8f --- /dev/null +++ b/test/interactive_setup_functional/manual_configuration_without_tls.config.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { join } from 'path'; + +import type { FtrConfigProviderContext } from '@kbn/test'; +import { getDataPath } from '@kbn/utils'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const withoutSecurityConfig = await readConfigFile( + require.resolve('./manual_configuration_without_security.config') + ); + + const tempKibanaYamlFile = join(getDataPath(), `interactive_setup_kibana_${Date.now()}.yml`); + await fs.writeFile(tempKibanaYamlFile, ''); + + return { + ...withoutSecurityConfig.getAll(), + + testFiles: [require.resolve('./tests/manual_configuration_without_tls')], + + junit: { + reportName: 'Interactive Setup Functional Tests (Manual configuration without TLS)', + }, + + esTestCluster: { + ...withoutSecurityConfig.get('esTestCluster'), + serverArgs: [ + ...withoutSecurityConfig + .get('esTestCluster.serverArgs') + .filter((arg: string) => !arg.startsWith('xpack.security.')), + 'xpack.security.enabled=true', + ], + }, + + kbnTestServer: { + ...withoutSecurityConfig.get('kbnTestServer'), + serverArgs: [ + ...withoutSecurityConfig + .get('kbnTestServer.serverArgs') + .filter((arg: string) => !arg.startsWith('--config')), + `--config=${tempKibanaYamlFile}`, + ], + }, + }; +} diff --git a/test/interactive_setup_functional/tests/enrollment_token.ts b/test/interactive_setup_functional/tests/enrollment_token.ts new file mode 100644 index 0000000000000..56311c9458cef --- /dev/null +++ b/test/interactive_setup_functional/tests/enrollment_token.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { kibanaPackageJson } from '@kbn/utils'; + +import type { FtrProviderContext } from '../../functional/ftr_provider_context'; +import { getElasticsearchCaCertificate } from '../../interactive_setup_api_integration/fixtures/tls_tools'; + +export default function ({ getService }: FtrProviderContext) { + const browser = getService('browser'); + const find = getService('find'); + const supertest = getService('supertest'); + const deployment = getService('deployment'); + const es = getService('es'); + const config = getService('config'); + const retry = getService('retry'); + const log = getService('log'); + + describe('Interactive Setup Functional Tests (Enrollment token)', function () { + this.tags(['skipCloud', 'ciGroup2']); + + const elasticsearchConfig = config.get('servers.elasticsearch'); + let verificationCode: string; + let caFingerprint: string; + before(async function () { + verificationCode = (await supertest.get('/test_endpoints/verification_code').expect(200)).body + .verificationCode; + log.info(`Verification code: ${verificationCode}`); + + caFingerprint = ( + await getElasticsearchCaCertificate(elasticsearchConfig.hostname, elasticsearchConfig.port) + ).fingerprint256 + .replace(/:/g, '') + .toLowerCase(); + log.info(`Elasticsearch ca fingerprint: ${caFingerprint}`); + }); + + let enrollmentAPIKey: string; + beforeEach(async function () { + const apiResponse = await es.security.createApiKey({ body: { name: 'enrollment_api_key' } }); + enrollmentAPIKey = `${apiResponse.id}:${apiResponse.api_key}`; + log.info(`API key for enrollment token: ${enrollmentAPIKey}`); + }); + + afterEach(async function () { + await es.security.invalidateApiKey({ body: { name: 'enrollment_api_key' } }); + }); + + it('should configure Kibana successfully', async function () { + this.timeout(150_000); + + const enrollmentToken = btoa( + JSON.stringify({ + ver: kibanaPackageJson.version, + adr: [`${elasticsearchConfig.hostname}:${elasticsearchConfig.port}`], + fgr: caFingerprint, + key: enrollmentAPIKey, + }) + ); + + await browser.get(`${deployment.getHostPort()}?code=${verificationCode}`); + const initialUrl = await browser.getCurrentUrl(); + log.info(`Opened interactive setup: ${initialUrl}`); + + const tokenField = await find.byName('token'); + await tokenField.clearValueWithKeyboard(); + await tokenField.type(enrollmentToken); + log.info(`Entered enrollment token: ${enrollmentToken}`); + + await find.clickByButtonText('Configure Elastic'); + log.info('Submitted form'); + + await retry.waitForWithTimeout('redirect to login page', 120_000, async () => { + log.debug(`Current URL: ${await browser.getCurrentUrl()}, initial URL: ${initialUrl}`); + return (await browser.getCurrentUrl()) !== initialUrl; + }); + }); + }); +} + +function btoa(str: string) { + return Buffer.from(str, 'binary').toString('base64'); +} diff --git a/test/interactive_setup_functional/tests/manual_configuration.ts b/test/interactive_setup_functional/tests/manual_configuration.ts new file mode 100644 index 0000000000000..3c7c5d9c08d76 --- /dev/null +++ b/test/interactive_setup_functional/tests/manual_configuration.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getUrl, kibanaServerTestUser } from '@kbn/test'; +import type { FtrProviderContext } from '../../functional/ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const browser = getService('browser'); + const find = getService('find'); + const supertest = getService('supertest'); + const deployment = getService('deployment'); + const config = getService('config'); + const retry = getService('retry'); + const log = getService('log'); + + describe('Interactive Setup Functional Tests (Manual configuration)', function () { + this.tags(['skipCloud', 'ciGroup2']); + + let verificationCode: string; + before(async function () { + verificationCode = (await supertest.get('/test_endpoints/verification_code').expect(200)).body + .verificationCode; + }); + + it('should configure Kibana successfully', async function () { + this.timeout(150_000); + + await browser.get(`${deployment.getHostPort()}?code=${verificationCode}`); + const url = await browser.getCurrentUrl(); + + await find.clickByButtonText('Configure manually'); + + const elasticsearchHost = getUrl.baseUrl(config.get('servers.elasticsearch')); + const hostField = await find.byName('host'); + await hostField.clearValueWithKeyboard(); + await hostField.type(elasticsearchHost); + + await find.clickByButtonText('Check address'); + + const usernameField = await find.byName('username'); + await usernameField.clearValueWithKeyboard(); + await usernameField.type(kibanaServerTestUser.username); + + const passwordField = await find.byName('password'); + await passwordField.clearValueWithKeyboard(); + await passwordField.type(kibanaServerTestUser.password); + + const caCertField = await find.byCssSelector('input[type="checkbox"]'); + if (!(await caCertField.isSelected())) { + const id = await caCertField.getAttribute('id'); + await find.clickByCssSelector(`label[for="${id}"]`); + } + + await find.clickByButtonText('Configure Elastic'); + + await retry.waitForWithTimeout('redirect to login page', 120_000, async () => { + log.debug(`Current URL: ${await browser.getCurrentUrl()}, initial URL: ${url}`); + return (await browser.getCurrentUrl()) !== url; + }); + }); + }); +} diff --git a/test/interactive_setup_functional/tests/manual_configuration_without_security.ts b/test/interactive_setup_functional/tests/manual_configuration_without_security.ts new file mode 100644 index 0000000000000..2111dc3cce7e7 --- /dev/null +++ b/test/interactive_setup_functional/tests/manual_configuration_without_security.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getUrl } from '@kbn/test'; +import type { FtrProviderContext } from '../../functional/ftr_provider_context'; + +export default function ({ getService, getPageObject }: FtrProviderContext) { + const browser = getService('browser'); + const find = getService('find'); + const supertest = getService('supertest'); + const deployment = getService('deployment'); + const config = getService('config'); + const retry = getService('retry'); + const log = getService('log'); + + describe('Interactive Setup Functional Tests (Manual configuration without Security)', function () { + this.tags(['skipCloud', 'ciGroup2']); + + let verificationCode: string; + before(async function () { + verificationCode = (await supertest.get('/test_endpoints/verification_code').expect(200)).body + .verificationCode; + }); + + it('should configure Kibana successfully', async function () { + this.timeout(150_000); + + await browser.get(`${deployment.getHostPort()}?code=${verificationCode}`); + const url = await browser.getCurrentUrl(); + + await find.clickByButtonText('Configure manually'); + + const elasticsearchHost = getUrl.baseUrl(config.get('servers.elasticsearch')); + const hostField = await find.byName('host'); + await hostField.clearValueWithKeyboard(); + await hostField.type(elasticsearchHost); + + await find.clickByButtonText('Check address'); + + await find.clickByButtonText('Configure Elastic'); + + await retry.waitForWithTimeout('redirect to home page', 120_000, async () => { + log.debug(`Current URL: ${await browser.getCurrentUrl()}, initial URL: ${url}`); + return (await browser.getCurrentUrl()) !== url; + }); + }); + }); +} diff --git a/test/interactive_setup_functional/tests/manual_configuration_without_tls.ts b/test/interactive_setup_functional/tests/manual_configuration_without_tls.ts new file mode 100644 index 0000000000000..b8e391dc6f93f --- /dev/null +++ b/test/interactive_setup_functional/tests/manual_configuration_without_tls.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getUrl, kibanaServerTestUser } from '@kbn/test'; +import type { FtrProviderContext } from '../../functional/ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const browser = getService('browser'); + const find = getService('find'); + const supertest = getService('supertest'); + const deployment = getService('deployment'); + const config = getService('config'); + const retry = getService('retry'); + const log = getService('log'); + + describe('Interactive Setup Functional Tests (Manual configuration without TLS)', function () { + this.tags(['skipCloud', 'ciGroup2']); + + let verificationCode: string; + before(async function () { + verificationCode = (await supertest.get('/test_endpoints/verification_code').expect(200)).body + .verificationCode; + }); + + it('should configure Kibana successfully', async function () { + this.timeout(150_000); + + await browser.get(`${deployment.getHostPort()}?code=${verificationCode}`); + const url = await browser.getCurrentUrl(); + + await find.clickByButtonText('Configure manually'); + + const elasticsearchHost = getUrl.baseUrl(config.get('servers.elasticsearch')); + const hostField = await find.byName('host'); + await hostField.clearValueWithKeyboard(); + await hostField.type(elasticsearchHost); + + await find.clickByButtonText('Check address'); + + const usernameField = await find.byName('username'); + await usernameField.clearValueWithKeyboard(); + await usernameField.type(kibanaServerTestUser.username); + + const passwordField = await find.byName('password'); + await passwordField.clearValueWithKeyboard(); + await passwordField.type(kibanaServerTestUser.password); + + await find.clickByButtonText('Configure Elastic'); + + await retry.waitForWithTimeout('redirect to login page', 120_000, async () => { + log.debug(`Current URL: ${await browser.getCurrentUrl()}, initial URL: ${url}`); + return (await browser.getCurrentUrl()) !== url; + }); + }); + }); +} diff --git a/vars/tasks.groovy b/vars/tasks.groovy index da18d73e5b36c..0f509fa8ba132 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -135,6 +135,8 @@ def functionalXpack(Map params = [:]) { whenChanged([ 'x-pack/plugins/security_solution/', + 'x-pack/plugins/cases/', + 'x-pack/plugins/timelines/', 'x-pack/test/security_solution_cypress/', 'x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/', 'x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx', @@ -146,13 +148,13 @@ def functionalXpack(Map params = [:]) { } } - // whenChanged([ - // 'x-pack/plugins/apm/', - // ]) { - // if (githubPr.isPr()) { - // task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) - // } - // } + whenChanged([ + 'x-pack/plugins/apm/', + ]) { + if (githubPr.isPr()) { + task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) + } + } whenChanged([ 'x-pack/plugins/uptime/', diff --git a/x-pack/plugins/actions/server/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client.test.ts index ca51b1cdfea1b..5f6260eb2451c 100644 --- a/x-pack/plugins/actions/server/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client.test.ts @@ -353,6 +353,36 @@ describe('create()', () => { ); }); + test('validates connector: config and secrets', async () => { + const connectorValidator = ({}, secrets: { param1: '1' }) => { + if (secrets.param1 == null) { + return '[param1] is required'; + } + return null; + }; + actionTypeRegistry.register({ + id: 'my-action-type', + name: 'My action type', + minimumLicenseRequired: 'basic', + validate: { + connector: connectorValidator, + }, + executor, + }); + await expect( + actionsClient.create({ + action: { + name: 'my name', + actionTypeId: 'my-action-type', + config: {}, + secrets: {}, + }, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: [param1] is required"` + ); + }); + test(`throws an error when an action type doesn't exist`, async () => { await expect( actionsClient.create({ @@ -1539,6 +1569,40 @@ describe('update()', () => { ); }); + test('validates connector: config and secrets', async () => { + actionTypeRegistry.register({ + id: 'my-action-type', + name: 'My action type', + minimumLicenseRequired: 'basic', + validate: { + connector: () => { + return '[param1] is required'; + }, + }, + executor, + }); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ + id: 'my-action', + type: 'action', + attributes: { + actionTypeId: 'my-action-type', + }, + references: [], + }); + await expect( + actionsClient.update({ + id: 'my-action', + action: { + name: 'my name', + config: {}, + secrets: {}, + }, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: [param1] is required"` + ); + }); + test('encrypts action type options unless specified not to', async () => { actionTypeRegistry.register({ id: 'my-action-type', diff --git a/x-pack/plugins/actions/server/actions_client.ts b/x-pack/plugins/actions/server/actions_client.ts index b391e50283ad1..deaa1a79d1640 100644 --- a/x-pack/plugins/actions/server/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { UsageCounter } from 'src/plugins/usage_collection/server'; import { i18n } from '@kbn/i18n'; @@ -22,7 +22,7 @@ import { import { AuditLogger } from '../../security/server'; import { ActionType } from '../common'; import { ActionTypeRegistry } from './action_type_registry'; -import { validateConfig, validateSecrets, ActionExecutorContract } from './lib'; +import { validateConfig, validateSecrets, ActionExecutorContract, validateConnector } from './lib'; import { ActionResult, FindActionResult, @@ -150,7 +150,9 @@ export class ActionsClient { const actionType = this.actionTypeRegistry.get(actionTypeId); const validatedActionTypeConfig = validateConfig(actionType, config); const validatedActionTypeSecrets = validateSecrets(actionType, secrets); - + if (actionType.validate?.connector) { + validateConnector(actionType, { config, secrets }); + } this.actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); this.auditLogger?.log( @@ -221,6 +223,9 @@ export class ActionsClient { const actionType = this.actionTypeRegistry.get(actionTypeId); const validatedActionTypeConfig = validateConfig(actionType, config); const validatedActionTypeSecrets = validateSecrets(actionType, secrets); + if (actionType.validate?.connector) { + validateConnector(actionType, { config, secrets }); + } this.actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts index 710f0c84f0cef..48110e29ff911 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts @@ -12,7 +12,7 @@ jest.mock('./lib/send_email', () => ({ import { Logger } from '../../../../../src/core/server'; import { actionsConfigMock } from '../actions_config.mock'; -import { validateConfig, validateSecrets, validateParams } from '../lib'; +import { validateConfig, validateConnector, validateParams, validateSecrets } from '../lib'; import { createActionTypeRegistry } from './index.test'; import { sendEmail } from './lib/send_email'; import { actionsMock } from '../mocks'; @@ -303,6 +303,75 @@ describe('secrets validation', () => { }); }); +describe('connector validation: secrets with config', () => { + test('connector validation succeeds when username/password was populated for hasAuth true', () => { + const secrets: Record = { + user: 'bob', + password: 'supersecret', + }; + const config: Record = { + hasAuth: true, + }; + expect(validateConnector(actionType, { config, secrets })).toBeNull(); + }); + + test('connector validation succeeds when username/password not filled for hasAuth false', () => { + const secrets: Record = { + user: null, + password: null, + clientSecret: null, + }; + const config: Record = { + hasAuth: false, + }; + expect(validateConnector(actionType, { config, secrets })).toBeNull(); + expect(validateConnector(actionType, { config, secrets: {} })).toBeNull(); + expect(validateConnector(actionType, { config, secrets: { user: null } })).toBeNull(); + expect(validateConnector(actionType, { config, secrets: { password: null } })).toBeNull(); + }); + + test('connector validation fails when username/password was populated for hasAuth true', () => { + const secrets: Record = { + password: null, + user: null, + }; + const config: Record = { + hasAuth: true, + }; + // invalid user + expect(() => { + validateConnector(actionType, { config, secrets }); + }).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: [user] is required"` + ); + }); + + test('connector validation succeeds when service is exchange_server and clientSecret is populated', () => { + const secrets: Record = { + clientSecret: '12345678', + }; + const config: Record = { + service: 'exchange_server', + }; + expect(validateConnector(actionType, { config, secrets })).toBeNull(); + }); + + test('connector validation fails when service is exchange_server and clientSecret is not populated', () => { + const secrets: Record = { + clientSecret: null, + }; + const config: Record = { + service: 'exchange_server', + }; + // invalid user + expect(() => { + validateConnector(actionType, { config, secrets }); + }).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: [clientSecret] is required"` + ); + }); +}); + describe('params validation', () => { test('params validation succeeds when params is valid', () => { const params: Record = { diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.ts b/x-pack/plugins/actions/server/builtin_action_types/email.ts index fcd003286d5bb..624fb2b418f48 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.ts @@ -116,11 +116,13 @@ function validateConfig( export type ActionTypeSecretsType = TypeOf; -const SecretsSchema = schema.object({ +const SecretsSchemaProps = { user: schema.nullable(schema.string()), password: schema.nullable(schema.string()), clientSecret: schema.nullable(schema.string()), -}); +}; + +const SecretsSchema = schema.object(SecretsSchemaProps); // params definition @@ -167,6 +169,25 @@ interface GetActionTypeParams { configurationUtilities: ActionsConfigurationUtilities; } +function validateConnector( + config: ActionTypeConfigType, + secrets: ActionTypeSecretsType +): string | null { + if (config.service === AdditionalEmailServices.EXCHANGE) { + if (secrets.clientSecret == null) { + return '[clientSecret] is required'; + } + } else if (config.hasAuth && (secrets.password == null || secrets.user == null)) { + if (secrets.user == null) { + return '[user] is required'; + } + if (secrets.password == null) { + return '[password] is required'; + } + } + return null; +} + // action type definition export const ActionTypeId = '.email'; export function getActionType(params: GetActionTypeParams): EmailActionType { @@ -183,6 +204,7 @@ export function getActionType(params: GetActionTypeParams): EmailActionType { }), secrets: SecretsSchema, params: ParamsSchema, + connector: validateConnector, }, renderParameterTemplates, executor: curry(executor)({ logger, publicBaseUrl, configurationUtilities }), diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts index 738fa236f89c0..50a1deba5af20 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts @@ -8,7 +8,7 @@ jest.mock('./lib/send_email', () => ({ sendEmail: jest.fn(), })); - +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { validateConfig, validateParams } from '../lib'; import { createActionTypeRegistry } from './index.test'; import { actionsMock } from '../mocks'; @@ -216,10 +216,12 @@ describe('execute()', () => { }); const calls = scopedClusterClient.bulk.mock.calls; - const timeValue = ((calls[0][0]?.body as unknown[])[1] as Record) - .field_to_use_for_time; + const timeValue = ( + ((calls[0][0] as estypes.BulkRequest)?.body as unknown[])[1] as Record + ).field_to_use_for_time; expect(timeValue).toBeInstanceOf(Date); - delete ((calls[0][0]?.body as unknown[])[1] as Record).field_to_use_for_time; + delete (((calls[0][0] as estypes.BulkRequest)?.body as unknown[])[1] as Record) + .field_to_use_for_time; expect(calls).toMatchInlineSnapshot(` Array [ Array [ diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.test.ts index 358af7cd2e9ef..e5a161611fcb1 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.test.ts @@ -132,7 +132,7 @@ describe('api_sir', () => { }); describe('prepareParams', () => { - test('it prepares the params correctly when the connector is legacy', async () => { + test('it prepares the params correctly when the connector uses the old API', async () => { expect(prepareParams(true, sirParams)).toEqual({ ...sirParams, incident: { @@ -145,7 +145,7 @@ describe('api_sir', () => { }); }); - test('it prepares the params correctly when the connector is not legacy', async () => { + test('it prepares the params correctly when the connector does not uses the old API', async () => { expect(prepareParams(false, sirParams)).toEqual({ ...sirParams, incident: { @@ -158,7 +158,7 @@ describe('api_sir', () => { }); }); - test('it prepares the params correctly when the connector is legacy and the observables are undefined', async () => { + test('it prepares the params correctly when the connector uses the old API and the observables are undefined', async () => { const { dest_ip: destIp, source_ip: sourceIp, @@ -192,7 +192,7 @@ describe('api_sir', () => { const res = await apiSIR.pushToService({ externalService, params, - config: { isLegacy: false }, + config: { usesTableApi: false }, secrets: {}, logger: mockedLogger, commentFieldKey: 'work_notes', @@ -221,7 +221,7 @@ describe('api_sir', () => { await apiSIR.pushToService({ externalService, params, - config: { isLegacy: false }, + config: { usesTableApi: false }, secrets: {}, logger: mockedLogger, commentFieldKey: 'work_notes', @@ -244,12 +244,12 @@ describe('api_sir', () => { ); }); - test('it does not call bulkAddObservableToIncident if it a legacy connector', async () => { + test('it does not call bulkAddObservableToIncident if the connector uses the old API', async () => { const params = { ...sirParams, incident: { ...sirParams.incident, externalId: null } }; await apiSIR.pushToService({ externalService, params, - config: { isLegacy: true }, + config: { usesTableApi: true }, secrets: {}, logger: mockedLogger, commentFieldKey: 'work_notes', @@ -274,7 +274,7 @@ describe('api_sir', () => { await apiSIR.pushToService({ externalService, params, - config: { isLegacy: false }, + config: { usesTableApi: false }, secrets: {}, logger: mockedLogger, commentFieldKey: 'work_notes', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.ts index 326bb79a0e708..4e74d79c6f4a0 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api_sir.ts @@ -59,13 +59,13 @@ const observablesToString = (obs: string | string[] | null | undefined): string }; export const prepareParams = ( - isLegacy: boolean, + usesTableApi: boolean, params: PushToServiceApiParamsSIR ): PushToServiceApiParamsSIR => { - if (isLegacy) { + if (usesTableApi) { /** * The schema has change to accept an array of observables - * or a string. In the case of a legacy connector we need to + * or a string. In the case of connector that uses the old API we need to * convert the observables to a string */ return { @@ -81,8 +81,8 @@ export const prepareParams = ( } /** - * For non legacy connectors the observables - * will be added in a different call. + * For connectors that do not use the old API + * the observables will be added in a different call. * They need to be set to null when sending the fields * to ServiceNow */ @@ -108,7 +108,7 @@ const pushToServiceHandler = async ({ }: PushToServiceApiHandlerArgs): Promise => { const res = await api.pushToService({ externalService, - params: prepareParams(!!config.isLegacy, params as PushToServiceApiParamsSIR), + params: prepareParams(!!config.usesTableApi, params as PushToServiceApiParamsSIR), config, secrets, commentFieldKey, @@ -130,7 +130,7 @@ const pushToServiceHandler = async ({ * through the pushToService call. */ - if (!config.isLegacy) { + if (!config.usesTableApi) { const sirExternalService = externalService as ExternalServiceSIR; const obsWithType: Array<[string[], ObservableTypes]> = [ diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts index af8d1b9f38b17..e41eea24834c7 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts @@ -14,7 +14,7 @@ export const ExternalIncidentServiceConfigurationBase = { export const ExternalIncidentServiceConfiguration = { ...ExternalIncidentServiceConfigurationBase, - isLegacy: schema.boolean({ defaultValue: true }), + usesTableApi: schema.boolean({ defaultValue: true }), }; export const ExternalIncidentServiceConfigurationBaseSchema = schema.object( @@ -49,7 +49,7 @@ const CommonAttributes = { externalId: schema.nullable(schema.string()), category: schema.nullable(schema.string()), subcategory: schema.nullable(schema.string()), - correlation_id: schema.nullable(schema.string()), + correlation_id: schema.nullable(schema.string({ defaultValue: DEFAULT_ALERTS_GROUPING_KEY })), correlation_display: schema.nullable(schema.string()), }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index cb030c7bb6933..c90a7222ba10b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -35,7 +35,8 @@ export const createExternalService: ServiceFactory = ( configurationUtilities: ActionsConfigurationUtilities, { table, importSetTable, useImportAPI, appScope }: SNProductsConfigValue ): ExternalService => { - const { apiUrl: url, isLegacy } = config as ServiceNowPublicConfigurationType; + const { apiUrl: url, usesTableApi: usesTableApiConfigValue } = + config as ServiceNowPublicConfigurationType; const { username, password } = secrets as ServiceNowSecretConfigurationType; if (!url || !username || !password) { @@ -57,11 +58,11 @@ export const createExternalService: ServiceFactory = ( auth: { username, password }, }); - const useOldApi = !useImportAPI || isLegacy; + const useTableApi = !useImportAPI || usesTableApiConfigValue; - const getCreateIncidentUrl = () => (useOldApi ? tableApiIncidentUrl : importSetTableUrl); + const getCreateIncidentUrl = () => (useTableApi ? tableApiIncidentUrl : importSetTableUrl); const getUpdateIncidentUrl = (incidentId: string) => - useOldApi ? `${tableApiIncidentUrl}/${incidentId}` : importSetTableUrl; + useTableApi ? `${tableApiIncidentUrl}/${incidentId}` : importSetTableUrl; const getIncidentViewURL = (id: string) => { // Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html @@ -105,7 +106,7 @@ export const createExternalService: ServiceFactory = ( /** * Gets the Elastic SN Application information including the current version. - * It should not be used on legacy connectors. + * It should not be used on connectors that use the old API. */ const getApplicationInformation = async (): Promise => { try { @@ -129,7 +130,7 @@ export const createExternalService: ServiceFactory = ( logger.debug(`Create incident: Application scope: ${scope}: Application version${version}`); const checkIfApplicationIsInstalled = async () => { - if (!useOldApi) { + if (!useTableApi) { const { version, scope } = await getApplicationInformation(); logApplicationInfo(scope, version); } @@ -180,17 +181,17 @@ export const createExternalService: ServiceFactory = ( url: getCreateIncidentUrl(), logger, method: 'post', - data: prepareIncident(useOldApi, incident), + data: prepareIncident(useTableApi, incident), configurationUtilities, }); checkInstance(res); - if (!useOldApi) { + if (!useTableApi) { throwIfImportSetApiResponseIsAnError(res.data); } - const incidentId = useOldApi ? res.data.result.sys_id : res.data.result[0].sys_id; + const incidentId = useTableApi ? res.data.result.sys_id : res.data.result[0].sys_id; const insertedIncident = await getIncident(incidentId); return { @@ -212,23 +213,23 @@ export const createExternalService: ServiceFactory = ( axios: axiosInstance, url: getUpdateIncidentUrl(incidentId), // Import Set API supports only POST. - method: useOldApi ? 'patch' : 'post', + method: useTableApi ? 'patch' : 'post', logger, data: { - ...prepareIncident(useOldApi, incident), + ...prepareIncident(useTableApi, incident), // elastic_incident_id is used to update the incident when using the Import Set API. - ...(useOldApi ? {} : { elastic_incident_id: incidentId }), + ...(useTableApi ? {} : { elastic_incident_id: incidentId }), }, configurationUtilities, }); checkInstance(res); - if (!useOldApi) { + if (!useTableApi) { throwIfImportSetApiResponseIsAnError(res.data); } - const id = useOldApi ? res.data.result.sys_id : res.data.result[0].sys_id; + const id = useTableApi ? res.data.result.sys_id : res.data.result[0].sys_id; const updatedIncident = await getIncident(id); return { diff --git a/x-pack/plugins/actions/server/cleanup_failed_executions/cleanup_tasks.test.ts b/x-pack/plugins/actions/server/cleanup_failed_executions/cleanup_tasks.test.ts index 451e12b9cf29a..b80a8d092118a 100644 --- a/x-pack/plugins/actions/server/cleanup_failed_executions/cleanup_tasks.test.ts +++ b/x-pack/plugins/actions/server/cleanup_failed_executions/cleanup_tasks.test.ts @@ -10,7 +10,8 @@ import { loggingSystemMock, elasticsearchServiceMock } from '../../../../../src/ import { spacesMock } from '../../../spaces/server/mocks'; import { CleanupTasksOpts, cleanupTasks } from './cleanup_tasks'; import { TaskInstance } from '../../../task_manager/server'; -import { ApiResponse, estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { TransportResult } from '@elastic/elasticsearch'; describe('cleanupTasks', () => { const logger = loggingSystemMock.create().get(); @@ -71,7 +72,7 @@ describe('cleanupTasks', () => { it('should delete action_task_params and task objects', async () => { esClient.bulk.mockResolvedValue({ body: { items: [], errors: false, took: 1 }, - } as unknown as ApiResponse); + } as unknown as TransportResult); const result = await cleanupTasks({ ...cleanupTasksOpts, tasks: [taskSO], @@ -106,7 +107,7 @@ describe('cleanupTasks', () => { errors: true, took: 1, }, - } as unknown as ApiResponse); + } as unknown as TransportResult); const result = await cleanupTasks({ ...cleanupTasksOpts, tasks: [taskSO], diff --git a/x-pack/plugins/actions/server/cleanup_failed_executions/lib/bulk_delete.ts b/x-pack/plugins/actions/server/cleanup_failed_executions/lib/bulk_delete.ts index 2e0037d01943d..5bbb48a3d520d 100644 --- a/x-pack/plugins/actions/server/cleanup_failed_executions/lib/bulk_delete.ts +++ b/x-pack/plugins/actions/server/cleanup_failed_executions/lib/bulk_delete.ts @@ -6,13 +6,14 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { ApiResponse, estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TransportResult } from '@elastic/elasticsearch'; export async function bulkDelete( esClient: ElasticsearchClient, index: string, ids: string[] -): Promise | undefined> { +): Promise | undefined> { if (ids.length === 0) { return; } diff --git a/x-pack/plugins/actions/server/cleanup_failed_executions/lib/extract_bulk_response_delete_failures.ts b/x-pack/plugins/actions/server/cleanup_failed_executions/lib/extract_bulk_response_delete_failures.ts index 90418c9763a4d..c3b4866f199d3 100644 --- a/x-pack/plugins/actions/server/cleanup_failed_executions/lib/extract_bulk_response_delete_failures.ts +++ b/x-pack/plugins/actions/server/cleanup_failed_executions/lib/extract_bulk_response_delete_failures.ts @@ -5,12 +5,13 @@ * 2.0. */ -import { ApiResponse, estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TransportResult } from '@elastic/elasticsearch'; -type ResponseFailures = Array>; +type ResponseFailures = Array>; export function extractBulkResponseDeleteFailures( - response: ApiResponse + response: TransportResult ): ResponseFailures { const result: ResponseFailures = []; for (const item of response.body.items) { diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index ba7f750859d40..4175649454f71 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -273,6 +273,45 @@ test('throws an error when config is invalid', async () => { }); }); +test('throws an error when connector is invalid', async () => { + const actionType: jest.Mocked = { + id: 'test', + name: 'Test', + minimumLicenseRequired: 'basic', + validate: { + connector: () => { + return 'error'; + }, + }, + executor: jest.fn(), + }; + const actionSavedObject = { + id: '1', + type: 'action', + attributes: { + actionTypeId: 'test', + }, + references: [], + }; + const actionResult = { + id: actionSavedObject.id, + name: actionSavedObject.id, + actionTypeId: actionSavedObject.attributes.actionTypeId, + isPreconfigured: false, + }; + actionsClient.get.mockResolvedValueOnce(actionResult); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject); + actionTypeRegistry.get.mockReturnValueOnce(actionType); + + const result = await actionExecutor.execute(executeParams); + expect(result).toEqual({ + actionId: '1', + status: 'error', + retry: false, + message: `error validating action type connector: error`, + }); +}); + test('throws an error when params is invalid', async () => { const actionType: jest.Mocked = { id: 'test', diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index d265bca237c3b..518d4582de2bc 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -9,7 +9,12 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, KibanaRequest } from 'src/core/server'; import { cloneDeep } from 'lodash'; import { withSpan } from '@kbn/apm-utils'; -import { validateParams, validateConfig, validateSecrets } from './validate_with_schema'; +import { + validateParams, + validateConfig, + validateSecrets, + validateConnector, +} from './validate_with_schema'; import { ActionTypeExecutorResult, ActionTypeRegistryContract, @@ -142,11 +147,16 @@ export class ActionExecutor { let validatedParams: Record; let validatedConfig: Record; let validatedSecrets: Record; - try { validatedParams = validateParams(actionType, params); validatedConfig = validateConfig(actionType, config); validatedSecrets = validateSecrets(actionType, secrets); + if (actionType.validate?.connector) { + validateConnector(actionType, { + config, + secrets, + }); + } } catch (err) { span?.setOutcome('failure'); return { status: 'error', actionId, message: err.message, retry: false }; diff --git a/x-pack/plugins/actions/server/lib/index.ts b/x-pack/plugins/actions/server/lib/index.ts index c47325c19fad9..c52a8b14ee6d8 100644 --- a/x-pack/plugins/actions/server/lib/index.ts +++ b/x-pack/plugins/actions/server/lib/index.ts @@ -6,7 +6,12 @@ */ export { ExecutorError } from './executor_error'; -export { validateParams, validateConfig, validateSecrets } from './validate_with_schema'; +export { + validateParams, + validateConfig, + validateSecrets, + validateConnector, +} from './validate_with_schema'; export { TaskRunnerFactory } from './task_runner_factory'; export { ActionExecutor, ActionExecutorContract } from './action_executor'; export { ILicenseState, LicenseState } from './license_state'; diff --git a/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts b/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts index 480a3e31fcb59..4f0a11252eb48 100644 --- a/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts +++ b/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts @@ -7,7 +7,12 @@ import { schema } from '@kbn/config-schema'; -import { validateParams, validateConfig, validateSecrets } from './validate_with_schema'; +import { + validateParams, + validateConfig, + validateSecrets, + validateConnector, +} from './validate_with_schema'; import { ActionType, ExecutorType } from '../types'; const executor: ExecutorType<{}, {}, {}, void> = async (options) => { @@ -47,6 +52,9 @@ test('should validate when there are no individual validators', () => { result = validateSecrets(actionType, testValue); expect(result).toEqual(testValue); + + result = validateConnector(actionType, { config: testValue }); + expect(result).toBeNull(); }); test('should validate when validators return incoming value', () => { @@ -74,6 +82,9 @@ test('should validate when validators return incoming value', () => { result = validateSecrets(actionType, testValue); expect(result).toEqual(testValue); + + result = validateConnector(actionType, { config: testValue }); + expect(result).toBeNull(); }); test('should validate when validators return different values', () => { @@ -102,6 +113,9 @@ test('should validate when validators return different values', () => { result = validateSecrets(actionType, testValue); expect(result).toEqual(returnedValue); + + result = validateConnector(actionType, { config: testValue, secrets: { user: 'test' } }); + expect(result).toBeNull(); }); test('should throw with expected error when validators fail', () => { @@ -119,6 +133,9 @@ test('should throw with expected error when validators fail', () => { params: erroringValidator, config: erroringValidator, secrets: erroringValidator, + connector: () => { + return 'test error'; + }, }, }; @@ -135,6 +152,10 @@ test('should throw with expected error when validators fail', () => { expect(() => validateSecrets(actionType, testValue)).toThrowErrorMatchingInlineSnapshot( `"error validating action type secrets: test error"` ); + + expect(() => + validateConnector(actionType, { config: testValue, secrets: { user: 'test' } }) + ).toThrowErrorMatchingInlineSnapshot(`"error validating action type connector: test error"`); }); test('should work with @kbn/config-schema', () => { @@ -148,6 +169,7 @@ test('should work with @kbn/config-schema', () => { params: testSchema, config: testSchema, secrets: testSchema, + connector: () => null, }, }; diff --git a/x-pack/plugins/actions/server/lib/validate_with_schema.ts b/x-pack/plugins/actions/server/lib/validate_with_schema.ts index 335fe4eee3da1..8ff0a3666c4b7 100644 --- a/x-pack/plugins/actions/server/lib/validate_with_schema.ts +++ b/x-pack/plugins/actions/server/lib/validate_with_schema.ts @@ -35,6 +35,22 @@ export function validateSecrets< return validateWithSchema(actionType, 'secrets', value); } +export function validateConnector< + Config extends ActionTypeConfig = ActionTypeConfig, + Secrets extends ActionTypeSecrets = ActionTypeSecrets, + Params extends ActionTypeParams = ActionTypeParams, + ExecutorResultData = void +>(actionType: ActionType, value: unknown) { + if (actionType.validate && actionType.validate.connector) { + const connectorValue = value as { config: Config; secrets: Secrets }; + const result = actionType.validate.connector(connectorValue.config, connectorValue.secrets); + if (result !== null) { + throw Boom.badRequest(`error validating action type connector: ${result}`); + } + } + return null; +} + type ValidKeys = 'params' | 'config' | 'secrets'; function validateWithSchema< @@ -45,7 +61,7 @@ function validateWithSchema< >( actionType: ActionType, key: ValidKeys, - value: unknown + value: unknown | { config: unknown; secrets: unknown } ): Record { if (actionType.validate) { let name; diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index d0404a253c0d9..2942c7492906a 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -96,19 +96,25 @@ export interface PluginSetupContract { >( actionType: ActionType ): void; + isPreconfiguredConnector(connectorId: string): boolean; } export interface PluginStartContract { isActionTypeEnabled(id: string, options?: { notifyUsage: boolean }): boolean; + isActionExecutable( actionId: string, actionTypeId: string, options?: { notifyUsage: boolean } ): boolean; + getActionsClientWithRequest(request: KibanaRequest): Promise>; + getActionsAuthorizationWithRequest(request: KibanaRequest): PublicMethodsOf; + preconfiguredActions: PreConfiguredAction[]; + renderActionParameterTemplates( actionTypeId: string, actionId: string, @@ -127,6 +133,7 @@ export interface ActionsPluginsSetup { features: FeaturesPluginSetup; spaces?: SpacesPluginSetup; } + export interface ActionsPluginsStart { encryptedSavedObjects: EncryptedSavedObjectsPluginStart; taskManager: TaskManagerStartContract; @@ -154,7 +161,7 @@ export class ActionsPlugin implements Plugin, plugins: ActionsPluginsSetup ): PluginSetupContract { + this.kibanaIndex = core.savedObjects.getKibanaIndex(); + this.licenseState = new LicenseState(plugins.licensing.license$); this.isESOCanEncrypt = plugins.encryptedSavedObjects.canEncrypt; @@ -253,14 +261,14 @@ export class ActionsPlugin implements Plugin( 'actions', - this.createRouteHandlerContext(core, this.kibanaIndexConfig.kibana.index) + this.createRouteHandlerContext(core, this.kibanaIndex) ); if (usageCollection) { initializeActionsTelemetry( this.telemetryLogger, plugins.taskManager, core, - this.kibanaIndexConfig.kibana.index, + this.kibanaIndex, this.preconfiguredActions ); } @@ -282,7 +290,7 @@ export class ActionsPlugin implements Plugin { expect(migratedAction).toEqual(action); }); - test('set isLegacy config property for .servicenow', () => { + test('set usesTableApi config property for .servicenow', () => { const migration716 = getActionsMigrations(encryptedSavedObjectsSetup)['7.16.0']; const action = getMockDataForServiceNow(); const migratedAction = migration716(action, context); @@ -177,13 +177,13 @@ describe('successful migrations', () => { ...action.attributes, config: { apiUrl: 'https://example.com', - isLegacy: true, + usesTableApi: true, }, }, }); }); - test('set isLegacy config property for .servicenow-sir', () => { + test('set usesTableApi config property for .servicenow-sir', () => { const migration716 = getActionsMigrations(encryptedSavedObjectsSetup)['7.16.0']; const action = getMockDataForServiceNow({ actionTypeId: '.servicenow-sir' }); const migratedAction = migration716(action, context); @@ -194,13 +194,13 @@ describe('successful migrations', () => { ...action.attributes, config: { apiUrl: 'https://example.com', - isLegacy: true, + usesTableApi: true, }, }, }); }); - test('it does not set isLegacy config for other connectors', () => { + test('it does not set usesTableApi config for other connectors', () => { const migration716 = getActionsMigrations(encryptedSavedObjectsSetup)['7.16.0']; const action = getMockData(); const migratedAction = migration716(action, context); diff --git a/x-pack/plugins/actions/server/saved_objects/actions_migrations.ts b/x-pack/plugins/actions/server/saved_objects/actions_migrations.ts index 688839eb89858..2e5b1b5d916fe 100644 --- a/x-pack/plugins/actions/server/saved_objects/actions_migrations.ts +++ b/x-pack/plugins/actions/server/saved_objects/actions_migrations.ts @@ -68,7 +68,7 @@ export function getActionsMigrations( doc.attributes.actionTypeId === '.servicenow' || doc.attributes.actionTypeId === '.servicenow-sir' || doc.attributes.actionTypeId === '.email', - pipeMigrations(markOldServiceNowITSMConnectorAsLegacy, setServiceConfigIfNotSet) + pipeMigrations(addUsesTableApiToServiceNowConnectors, setServiceConfigIfNotSet) ); const migrationActions800 = createEsoMigration( @@ -197,7 +197,7 @@ const addIsMissingSecretsField = ( }; }; -const markOldServiceNowITSMConnectorAsLegacy = ( +const addUsesTableApiToServiceNowConnectors = ( doc: SavedObjectUnsanitizedDoc ): SavedObjectUnsanitizedDoc => { if ( @@ -213,7 +213,7 @@ const markOldServiceNowITSMConnectorAsLegacy = ( ...doc.attributes, config: { ...doc.attributes.config, - isLegacy: true, + usesTableApi: true, }, }, }; diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 64250ca77fba4..627cd7028e5b1 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -111,6 +111,7 @@ export interface ActionType< params?: ValidatorType; config?: ValidatorType; secrets?: ValidatorType; + connector?: (config: Config, secrets: Secrets) => string | null; }; renderParameterTemplates?( params: Params, diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.ts index 803a2122fe7f8..ab72352d460e3 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { ElasticsearchClient } from 'kibana/server'; import { AlertHistoryEsIndexConnectorId } from '../../common'; import { ActionResult, PreConfiguredAction } from '../types'; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts index 300634af84585..d718373446b60 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts @@ -8,7 +8,7 @@ import { remove } from 'lodash'; import { EsQueryConfig, nodeBuilder, toElasticsearchQuery, KueryNode } from '@kbn/es-query'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RegistryAlertTypeWithAuth } from './alerting_authorization'; export enum AlertingAuthorizationFilterType { diff --git a/x-pack/plugins/alerting/server/lib/errors/es_error_parser.ts b/x-pack/plugins/alerting/server/lib/errors/es_error_parser.ts index 3573da3a52eea..f26fa22f8d730 100644 --- a/x-pack/plugins/alerting/server/lib/errors/es_error_parser.ts +++ b/x-pack/plugins/alerting/server/lib/errors/es_error_parser.ts @@ -5,7 +5,6 @@ * 2.0. */ -// import { ResponseError } from '@elastic/elasticsearch/lib/errors'; import { ElasticsearchError, ElasticsearchErrorCausedByObject } from './types'; const getEsCause = ( diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 3623495058eb0..c8f52110f5bcc 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -7,7 +7,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { first, map, share } from 'rxjs/operators'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { combineLatest } from 'rxjs'; import { SecurityPluginSetup, SecurityPluginStart } from '../../security/server'; @@ -108,10 +108,13 @@ export interface PluginSetupContract { export interface PluginStartContract { listTypes: RuleTypeRegistry['list']; + getRulesClientWithRequest(request: KibanaRequest): PublicMethodsOf; + getAlertingAuthorizationWithRequest( request: KibanaRequest ): PublicMethodsOf; + getFrameworkHealth: () => Promise; } @@ -125,6 +128,7 @@ export interface AlertingPluginsSetup { eventLog: IEventLogService; statusService: StatusServiceSetup; } + export interface AlertingPluginsStart { actions: ActionsPluginStartContract; taskManager: TaskManagerStartContract; @@ -150,7 +154,6 @@ export class AlertingPlugin { private readonly kibanaVersion: PluginInitializerContext['env']['packageInfo']['version']; private eventLogService?: IEventLogService; private eventLogger?: IEventLogger; - private readonly kibanaIndexConfig: Observable<{ kibana: { index: string } }>; private kibanaBaseUrl: string | undefined; constructor(initializerContext: PluginInitializerContext) { @@ -160,7 +163,6 @@ export class AlertingPlugin { this.rulesClientFactory = new RulesClientFactory(); this.alertingAuthorizationClientFactory = new AlertingAuthorizationClientFactory(); this.telemetryLogger = initializerContext.logger.get('usage'); - this.kibanaIndexConfig = initializerContext.config.legacy.globalConfig$; this.kibanaVersion = initializerContext.env.packageInfo.version; } @@ -168,6 +170,7 @@ export class AlertingPlugin { core: CoreSetup, plugins: AlertingPluginsSetup ): PluginSetupContract { + const kibanaIndex = core.savedObjects.getKibanaIndex(); this.kibanaBaseUrl = core.http.basePath.publicBaseUrl; this.licenseState = new LicenseState(plugins.licensing.license$); this.security = plugins.security; @@ -211,14 +214,7 @@ export class AlertingPlugin { usageCollection, core.getStartServices().then(([_, { taskManager }]) => taskManager) ); - this.kibanaIndexConfig.subscribe((config) => { - initializeAlertingTelemetry( - this.telemetryLogger, - core, - plugins.taskManager, - config.kibana.index - ); - }); + initializeAlertingTelemetry(this.telemetryLogger, core, plugins.taskManager, kibanaIndex); } // Usage counter for telemetry diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index bde0c35028582..e6f20049bc470 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -9,7 +9,7 @@ import Semver from 'semver'; import Boom from '@hapi/boom'; import { omit, isEqual, map, uniq, pick, truncate, trim, mapValues } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Logger, SavedObjectsClientContract, diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.ts index 0a1d7bfc8a9d7..67ecca57216e5 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isRuleType, ruleTypeMappings } from '@kbn/securitysolution-rules'; import { isString } from 'lodash/fp'; import { LogMeta, @@ -52,7 +53,8 @@ export const isAnyActionSupportIncidents = (doc: SavedObjectUnsanitizedDoc): boolean => +// Deprecated in 8.0 +export const isSiemSignalsRuleType = (doc: SavedObjectUnsanitizedDoc): boolean => doc.attributes.alertTypeId === 'siem.signals'; /** @@ -96,19 +98,19 @@ export function getMigrations( const migrationSecurityRules713 = createEsoMigration( encryptedSavedObjects, - (doc): doc is SavedObjectUnsanitizedDoc => isSecuritySolutionRule(doc), + (doc): doc is SavedObjectUnsanitizedDoc => isSiemSignalsRuleType(doc), pipeMigrations(removeNullsFromSecurityRules) ); const migrationSecurityRules714 = createEsoMigration( encryptedSavedObjects, - (doc): doc is SavedObjectUnsanitizedDoc => isSecuritySolutionRule(doc), + (doc): doc is SavedObjectUnsanitizedDoc => isSiemSignalsRuleType(doc), pipeMigrations(removeNullAuthorFromSecurityRules) ); const migrationSecurityRules715 = createEsoMigration( encryptedSavedObjects, - (doc): doc is SavedObjectUnsanitizedDoc => isSecuritySolutionRule(doc), + (doc): doc is SavedObjectUnsanitizedDoc => isSiemSignalsRuleType(doc), pipeMigrations(addExceptionListsToReferences) ); @@ -126,7 +128,7 @@ export function getMigrations( const migrationRules800 = createEsoMigration( encryptedSavedObjects, (doc: SavedObjectUnsanitizedDoc): doc is SavedObjectUnsanitizedDoc => true, - (doc) => doc // no-op + pipeMigrations(addRACRuleTypes) ); return { @@ -647,6 +649,25 @@ function setLegacyId( }; } +function addRACRuleTypes( + doc: SavedObjectUnsanitizedDoc +): SavedObjectUnsanitizedDoc { + const ruleType = doc.attributes.params.type; + return isSiemSignalsRuleType(doc) && isRuleType(ruleType) + ? { + ...doc, + attributes: { + ...doc.attributes, + alertTypeId: ruleTypeMappings[ruleType], + params: { + ...doc.attributes.params, + outputIndex: '', + }, + }, + } + : doc; +} + function getRemovePreconfiguredConnectorsFromReferencesFn( isPreconfigured: (connectorId: string) => boolean ) { diff --git a/x-pack/plugins/apm/common/search_strategies/field_stats_types.ts b/x-pack/plugins/apm/common/search_strategies/field_stats_types.ts index d96bb4408f0e8..d63dd7f8d58a1 100644 --- a/x-pack/plugins/apm/common/search_strategies/field_stats_types.ts +++ b/x-pack/plugins/apm/common/search_strategies/field_stats_types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SearchStrategyParams } from './types'; export interface FieldStatsCommonRequestParams extends SearchStrategyParams { diff --git a/x-pack/plugins/apm/common/utils/environment_query.ts b/x-pack/plugins/apm/common/utils/environment_query.ts index 7b35f90d87691..e2f9a722e3de2 100644 --- a/x-pack/plugins/apm/common/utils/environment_query.ts +++ b/x-pack/plugins/apm/common/utils/environment_query.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SERVICE_ENVIRONMENT } from '../elasticsearch_fieldnames'; import { ENVIRONMENT_ALL, diff --git a/x-pack/plugins/apm/dev_docs/linting.md b/x-pack/plugins/apm/dev_docs/linting.md index edf3e813a88e9..3dbd7b5b27484 100644 --- a/x-pack/plugins/apm/dev_docs/linting.md +++ b/x-pack/plugins/apm/dev_docs/linting.md @@ -19,3 +19,12 @@ yarn prettier "./x-pack/plugins/apm/**/*.{tsx,ts,js}" --write ``` node scripts/eslint.js x-pack/plugins/apm ``` + +## Install pre-commit hook (optional) +In case you want to run a couple of checks like linting or check the file casing of the files to commit, we provide a way to install a pre-commit hook. To configure it you just need to run the following: + +`node scripts/register_git_hook` + +After the script completes the pre-commit hook will be created within the file .git/hooks/pre-commit. If you choose to not install it, don’t worry, we still run a quick CI check to provide feedback earliest as we can about the same checks. + +More information about linting can be found in the [Kibana Guide](https://www.elastic.co/guide/en/kibana/current/kibana-linting.html). \ No newline at end of file diff --git a/x-pack/plugins/apm/dev_docs/routing_and_linking.md b/x-pack/plugins/apm/dev_docs/routing_and_linking.md index af22bcdbdfa11..a1fdff3821c4c 100644 --- a/x-pack/plugins/apm/dev_docs/routing_and_linking.md +++ b/x-pack/plugins/apm/dev_docs/routing_and_linking.md @@ -69,7 +69,7 @@ const serviceOverviewLink = apmRouter.link('/services/:serviceName', { path: { s If you're not in React context, you can also import `apmRouter` directly and call its `link` function - but you have to prepend the basePath manually in that case. -We also have the [`getAPMHref` function and `APMLink` component](../public/components/shared/Links/apm/APMLink.tsx), but we should consider them deprecated, in favor of `router.link`. Other components inside that directory contain other functions and components that provide the same functionality for linking to more specific sections inside the APM plugin. +We also have the [`getLegacyApmHref` function and `APMLink` component](../public/components/shared/Links/apm/APMLink.tsx), but we should consider them deprecated, in favor of `router.link`. Other components inside that directory contain other functions and components that provide the same functionality for linking to more specific sections inside the APM plugin. ### Cross-app linking diff --git a/x-pack/plugins/apm/ftr_e2e/cypress_start.ts b/x-pack/plugins/apm/ftr_e2e/cypress_start.ts index caf87d2627459..0cfc58653801a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress_start.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress_start.ts @@ -16,15 +16,10 @@ import { esArchiverLoad, esArchiverUnload } from './cypress/tasks/es_archiver'; export function cypressRunTests(spec?: string) { return async ({ getService }: FtrProviderContext) => { - try { - const result = await cypressStart(getService, cypress.run, spec); + const result = await cypressStart(getService, cypress.run, spec); - if (result && (result.status === 'failed' || result.totalFailed > 0)) { - process.exit(1); - } - } catch (error) { - console.error('errors: ', error); - process.exit(1); + if (result && (result.status === 'failed' || result.totalFailed > 0)) { + throw new Error(`APM Cypress tests failed`); } }; } diff --git a/x-pack/plugins/apm/jest.config.js b/x-pack/plugins/apm/jest.config.js index 4fd2e72776943..66b4b164a794c 100644 --- a/x-pack/plugins/apm/jest.config.js +++ b/x-pack/plugins/apm/jest.config.js @@ -11,7 +11,10 @@ module.exports = { preset: '@kbn/test', rootDir: path.resolve(__dirname, '../../..'), roots: ['/x-pack/plugins/apm'], - setupFiles: ['/x-pack/plugins/apm/.storybook/jest_setup.js'], + setupFiles: [ + '/x-pack/plugins/apm/jest_setup.js', + '/x-pack/plugins/apm/.storybook/jest_setup.js', + ], coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/apm', coverageReporters: ['text', 'html'], collectCoverageFrom: [ diff --git a/x-pack/plugins/apm/jest_setup.js b/x-pack/plugins/apm/jest_setup.js new file mode 100644 index 0000000000000..df8ba56cdc1c3 --- /dev/null +++ b/x-pack/plugins/apm/jest_setup.js @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* global jest */ + +// When a `console.error` is encountered, throw the error to make the test fail. +// This effectively treats logged errors during the test run as failures. +jest.spyOn(console, 'error').mockImplementation((message) => { + throw new Error(message); +}); diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json index 865358959ea72..e57859bfa253e 100644 --- a/x-pack/plugins/apm/kibana.json +++ b/x-pack/plugins/apm/kibana.json @@ -12,6 +12,7 @@ "embeddable", "features", "infra", + "inspector", "licensing", "observability", "ruleRegistry", diff --git a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx b/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx index fb1a99db0bf5b..2015bf2228b6c 100644 --- a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx @@ -23,17 +23,21 @@ import { EuiSpacer } from '@elastic/eui'; import React from 'react'; import { Coordinate } from '../../../../typings/timeseries'; import { useTheme } from '../../../hooks/use_theme'; +import { IUiSettingsClient } from '../../../../../../../src/core/public'; +import { getTimeZone } from '../../shared/charts/helper/timezone'; interface ChartPreviewProps { yTickFormat?: TickFormatter; data?: Coordinate[]; threshold: number; + uiSettings?: IUiSettingsClient; } export function ChartPreview({ data = [], yTickFormat, threshold, + uiSettings, }: ChartPreviewProps) { const theme = useTheme(); const thresholdOpacity = 0.3; @@ -67,6 +71,8 @@ export function ChartPreview({ }, ]; + const timeZone = getTimeZone(uiSettings); + return ( <> @@ -99,6 +105,7 @@ export function ChartPreview({ domain={{ max: yMax, min: NaN }} /> ({}) }, notifications: { toasts: { add: () => {} } }, -} as unknown as Partial); + uiSettings: { get: () => {} }, +} as unknown as CoreStart; + +const KibanaReactContext = createKibanaReactContext(coreMock); interface Args { alertParams: AlertParams; @@ -27,6 +33,8 @@ const stories: Meta<{}> = { component: ErrorCountAlertTrigger, decorators: [ (StoryComponent) => { + createCallApmApi(coreMock); + return (
diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.test.tsx b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.test.tsx index 26c62b10e6220..edf3b5b675cc4 100644 --- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.test.tsx +++ b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import * as stories from './error_count_alert_trigger.stories'; import { composeStories } from '@storybook/testing-react'; @@ -13,7 +13,9 @@ import { composeStories } from '@storybook/testing-react'; const { CreatingInApmFromService } = composeStories(stories); describe('ErrorCountAlertTrigger', () => { - it('renders', () => { - expect(() => render()).not.toThrowError(); + it('renders', async () => { + render(); + + expect(await screen.findByText('Service')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx index eac128a7e88c4..1c72d5f104854 100644 --- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx @@ -120,6 +120,7 @@ export function ErrorCountAlertTrigger(props: Props) { data={data?.errorCountChartPreview} threshold={params.threshold} yTickFormat={asInteger} + uiSettings={services.uiSettings} /> ); diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx index 8957dfc823e44..fa75fcca579e5 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx @@ -139,6 +139,7 @@ export function TransactionDurationAlertTrigger(props: Props) { data={latencyChartPreview} threshold={thresholdMs} yTickFormat={yTickFormat} + uiSettings={services.uiSettings} /> ); diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx index ddddc4bbecbad..a818218cbf3ad 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx @@ -131,6 +131,7 @@ export function TransactionErrorRateAlertTrigger(props: Props) { data={data?.errorRateChartPreview} yTickFormat={(d: number | null) => asPercent(d, 1)} threshold={thresholdAsPercent} + uiSettings={services.uiSettings} /> ); diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx index 57efea4ffdcac..72273bf8c9e19 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx @@ -13,7 +13,6 @@ import { useUrlParams } from '../../../context/url_params_context/use_url_params import { useFetcher } from '../../../hooks/use_fetcher'; import { getTimeRangeComparison } from '../../shared/time_comparison/get_time_range_comparison'; import { DependenciesTable } from '../../shared/dependencies_table'; -import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context'; import { ServiceLink } from '../../shared/service_link'; import { useTimeRange } from '../../../hooks/use_time_range'; @@ -23,8 +22,8 @@ export function BackendDetailDependenciesTable() { } = useUrlParams(); const { - query: { rangeFrom, rangeTo, kuery, environment }, - } = useApmParams('/backends/{backendName}/overview'); + query: { backendName, rangeFrom, rangeTo, kuery, environment }, + } = useApmParams('/backends/overview'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); @@ -35,8 +34,6 @@ export function BackendDetailDependenciesTable() { comparisonType, }); - const { backendName } = useApmBackendContext(); - const { data, status } = useFetcher( (callApmApi) => { if (!start || !end) { @@ -44,12 +41,17 @@ export function BackendDetailDependenciesTable() { } return callApmApi({ - endpoint: 'GET /internal/apm/backends/{backendName}/upstream_services', + endpoint: 'GET /internal/apm/backends/upstream_services', params: { - path: { + query: { backendName, + start, + end, + environment, + numBuckets: 20, + offset, + kuery, }, - query: { start, end, environment, numBuckets: 20, offset, kuery }, }, }); }, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx index cf14145dba82a..3b19e8b6dd920 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx @@ -7,7 +7,6 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { asPercent } from '../../../../common/utils/formatters'; -import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context'; import { useComparison } from '../../../hooks/use_comparison'; import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; @@ -25,13 +24,11 @@ export function BackendFailedTransactionRateChart({ }: { height: number; }) { - const { backendName } = useApmBackendContext(); - const theme = useTheme(); const { - query: { kuery, environment, rangeFrom, rangeTo }, - } = useApmParams('/backends/{backendName}/overview'); + query: { backendName, kuery, environment, rangeFrom, rangeTo }, + } = useApmParams('/backends/overview'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); @@ -44,12 +41,10 @@ export function BackendFailedTransactionRateChart({ } return callApmApi({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/error_rate', + endpoint: 'GET /internal/apm/backends/charts/error_rate', params: { - path: { - backendName, - }, query: { + backendName, start, end, offset, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx index 3f5a56d55d823..2e750141257a5 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx @@ -7,7 +7,6 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { getDurationFormatter } from '../../../../common/utils/formatters'; -import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context'; import { useComparison } from '../../../hooks/use_comparison'; import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; @@ -21,13 +20,11 @@ import { import { useApmParams } from '../../../hooks/use_apm_params'; export function BackendLatencyChart({ height }: { height: number }) { - const { backendName } = useApmBackendContext(); - const theme = useTheme(); const { - query: { rangeFrom, rangeTo, kuery, environment }, - } = useApmParams('/backends/{backendName}/overview'); + query: { backendName, rangeFrom, rangeTo, kuery, environment }, + } = useApmParams('/backends/overview'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); @@ -40,12 +37,10 @@ export function BackendLatencyChart({ height }: { height: number }) { } return callApmApi({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/latency', + endpoint: 'GET /internal/apm/backends/charts/latency', params: { - path: { - backendName, - }, query: { + backendName, start, end, offset, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx index f5d9cb7a7a55e..6f201f468a9e3 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx @@ -7,7 +7,6 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { asTransactionRate } from '../../../../common/utils/formatters'; -import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context'; import { useComparison } from '../../../hooks/use_comparison'; import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; @@ -17,13 +16,11 @@ import { useTheme } from '../../../hooks/use_theme'; import { useApmParams } from '../../../hooks/use_apm_params'; export function BackendThroughputChart({ height }: { height: number }) { - const { backendName } = useApmBackendContext(); - const theme = useTheme(); const { - query: { rangeFrom, rangeTo, kuery, environment }, - } = useApmParams('/backends/{backendName}/overview'); + query: { backendName, rangeFrom, rangeTo, kuery, environment }, + } = useApmParams('/backends/overview'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); @@ -36,12 +33,10 @@ export function BackendThroughputChart({ height }: { height: number }) { } return callApmApi({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/throughput', + endpoint: 'GET /internal/apm/backends/charts/throughput', params: { - path: { - backendName, - }, query: { + backendName, start, end, offset, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/index.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/index.tsx index 3b4deac794df0..6823b571e9597 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/index.tsx @@ -11,7 +11,6 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ApmBackendContextProvider } from '../../../context/apm_backend/apm_backend_context'; import { useBreadcrumb } from '../../../context/breadcrumbs/use_breadcrumb'; import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context'; import { useApmParams } from '../../../hooks/use_apm_params'; @@ -31,8 +30,8 @@ import { useBreakpoints } from '../../../hooks/use_breakpoints'; export function BackendDetailOverview() { const { - path: { backendName }, query: { + backendName, rangeFrom, rangeTo, refreshInterval, @@ -40,7 +39,7 @@ export function BackendDetailOverview() { environment, kuery, }, - } = useApmParams('/backends/{backendName}/overview'); + } = useApmParams('/backends/overview'); const apmRouter = useApmRouter(); @@ -60,9 +59,9 @@ export function BackendDetailOverview() { }, { title: backendName, - href: apmRouter.link('/backends/{backendName}/overview', { - path: { backendName }, + href: apmRouter.link('/backends/overview', { query: { + backendName, rangeFrom, rangeTo, refreshInterval, @@ -82,62 +81,59 @@ export function BackendDetailOverview() { const largeScreenOrSmaller = useBreakpoints().isLarge; return ( - - - - - - - - -

- {i18n.translate( - 'xpack.apm.backendDetailLatencyChartTitle', - { defaultMessage: 'Latency' } - )} -

-
- -
-
- - - -

- {i18n.translate( - 'xpack.apm.backendDetailThroughputChartTitle', - { defaultMessage: 'Throughput' } - )} -

-
- -
-
- - - -

- {i18n.translate( - 'xpack.apm.backendDetailFailedTransactionRateChartTitle', - { defaultMessage: 'Failed transaction rate' } - )} -

-
- -
-
-
-
- - -
-
+ + + + + + + +

+ {i18n.translate('xpack.apm.backendDetailLatencyChartTitle', { + defaultMessage: 'Latency', + })} +

+
+ +
+
+ + + +

+ {i18n.translate( + 'xpack.apm.backendDetailThroughputChartTitle', + { defaultMessage: 'Throughput' } + )} +

+
+ +
+
+ + + +

+ {i18n.translate( + 'xpack.apm.backendDetailFailedTransactionRateChartTitle', + { defaultMessage: 'Failed transaction rate' } + )} +

+
+ +
+
+
+
+ + +
); } diff --git a/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx index c214c4348bbe7..b84e8830aae5f 100644 --- a/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx @@ -64,10 +64,10 @@ export function BackendInventoryDependenciesTable() { } const link = ( { - const apmPluginContextMock = { - observabilityRuleTypeRegistry: { getFormatter: () => undefined }, - } as unknown as ApmPluginContextValue; - const kibanaContextServices = { uiSettings: { get: () => {} }, }; + const apmPluginContextMock = { + observabilityRuleTypeRegistry: { getFormatter: () => undefined }, + core: { + uiSettings: kibanaContextServices.uiSettings, + }, + } as unknown as ApmPluginContextValue; + return ( diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx index 429ad989b9738..6a3157b3c4b7f 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx @@ -32,6 +32,7 @@ import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plug import { LazyAlertsFlyout } from '../../../../../../observability/public'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { Coordinate } from '../../../../../typings/timeseries'; +import { getTimeZone } from '../../../shared/charts/helper/timezone'; const ALERT_RULE_TYPE_ID: typeof ALERT_RULE_TYPE_ID_TYPED = ALERT_RULE_TYPE_ID_NON_TYPED; @@ -58,6 +59,7 @@ interface Props { } export function ErrorDistribution({ distribution, title, fetchStatus }: Props) { + const { core } = useApmPluginContext(); const theme = useTheme(); const currentPeriod = getCoordinatedBuckets(distribution.currentPeriod); const previousPeriod = getCoordinatedBuckets(distribution.previousPeriod); @@ -103,6 +105,8 @@ export function ErrorDistribution({ distribution, title, fetchStatus }: Props) { undefined ); + const timeZone = getTimeZone(core.uiSettings); + return ( <> @@ -138,6 +142,7 @@ export function ErrorDistribution({ distribution, title, fetchStatus }: Props) { {timeseries.map((serie) => { return ( List', () => { - beforeAll(() => { - mockMoment(); - }); - - it('should render empty state', () => { - const storeState = {}; - const wrapper = mount( - - - - - , - storeState - ); - - expect(toJson(wrapper)).toMatchSnapshot(); - }); - - it('should render with data', () => { - const wrapper = mount( - - - - - - - - - - ); - - expect(toJson(wrapper)).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/List/__snapshots__/List.test.tsx.snap b/x-pack/plugins/apm/public/components/app/error_group_overview/List/__snapshots__/List.test.tsx.snap deleted file mode 100644 index ee68630daa469..0000000000000 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/List/__snapshots__/List.test.tsx.snap +++ /dev/null @@ -1,1335 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ErrorGroupOverview -> List should render empty state 1`] = ` -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Group ID - - - - - - - - - - Type - - - - - - Error message and culprit - - - - - - - - - - -
-
- - No errors found - -
-
-
-
-`; - -exports[`ErrorGroupOverview -> List should render with data 1`] = ` -.c0 { - font-family: 'Roboto Mono','Consolas','Menlo','Courier',monospace; -} - -.c2 { - max-width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.c1 { - max-width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.c3 { - font-family: 'Roboto Mono','Consolas','Menlo','Courier',monospace; - font-size: 18px; - max-width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.c4 { - font-family: 'Roboto Mono','Consolas','Menlo','Courier',monospace; -} - -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - Group ID - - - - - - - - - - Type - - - - - - Error message and culprit - - - - - - - - - - -
-
- Group ID - - - - -
- -
-
- Type -
- -
-
- Error message and culprit -
-
-
- - - About to blow up! - - -
- -
- elasticapm.contrib.django.client.capture -
-
-
-
-
-
-
-
- Occurrences -
-
- 75 -
-
-
- Latest occurrence -
-
- - 1337 minutes ago (mocking 1515578797) - -
-
-
- Group ID - - - - -
- -
-
- Type -
- -
-
- Error message and culprit -
-
-
- - - AssertionError: - - -
- -
- opbeans.views.oopsie -
-
-
-
-
-
-
-
- Occurrences -
-
- 75 -
-
-
- Latest occurrence -
-
- - 1337 minutes ago (mocking 1515578797) - -
-
-
- Group ID - - - - -
- -
-
- Type -
- -
-
- Error message and culprit -
-
-
- - - AssertionError: Bad luck! - - -
- -
- opbeans.tasks.update_stats -
-
-
-
-
-
-
-
- Occurrences -
-
- 24 -
-
-
- Latest occurrence -
-
- - 1337 minutes ago (mocking 1515578796) - -
-
-
- Group ID - - - - -
- -
-
- Type -
- -
-
- Error message and culprit -
-
-
- - - Customer with ID 8517 not found - - -
- -
- opbeans.views.customer -
-
-
-
-
-
-
-
- Occurrences -
-
- 15 -
-
-
- Latest occurrence -
-
- - 1337 minutes ago (mocking 1515578773) - -
-
-
-
-
-
-
-
- -
-
-
-
-`; diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/List/__fixtures__/props.json b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/__fixtures__/props.json similarity index 100% rename from x-pack/plugins/apm/public/components/app/error_group_overview/List/__fixtures__/props.json rename to x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/__fixtures__/props.json diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.stories.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.stories.tsx new file mode 100644 index 0000000000000..e61e43c8bb7ea --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.stories.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Meta, Story } from '@storybook/react'; +import React, { ComponentProps } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; +import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider'; + +import { ErrorGroupList } from '.'; + +type Args = ComponentProps; + +const stories: Meta = { + title: 'app/ErrorGroupOverview/ErrorGroupList', + component: ErrorGroupList, + decorators: [ + (StoryComponent) => { + return ( + + + + + + + + ); + }, + ], +}; +export default stories; + +export const Example: Story = (args) => { + return ; +}; +Example.args = { + items: [ + { + message: 'net/http: abort Handler', + occurrenceCount: 14, + culprit: 'Main.func2', + groupId: '83a653297ec29afed264d7b60d5cda7b', + latestOccurrenceAt: '2021-10-21T16:18:41.434Z', + handled: false, + type: 'errorString', + }, + { + message: 'POST /api/orders (500)', + occurrenceCount: 5, + culprit: 'logrusMiddleware', + groupId: '7a640436a9be648fd708703d1ac84650', + latestOccurrenceAt: '2021-10-21T16:18:40.162Z', + handled: false, + type: 'OpError', + }, + { + message: + 'write tcp 10.36.2.24:3000->10.36.1.14:34232: write: connection reset by peer', + occurrenceCount: 4, + culprit: 'apiHandlers.getProductCustomers', + groupId: '95ca0e312c109aa11e298bcf07f1445b', + latestOccurrenceAt: '2021-10-21T16:18:42.650Z', + handled: false, + type: 'OpError', + }, + { + message: + 'write tcp 10.36.0.21:3000->10.36.1.252:57070: write: connection reset by peer', + occurrenceCount: 3, + culprit: 'apiHandlers.getCustomers', + groupId: '4053d7e33d2b716c819bd96d9d6121a2', + latestOccurrenceAt: '2021-10-21T16:07:44.078Z', + handled: false, + type: 'OpError', + }, + { + message: + 'write tcp 10.36.0.21:3000->10.36.0.88:33926: write: broken pipe', + occurrenceCount: 2, + culprit: 'apiHandlers.getOrders', + groupId: '94f4ca8ec8c02e5318cf03f46ae4c1f3', + latestOccurrenceAt: '2021-10-21T16:13:45.742Z', + handled: false, + type: 'OpError', + }, + ], + serviceName: 'test service', +}; + +export const EmptyState: Story = (args) => { + return ; +}; +EmptyState.args = { + items: [], + serviceName: 'test service', +}; diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.test.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.test.tsx new file mode 100644 index 0000000000000..278825c25c68c --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/error_group_list.test.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render } from '@testing-library/react'; +import React from 'react'; +import * as stories from './error_group_list.stories'; + +const { Example } = composeStories(stories); + +describe('ErrorGroupList', () => { + it('renders', () => { + expect(() => render()).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx rename to x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx index 9020021d3d6f8..5e9095def6e55 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx @@ -23,7 +23,7 @@ import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { FailedTransactionRateChart } from '../../shared/charts/failed_transaction_rate_chart'; import { ErrorDistribution } from '../error_group_details/Distribution'; -import { ErrorGroupList } from './List'; +import { ErrorGroupList } from './error_group_list'; export function ErrorGroupOverview() { const { serviceName } = useApmServiceContext(); diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.stories.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.stories.tsx new file mode 100644 index 0000000000000..628ef4617417c --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.stories.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Meta, Story } from '@storybook/react'; +import React, { ComponentProps } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { CoreStart } from '../../../../../../../../src/core/public'; +import { createKibanaReactContext } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ServiceHealthStatus } from '../../../../../common/service_health_status'; +import type { ApmPluginContextValue } from '../../../../context/apm_plugin/apm_plugin_context'; +import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; +import { ServiceList } from './'; +import { items } from './__fixtures__/service_api_mock_data'; + +type Args = ComponentProps; + +const coreMock = { + http: { + get: async () => { + return { fallBackToTransactions: false }; + }, + }, + notifications: { toasts: { add: () => {} } }, + uiSettings: { get: () => ({}) }, +} as unknown as CoreStart; + +const KibanaReactContext = createKibanaReactContext(coreMock); + +const stories: Meta = { + title: 'app/ServiceInventory/ServiceList', + component: ServiceList, + decorators: [ + (StoryComponent) => { + return ( + + + + + + + + ); + }, + ], +}; +export default stories; + +export const Example: Story = (args) => { + return ; +}; +Example.args = { + isLoading: false, + items, +}; + +export const EmptyState: Story = (args) => { + return ; +}; +EmptyState.args = { + isLoading: false, + items: [], +}; + +export const WithHealthWarnings: Story = (args) => { + return ; +}; +WithHealthWarnings.args = { + isLoading: false, + items: items.map((item) => ({ + ...item, + healthStatus: ServiceHealthStatus.warning, + })), +}; diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx index 69ec1e6b1eb93..5068d13d589c8 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx @@ -5,58 +5,27 @@ * 2.0. */ -import React, { ReactNode } from 'react'; -import { MemoryRouter } from 'react-router-dom'; -import { Breakpoints } from '../../../../hooks/use_breakpoints'; -import { ServiceHealthStatus } from '../../../../../common/service_health_status'; -import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; -import { mockMoment, renderWithTheme } from '../../../../utils/testHelpers'; -import { getServiceColumns, ServiceList } from './'; -import { items } from './__fixtures__/service_api_mock_data'; +import { composeStories } from '@storybook/testing-react'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; -import { - getCallApmApiSpy, - getCreateCallApmApiSpy, -} from '../../../../services/rest/callApmApiSpy'; +import { Breakpoints } from '../../../../hooks/use_breakpoints'; +import { getServiceColumns } from './'; +import * as stories from './service_list.stories'; -function Wrapper({ children }: { children?: ReactNode }) { - return ( - - {children} - - ); -} +const { Example, EmptyState, WithHealthWarnings } = composeStories(stories); describe('ServiceList', () => { - beforeAll(() => { - mockMoment(); + it('renders empty state', async () => { + render(); - const callApmApiSpy = getCallApmApiSpy().mockImplementation( - ({ endpoint }) => { - if (endpoint === 'GET /internal/apm/fallback_to_transactions') { - return Promise.resolve({ fallbackToTransactions: false }); - } - return Promise.reject(`Response for ${endpoint} is not defined`); - } - ); - - getCreateCallApmApiSpy().mockImplementation(() => callApmApiSpy as any); + expect(await screen.findByRole('table')).toBeInTheDocument(); }); - it('renders empty state', () => { - expect(() => - renderWithTheme(, { - wrapper: Wrapper, - }) - ).not.toThrowError(); - }); + it('renders with data', async () => { + render(); - it('renders with data', () => { - expect(() => - renderWithTheme(, { - wrapper: Wrapper, - }) - ).not.toThrowError(); + expect(await screen.findByRole('table')).toBeInTheDocument(); }); describe('responsive columns', () => { @@ -212,44 +181,20 @@ describe('ServiceList', () => { }); describe('without ML data', () => { - it('does not render the health column', () => { - const { queryByText } = renderWithTheme( - , - { - wrapper: Wrapper, - } - ); - const healthHeading = queryByText('Health'); - - expect(healthHeading).toBeNull(); - }); - it('sorts by throughput', async () => { - const { findByTitle } = renderWithTheme( - , - { - wrapper: Wrapper, - } - ); + render(); - expect(await findByTitle('Throughput')).toBeInTheDocument(); + expect(await screen.findByTitle('Throughput')).toBeInTheDocument(); }); }); describe('with ML data', () => { it('renders the health column', async () => { - const { findByTitle } = renderWithTheme( - ({ - ...item, - healthStatus: ServiceHealthStatus.warning, - }))} - />, - { wrapper: Wrapper } - ); + render(); - expect(await findByTitle('Health')).toBeInTheDocument(); + expect( + await screen.findByRole('button', { name: /Health/ }) + ).toBeInTheDocument(); }); }); }); diff --git a/x-pack/plugins/apm/public/components/app/service_map/Controls.tsx b/x-pack/plugins/apm/public/components/app/service_map/Controls.tsx index dd34110a8ffc6..69644216fc267 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Controls.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Controls.tsx @@ -12,7 +12,7 @@ import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common' import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { useTheme } from '../../../hooks/use_theme'; import { useUrlParams } from '../../../context/url_params_context/use_url_params'; -import { getAPMHref } from '../../shared/Links/apm/APMLink'; +import { getLegacyApmHref } from '../../shared/Links/apm/APMLink'; import { APMQueryParams } from '../../shared/Links/url_helpers'; import { CytoscapeContext } from './Cytoscape'; import { getAnimationOptions, getNodeHeight } from './cytoscape_options'; @@ -112,7 +112,7 @@ export function Controls() { const [zoom, setZoom] = useState((cy && cy.zoom()) || 1); const duration = parseInt(theme.eui.euiAnimSpeedFast, 10); const downloadUrl = useDebugDownloadUrl(cy); - const viewFullMapUrl = getAPMHref({ + const viewFullMapUrl = getLegacyApmHref({ basePath, path: '/service-map', search: `kuery=${encodeURIComponent(kuery)}`, diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx index c04619338f80b..a545f474746a4 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx @@ -38,10 +38,10 @@ export function BackendContents({ (callApmApi) => { if (backendName) { return callApmApi({ - endpoint: 'GET /internal/apm/service-map/backend/{backendName}', + endpoint: 'GET /internal/apm/service-map/backend', params: { - path: { backendName }, query: { + backendName, environment, start, end, @@ -57,12 +57,11 @@ export function BackendContents({ ); const isLoading = status === FETCH_STATUS.LOADING; - const detailsUrl = apmRouter.link('/backends/{backendName}/overview', { - path: { backendName }, - query: query as TypeOf< - ApmRoutes, - '/backends/{backendName}/overview' - >['query'], + const detailsUrl = apmRouter.link('/backends/overview', { + query: { + ...query, + backendName, + } as TypeOf['query'], }); const trackEvent = useUiTracker(); diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx index eea15c0e915f0..208d1a30a46d1 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx @@ -76,10 +76,10 @@ export function ServiceOverviewDependenciesTable({ const itemLink = location.type === NodeType.backend ? ( - - - + + + - {children} - - - - + + {children} + + + + + ); } @@ -93,13 +96,13 @@ describe('transaction_details/distribution', () => { })); render( - - - + , + + { wrapper: Wrapper } ); await waitFor(() => { diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/sticky_span_properties.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/sticky_span_properties.tsx index 2e02dcee95371..cd8f8192beb40 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/sticky_span_properties.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/sticky_span_properties.tsx @@ -103,8 +103,10 @@ export function StickySpanProperties({ span, transaction }: Props) { fieldName: SPAN_DESTINATION_SERVICE_RESOURCE, val: ( { diff --git a/x-pack/plugins/apm/public/components/routing/home/index.tsx b/x-pack/plugins/apm/public/components/routing/home/index.tsx index 7372a40a59bbe..025fa8ddcc8a0 100644 --- a/x-pack/plugins/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/index.tsx @@ -20,6 +20,7 @@ import { ServiceInventory } from '../../app/service_inventory'; import { ServiceMapHome } from '../../app/service_map'; import { TraceOverview } from '../../app/trace_overview'; import { ApmMainTemplate } from '../templates/apm_main_template'; +import { RedirectToBackendOverviewRouteView } from './redirect_to_backend_overview_route_view'; function page({ path, @@ -109,13 +110,22 @@ export const home = { children: [ { path: '/backends/{backendName}/overview', - element: , + element: , params: t.type({ path: t.type({ backendName: t.string, }), }), }, + { + path: '/backends/overview', + element: , + params: t.type({ + query: t.type({ + backendName: t.string, + }), + }), + }, page({ path: '/backends', title: DependenciesInventoryTitle, diff --git a/x-pack/plugins/apm/public/components/routing/home/redirect_to_backend_overview_route_view.tsx b/x-pack/plugins/apm/public/components/routing/home/redirect_to_backend_overview_route_view.tsx new file mode 100644 index 0000000000000..ef6d04828c19d --- /dev/null +++ b/x-pack/plugins/apm/public/components/routing/home/redirect_to_backend_overview_route_view.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import qs from 'query-string'; +import React from 'react'; +import { Redirect } from 'react-router-dom'; +import { useApmParams } from '../../../hooks/use_apm_params'; + +export function RedirectToBackendOverviewRouteView() { + const { + path: { backendName }, + query, + } = useApmParams('/backends/{backendName}/overview'); + + const search = qs.stringify({ ...query, backendName }); + + return ; +} diff --git a/x-pack/plugins/apm/public/components/routing/templates/backend_detail_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/backend_detail_template.tsx index 27eb16a0221b7..f87e9a46df584 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/backend_detail_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/backend_detail_template.tsx @@ -7,9 +7,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import React from 'react'; -import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context'; import { ApmMainTemplate } from './apm_main_template'; import { SpanIcon } from '../../shared/span_icon'; +import { useApmParams } from '../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../hooks/use_time_range'; +import { useFetcher } from '../../../hooks/use_fetcher'; interface Props { title: string; @@ -18,11 +20,32 @@ interface Props { export function BackendDetailTemplate({ title, children }: Props) { const { - backendName, - metadata: { data }, - } = useApmBackendContext(); + query: { backendName, rangeFrom, rangeTo }, + } = useApmParams('/backends/overview'); - const metadata = data?.metadata; + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + const backendMetadataFetch = useFetcher( + (callApmApi) => { + if (!start || !end) { + return; + } + + return callApmApi({ + endpoint: 'GET /internal/apm/backends/metadata', + params: { + query: { + backendName, + start, + end, + }, + }, + }); + }, + [backendName, start, end] + ); + + const { data: { metadata } = {} } = backendMetadataFetch; return ( ; + +const coreMock = { + notifications: { toasts: { add: () => {} } }, + usageCollection: { reportUiCounter: () => {} }, + observability: { + navigation: { + PageTemplate: () => { + return <>hello world; + }, + }, + }, + http: { + basePath: { + prepend: (path: string) => `/basepath${path}`, + get: () => `/basepath`, + }, + get: async () => ({}), + }, + docLinks: { + DOC_LINK_VERSION: '0', + ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', + links: { + apm: {}, + observability: { guide: '' }, + }, + } as unknown as DocLinksStart, +} as unknown as Partial; + +const KibanaReactContext = createKibanaReactContext(coreMock); + +const stories: Meta = { + title: 'routing/templates/SettingsTemplate', + component: SettingsTemplate, + decorators: [ + (StoryComponent) => { + return ( + + + + + + + + ); + }, + ], +}; +export default stories; + +export const Example: Story = (args) => { + return ; +}; +Example.args = { + children: <>test, + selectedTab: 'agent-configurations', +}; diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.test.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.test.tsx index d52c758909ff1..90dbbdf2bc546 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.test.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.test.tsx @@ -5,69 +5,17 @@ * 2.0. */ -import { render } from '@testing-library/react'; -import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context'; -import React, { ReactNode } from 'react'; -import { SettingsTemplate } from './settings_template'; -import { createMemoryHistory } from 'history'; -import { MemoryRouter, RouteComponentProps } from 'react-router-dom'; -import { CoreStart, DocLinksStart, HttpStart } from 'kibana/public'; -import { createKibanaReactContext } from 'src/plugins/kibana_react/public'; -import { createCallApmApi } from '../../../services/rest/createCallApmApi'; +import { composeStories } from '@storybook/testing-react'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import * as stories from './settings_template.stories'; -const { location } = createMemoryHistory(); - -const KibanaReactContext = createKibanaReactContext({ - notifications: { toasts: { add: () => {} } }, - usageCollection: { reportUiCounter: () => {} }, - observability: { - navigation: { - PageTemplate: () => { - return <>hello world; - }, - }, - }, - http: { - basePath: { - prepend: (path: string) => `/basepath${path}`, - get: () => `/basepath`, - }, - } as HttpStart, - docLinks: { - DOC_LINK_VERSION: '0', - ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', - links: { - apm: {}, - observability: { guide: '' }, - }, - } as unknown as DocLinksStart, -} as unknown as Partial); - -function Wrapper({ children }: { children?: ReactNode }) { - return ( - - - {children} - - - ); -} +const { Example } = composeStories(stories); describe('Settings', () => { - beforeEach(() => { - createCallApmApi({} as CoreStart); - }); it('renders', async () => { - const routerProps = { - location, - } as unknown as RouteComponentProps<{}>; - expect(() => - render( - -
hello world
-
, - { wrapper: Wrapper } - ) - ).not.toThrowError(); + render(); + + expect(await screen.findByText('hello world')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx index a76b464731513..ecca2ddb07ec3 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx @@ -13,7 +13,7 @@ import { useHistory } from 'react-router-dom'; import { CoreStart } from 'kibana/public'; import { ApmMainTemplate } from './apm_main_template'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; -import { getAPMHref } from '../../shared/Links/apm/APMLink'; +import { getLegacyApmHref } from '../../shared/Links/apm/APMLink'; type Tab = NonNullable[0] & { key: @@ -69,7 +69,7 @@ function getTabs({ label: i18n.translate('xpack.apm.settings.agentConfig', { defaultMessage: 'Agent Configuration', }), - href: getAPMHref({ + href: getLegacyApmHref({ basePath, path: `/settings/agent-configuration`, search, @@ -80,7 +80,7 @@ function getTabs({ label: i18n.translate('xpack.apm.settings.anomalyDetection', { defaultMessage: 'Anomaly detection', }), - href: getAPMHref({ + href: getLegacyApmHref({ basePath, path: `/settings/anomaly-detection`, search, @@ -92,21 +92,29 @@ function getTabs({ label: i18n.translate('xpack.apm.settings.customizeApp', { defaultMessage: 'Customize app', }), - href: getAPMHref({ basePath, path: `/settings/customize-ui`, search }), + href: getLegacyApmHref({ + basePath, + path: `/settings/customize-ui`, + search, + }), }, { key: 'apm-indices', label: i18n.translate('xpack.apm.settings.indices', { defaultMessage: 'Indices', }), - href: getAPMHref({ basePath, path: `/settings/apm-indices`, search }), + href: getLegacyApmHref({ + basePath, + path: `/settings/apm-indices`, + search, + }), }, { key: 'schema', label: i18n.translate('xpack.apm.settings.schema', { defaultMessage: 'Schema', }), - href: getAPMHref({ basePath, path: `/settings/schema`, search }), + href: getLegacyApmHref({ basePath, path: `/settings/schema`, search }), }, ]; diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx index 7c9f6479bfc6a..fbf4dff24fbf4 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx @@ -54,13 +54,13 @@ export function useAPMHref({ ...query, }; - return getAPMHref({ basePath, path, query: nextQuery, search }); + return getLegacyApmHref({ basePath, path, query: nextQuery, search }); } /** * Get an APM link for a path. */ -export function getAPMHref({ +export function getLegacyApmHref({ basePath, path = '', search, @@ -91,7 +91,7 @@ export function APMLink({ path = '', query, mergeQuery, ...rest }: Props) { const mergedQuery = mergeQuery ? mergeQuery(query ?? {}) : query; - const href = getAPMHref({ basePath, path, search, query: mergedQuery }); + const href = getLegacyApmHref({ basePath, path, search, query: mergedQuery }); return ; } diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx index 58c510eff13a4..c45ab22682ef4 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx @@ -7,14 +7,14 @@ import { IBasePath } from 'kibana/public'; import { AgentConfigurationIntake } from '../../../../../common/agent_configuration/configuration_types'; -import { getAPMHref } from './APMLink'; +import { getLegacyApmHref } from './APMLink'; export function editAgentConfigurationHref( configService: AgentConfigurationIntake['service'], search: string, basePath: IBasePath ) { - return getAPMHref({ + return getLegacyApmHref({ basePath, path: '/settings/agent-configuration/edit', search, diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_detail_link.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_detail_link.tsx index 2f6016466e37e..06db6c9d42382 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_detail_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_detail_link.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; import { EuiLink } from '@elastic/eui'; import { pickBy, identity } from 'lodash'; -import { getAPMHref, APMLinkExtendProps } from './APMLink'; +import { getLegacyApmHref, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { pickKeys } from '../../../../../common/utils/pick_keys'; import { APMQueryParams } from '../url_helpers'; @@ -43,7 +43,7 @@ export function TransactionDetailLink({ const { urlParams } = useUrlParams(); const { core } = useApmPluginContext(); const location = useLocation(); - const href = getAPMHref({ + const href = getLegacyApmHref({ basePath: core.http.basePath, path: `/services/${serviceName}/transactions/view`, query: { diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_overview_link.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_overview_link.tsx index e56e4a32d9bad..d3e40aebc1daf 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_overview_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/transaction_overview_link.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; import { removeUndefinedProps } from '../../../../context/url_params_context/helpers'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; -import { APMLinkExtendProps, getAPMHref } from './APMLink'; +import { APMLinkExtendProps, getLegacyApmHref } from './APMLink'; interface Props extends APMLinkExtendProps { serviceName: string; @@ -29,7 +29,7 @@ export function useTransactionsOverviewHref({ const query = { latencyAggregationType, transactionType }; - return getAPMHref({ + return getLegacyApmHref({ basePath: core.http.basePath, path: `/services/${serviceName}/transactions`, query: removeUndefinedProps(query), diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx index 970cc886d30bd..4891ca896076a 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx @@ -24,7 +24,7 @@ import { useApmParams } from '../../../hooks/use_apm_params'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { useTheme } from '../../../hooks/use_theme'; import { APIReturnType } from '../../../services/rest/createCallApmApi'; -import { getAPMHref } from '../Links/apm/APMLink'; +import { getLegacyApmHref } from '../Links/apm/APMLink'; export type AnomalyDetectionApiResponse = APIReturnType<'GET /internal/apm/settings/anomaly-detection/jobs'>; @@ -47,7 +47,7 @@ export function AnomalyDetectionSetupLink() { return ( {canGetJobs && hasValidLicense ? ( diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx index 633d03ce8e1df..655fc2da2b097 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx @@ -9,7 +9,7 @@ import { EuiHeaderLink, EuiHeaderLinks } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { getAlertingCapabilities } from '../../alerting/get_alerting_capabilities'; -import { getAPMHref } from '../Links/apm/APMLink'; +import { getLegacyApmHref } from '../Links/apm/APMLink'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { AlertingPopoverAndFlyout } from './alerting_popover_flyout'; import { AnomalyDetectionSetupLink } from './anomaly_detection_setup_link'; @@ -33,7 +33,7 @@ export function ApmHeaderActionMenu() { const canSaveApmAlerts = capabilities.apm.save && canSaveAlerts; function apmHref(path: string) { - return getAPMHref({ basePath, path, search }); + return getLegacyApmHref({ basePath, path, search }); } function kibanaHref(path: string) { diff --git a/x-pack/plugins/apm/public/components/shared/backend_link.stories.tsx b/x-pack/plugins/apm/public/components/shared/backend_link.stories.tsx index 31bc2f2302798..d26269d85cc9c 100644 --- a/x-pack/plugins/apm/public/components/shared/backend_link.stories.tsx +++ b/x-pack/plugins/apm/public/components/shared/backend_link.stories.tsx @@ -30,7 +30,11 @@ export const Example: Story = (args) => { return ; }; Example.args = { - backendName: 'postgres', - type: 'db', - subtype: 'postgresql', + query: { + backendName: 'postgres', + environment: 'ENVIRONMENT_ALL', + kuery: '', + rangeFrom: 'now-15m', + rangeTo: 'now', + }, }; diff --git a/x-pack/plugins/apm/public/components/shared/backend_link.test.tsx b/x-pack/plugins/apm/public/components/shared/backend_link.test.tsx new file mode 100644 index 0000000000000..683fec3a41725 --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/backend_link.test.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render } from '@testing-library/react'; +import React from 'react'; +import * as stories from './backend_link.stories'; + +const { Example } = composeStories(stories); + +describe('BackendLink', () => { + it('renders', () => { + expect(() => render()).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/shared/backend_link.tsx b/x-pack/plugins/apm/public/components/shared/backend_link.tsx index 342c668d2efdb..92cad37273b02 100644 --- a/x-pack/plugins/apm/public/components/shared/backend_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/backend_link.tsx @@ -17,15 +17,13 @@ import { SpanIcon } from './span_icon'; const StyledLink = euiStyled(EuiLink)`${truncate('100%')};`; interface BackendLinkProps { - backendName: string; - query: TypeOf['query']; + query: TypeOf['query']; subtype?: string; type?: string; onClick?: React.ComponentProps['onClick']; } export function BackendLink({ - backendName, query, subtype, type, @@ -35,8 +33,7 @@ export function BackendLink({ return ( - {backendName} + {query.backendName} ); diff --git a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx index 16157071affcd..7f7c163ff1ea1 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx @@ -44,6 +44,8 @@ import { getMaxY, getResponseTimeTickFormatter, } from '../../../shared/charts/transaction_charts/helper'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { getTimeZone } from '../helper/timezone'; interface Props { fetchStatus: FETCH_STATUS; @@ -66,15 +68,12 @@ export function BreakdownChart({ }: Props) { const history = useHistory(); const chartTheme = useChartTheme(); - + const { core } = useApmPluginContext(); const { chartRef, setPointerEvent } = useChartPointerEventContext(); - const { query: { rangeFrom, rangeTo }, } = useApmParams('/services/{serviceName}'); - const theme = useTheme(); - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const min = moment.utc(start).valueOf(); @@ -92,6 +91,8 @@ export function BreakdownChart({ ? getResponseTimeTickFormatter(getDurationFormatter(maxY)) : asPercentBound; + const timeZone = getTimeZone(core.uiSettings); + return ( @@ -150,6 +151,7 @@ export function BreakdownChart({ timeseries.map((serie) => { return ( { setSelectedAlertId, theme, })![0].props.dataValues[0].header - ).toEqual('Alert'); + ).toEqual('Alert - Experimental'); }); it('uses the reason in the annotation details', () => { @@ -123,7 +123,7 @@ describe('getAlertAnnotations', () => { setSelectedAlertId, theme, })![0].props.dataValues[0].details - ).toEqual('a good reason'); + ).toEqual('a good reason. Click to see more details.'); }); describe('with no formatter', () => { @@ -140,7 +140,7 @@ describe('getAlertAnnotations', () => { setSelectedAlertId, theme, })![0].props.dataValues[0].details - ).toEqual(alert[ALERT_RULE_NAME]![0]); + ).toEqual(`${alert[ALERT_RULE_NAME]![0]}. Click to see more details.`); }); }); @@ -191,7 +191,7 @@ describe('getAlertAnnotations', () => { setSelectedAlertId, theme, })![0].props.dataValues[0].header - ).toEqual('Warning Alert'); + ).toEqual('Warning Alert - Experimental'); }); }); @@ -224,7 +224,7 @@ describe('getAlertAnnotations', () => { setSelectedAlertId, theme, })![0].props.dataValues[0].header - ).toEqual('Critical Alert'); + ).toEqual('Critical Alert - Experimental'); }); }); }); diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx index f4c47a9247e75..038269d3cefdc 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx @@ -122,7 +122,13 @@ export function getAlertAnnotations({ const end = start + parsed[ALERT_DURATION]! / 1000; const severityLevel = parsed[ALERT_SEVERITY]; const color = getAlertColor({ severityLevel, theme }); - const header = getAlertHeader({ severityLevel }); + const experimentalLabel = i18n.translate( + 'xpack.apm.alertAnnotationTooltipExperimentalText', + { defaultMessage: 'Experimental' } + ); + const header = `${getAlertHeader({ + severityLevel, + })} - ${experimentalLabel}`; const formatter = getFormatter(parsed[ALERT_RULE_TYPE_ID]!); const formatted = { link: undefined, @@ -133,13 +139,18 @@ export function getAlertAnnotations({ }) ?? {}), }; const isSelected = uuid === selectedAlertId; + const moreDetails = i18n.translate( + 'xpack.apm.alertAnnotationTooltipMoreDetailsText', + { defaultMessage: 'Click to see more details.' } + ); + const details = `${formatted.reason}. ${moreDetails}`; return [ { let originalTimezone: moment.MomentZone | null; @@ -67,4 +68,22 @@ describe('Timezone helper', () => { ]); }); }); + + describe('getTimeZone', () => { + it('returns local when uiSettings is undefined', () => { + expect(getTimeZone()).toEqual('local'); + }); + + it('returns local when uiSettings returns Browser', () => { + expect( + getTimeZone({ get: () => 'Browser' } as unknown as IUiSettingsClient) + ).toEqual('local'); + }); + it('returns timezone defined on uiSettings', () => { + const timezone = 'America/toronto'; + expect( + getTimeZone({ get: () => timezone } as unknown as IUiSettingsClient) + ).toEqual(timezone); + }); + }); }); diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts b/x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts index 539c81c61c3ce..f807d83c8977f 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts @@ -7,6 +7,8 @@ import d3 from 'd3'; import { getTimezoneOffsetInMs } from './get_timezone_offset_in_ms'; +import { IUiSettingsClient } from '../../../../../../../../src/core/public'; +import { UI_SETTINGS } from '../../../../../../../../src/plugins/data/common'; interface Params { domain: [number, number]; @@ -31,3 +33,15 @@ export const getDomainTZ = (min: number, max: number): [number, number] => { ); return [xMinZone, xMaxZone]; }; + +export function getTimeZone(uiSettings?: IUiSettingsClient) { + const kibanaTimeZone = uiSettings?.get<'Browser' | string>( + UI_SETTINGS.DATEFORMAT_TZ + ); + + if (!kibanaTimeZone || kibanaTimeZone === 'Browser') { + return 'local'; + } + + return kibanaTimeZone; +} diff --git a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx index ad51e66f1959c..e1921aca8d9ef 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx @@ -20,18 +20,18 @@ import { ALERT_RULE_UUID, ALERT_RULE_NAME, ALERT_RULE_CATEGORY, + ALERT_RULE_CONSUMER, ALERT_RULE_PRODUCER, + SPACE_IDS, } from '@kbn/rule-data-utils'; -import { StoryContext } from '@storybook/react'; -import React, { ComponentType } from 'react'; -import { MemoryRouter, Route } from 'react-router-dom'; +import { Meta, Story } from '@storybook/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types'; -import { - ApmPluginContext, - ApmPluginContextValue, -} from '../../../../context/apm_plugin/apm_plugin_context'; +import type { ApmPluginContextValue } from '../../../../context/apm_plugin/apm_plugin_context'; +import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; import { APMServiceContext } from '../../../../context/apm_service/apm_service_context'; import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider'; @@ -46,7 +46,7 @@ interface Args { latencyChartResponse: APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/latency'>; } -export default { +const stories: Meta = { title: 'shared/charts/LatencyChart', component: LatencyChart, argTypes: { @@ -57,7 +57,7 @@ export default { }, }, decorators: [ - (Story: ComponentType, { args }: StoryContext) => { + (StoryComponent, { args }) => { const { alertsResponse, latencyChartResponse } = args as Args; const serviceName = 'testService'; @@ -88,44 +88,46 @@ export default { const transactionType = `${Math.random()}`; // So we don't memoize return ( - - - - + + + - - - - - - - - - - - + + + + + + + + ); }, ], }; -export function Example(_args: Args) { +export default stories; + +export const Example: Story = () => { return ( ); -} +}; Example.args = { alertsResponse: { alerts: [ @@ -139,6 +141,7 @@ Example.args = { tags: ['apm', 'service.name:frontend-rum'], 'transaction.type': ['page-load'], [ALERT_RULE_PRODUCER]: ['apm'], + [ALERT_RULE_CONSUMER]: ['apm'], [ALERT_UUID]: ['af2ae371-df79-4fca-b0eb-a2dbd9478180'], [ALERT_RULE_UUID]: ['82e0ee40-c2f4-11eb-9a42-a9da66a1722f'], 'event.action': ['active'], @@ -149,9 +152,11 @@ Example.args = { [ALERT_START]: ['2021-06-02T04:00:00.000Z'], 'event.kind': ['state'], [ALERT_RULE_CATEGORY]: ['Latency threshold'], + [SPACE_IDS]: [], }, { [ALERT_RULE_TYPE_ID]: ['apm.transaction_duration'], + [ALERT_EVALUATION_VALUE]: [2001708.19], 'service.name': ['frontend-rum'], [ALERT_RULE_NAME]: ['Latency threshold | frontend-rum'], @@ -160,6 +165,7 @@ Example.args = { tags: ['apm', 'service.name:frontend-rum'], 'transaction.type': ['page-load'], [ALERT_RULE_PRODUCER]: ['apm'], + [ALERT_RULE_CONSUMER]: ['apm'], [ALERT_SEVERITY]: ['warning'], [ALERT_UUID]: ['af2ae371-df79-4fca-b0eb-a2dbd9478181'], [ALERT_RULE_UUID]: ['82e0ee40-c2f4-11eb-9a42-a9da66a1722f'], @@ -171,9 +177,11 @@ Example.args = { [ALERT_START]: ['2021-06-02T10:45:00.000Z'], 'event.kind': ['state'], [ALERT_RULE_CATEGORY]: ['Latency threshold'], + [SPACE_IDS]: [], }, { [ALERT_RULE_TYPE_ID]: ['apm.transaction_duration'], + [ALERT_EVALUATION_VALUE]: [2001708.19], 'service.name': ['frontend-rum'], [ALERT_RULE_NAME]: ['Latency threshold | frontend-rum'], @@ -182,6 +190,7 @@ Example.args = { tags: ['apm', 'service.name:frontend-rum'], 'transaction.type': ['page-load'], [ALERT_RULE_PRODUCER]: ['apm'], + [ALERT_RULE_CONSUMER]: ['apm'], [ALERT_SEVERITY]: ['critical'], [ALERT_UUID]: ['af2ae371-df79-4fca-b0eb-a2dbd9478182'], [ALERT_RULE_UUID]: ['82e0ee40-c2f4-11eb-9a42-a9da66a1722f'], @@ -193,6 +202,7 @@ Example.args = { [ALERT_START]: ['2021-06-02T16:50:00.000Z'], 'event.kind': ['state'], [ALERT_RULE_CATEGORY]: ['Latency threshold'], + [SPACE_IDS]: [], }, ], }, @@ -801,19 +811,24 @@ Example.args = { }, ], }, - previousPeriod: { latencyTimeseries: [] }, + previousPeriod: { latencyTimeseries: [], overallAvgDuration: null }, }, }; -export function NoData(_args: Args) { +export const NoData: Story = () => { return ( ); -} +}; NoData.args = { alertsResponse: { alerts: [] }, latencyChartResponse: { - currentPeriod: { latencyTimeseries: [] }, - previousPeriod: { latencyTimeseries: [] }, + anomalyTimeseries: { + jobId: 'apm-production-00aa-high_mean_transaction_duration', + anomalyScore: [], + anomalyBoundaries: [], + }, + currentPeriod: { latencyTimeseries: [], overallAvgDuration: null }, + previousPeriod: { latencyTimeseries: [], overallAvgDuration: null }, }, }; diff --git a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.test.tsx new file mode 100644 index 0000000000000..f5f7c87ed22de --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.test.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render, waitFor } from '@testing-library/react'; +import React from 'react'; +import * as stories from './latency_chart.stories'; + +const { Example } = composeStories(stories); + +describe('LatencyChart', () => { + it('renders', async () => { + await waitFor(() => { + expect(() => render()).not.toThrowError(); + }); + }); +}); diff --git a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx index 08e8908d50e7a..bcdfff2678cda 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx @@ -19,8 +19,8 @@ import { RectAnnotation, ScaleType, Settings, - YDomainRange, XYBrushEvent, + YDomainRange, } from '@elastic/charts'; import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -46,6 +46,7 @@ import { getLatencyChartSelector } from '../../../selectors/latency_chart_select import { unit } from '../../../utils/style'; import { ChartContainer } from './chart_container'; import { getAlertAnnotations } from './helper/get_alert_annotations'; +import { getTimeZone } from './helper/timezone'; import { isTimeseriesEmpty, onBrushEnd } from './helper/helper'; interface Props { @@ -85,7 +86,7 @@ export function TimeseriesChart({ alerts, }: Props) { const history = useHistory(); - const { observabilityRuleTypeRegistry } = useApmPluginContext(); + const { observabilityRuleTypeRegistry, core } = useApmPluginContext(); const { getFormatter } = observabilityRuleTypeRegistry; const { annotations } = useAnnotationsContext(); const { setPointerEvent, chartRef } = useChartPointerEventContext(); @@ -97,6 +98,8 @@ export function TimeseriesChart({ const xValues = timeseries.flatMap(({ data }) => data.map(({ x }) => x)); + const timeZone = getTimeZone(core.uiSettings); + const min = Math.min(...xValues); const max = Math.max(...xValues); @@ -180,6 +183,7 @@ export function TimeseriesChart({ return ( = (args) => { }; Example.args = { agentName: 'java', + query: { + environment: 'ENVIRONMENT_ALL', + kuery: '', + rangeFrom: 'now-15m', + rangeTo: 'now', + }, serviceName: 'opbeans-java', }; diff --git a/x-pack/plugins/apm/public/components/shared/service_link.test.tsx b/x-pack/plugins/apm/public/components/shared/service_link.test.tsx new file mode 100644 index 0000000000000..63311b306e6bb --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/service_link.test.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render } from '@testing-library/react'; +import React from 'react'; +import * as stories from './service_link.stories'; + +const { Example } = composeStories(stories); + +describe('ServiceLink', () => { + it('renders', () => { + expect(() => render()).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/shared/suggestions_select/suggestions_select.test.tsx b/x-pack/plugins/apm/public/components/shared/suggestions_select/suggestions_select.test.tsx index b1fce1c439f32..629a3f3df47f7 100644 --- a/x-pack/plugins/apm/public/components/shared/suggestions_select/suggestions_select.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/suggestions_select/suggestions_select.test.tsx @@ -6,14 +6,16 @@ */ import { composeStories } from '@storybook/testing-react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import * as stories from './suggestions_select.stories'; const { Example } = composeStories(stories); describe('SuggestionsSelect', () => { - it('renders', () => { - expect(() => render()).not.toThrowError(); + it('renders', async () => { + render(); + + expect(await screen.findByRole('combobox')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx b/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx deleted file mode 100644 index 6093f05c2cb02..0000000000000 --- a/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx +++ /dev/null @@ -1,74 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { createContext, useMemo } from 'react'; -import { FETCH_STATUS, useFetcher } from '../../hooks/use_fetcher'; -import { useApmParams } from '../../hooks/use_apm_params'; -import { APIReturnType } from '../../services/rest/createCallApmApi'; -import { useTimeRange } from '../../hooks/use_time_range'; - -export const ApmBackendContext = createContext< - | { - backendName: string; - metadata: { - data?: APIReturnType<'GET /internal/apm/backends/{backendName}/metadata'>; - status?: FETCH_STATUS; - }; - } - | undefined ->(undefined); - -export function ApmBackendContextProvider({ - children, -}: { - children: React.ReactNode; -}) { - const { - path: { backendName }, - query: { rangeFrom, rangeTo }, - } = useApmParams('/backends/{backendName}/overview'); - - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - - const backendMetadataFetch = useFetcher( - (callApmApi) => { - if (!start || !end) { - return; - } - - return callApmApi({ - endpoint: 'GET /internal/apm/backends/{backendName}/metadata', - params: { - path: { - backendName, - }, - query: { - start, - end, - }, - }, - }); - }, - [backendName, start, end] - ); - - const value = useMemo(() => { - return { - backendName, - metadata: { - data: backendMetadataFetch.data, - status: backendMetadataFetch.status, - }, - }; - }, [backendName, backendMetadataFetch.data, backendMetadataFetch.status]); - - return ( - - {children} - - ); -} diff --git a/x-pack/plugins/apm/public/context/apm_backend/use_apm_backend_context.tsx b/x-pack/plugins/apm/public/context/apm_backend/use_apm_backend_context.tsx deleted file mode 100644 index 5a48014c75662..0000000000000 --- a/x-pack/plugins/apm/public/context/apm_backend/use_apm_backend_context.tsx +++ /dev/null @@ -1,20 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { useContext } from 'react'; -import { ApmBackendContext } from './apm_backend_context'; - -export function useApmBackendContext() { - const context = useContext(ApmBackendContext); - - if (!context) { - throw new Error( - 'ApmBackendContext has no set value, did you forget rendering ApmBackendContextProvider?' - ); - } - - return context; -} diff --git a/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts b/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts index 3d0f0bd3c3c72..d5cc9a63dbfcd 100644 --- a/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts +++ b/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts @@ -135,11 +135,9 @@ export async function aggregateLatencyMetrics() { destOptions = parseIndexUrl(dest); destClient = getEsClient({ node: destOptions.node }); - const mappings = ( - await sourceClient.indices.getMapping({ - index: sourceOptions.index, - }) - ).body; + const mappings = await sourceClient.indices.getMapping({ + index: sourceOptions.index, + }); const lastMapping = mappings[Object.keys(mappings)[0]]; diff --git a/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts b/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts index b9102efee50dc..559f746ab50f2 100644 --- a/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts +++ b/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts @@ -10,7 +10,7 @@ import { execSync } from 'child_process'; import moment from 'moment'; import path from 'path'; import fs from 'fs'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getEsClient } from '../shared/get_es_client'; import { parseIndexUrl } from '../shared/parse_index_url'; @@ -144,6 +144,7 @@ async function run() { // profile const indicesWithDocs = response.body.aggregations?.index.buckets.map( + // @ts-expect-error bucket has any type (bucket) => bucket.key as string ) ?? []; diff --git a/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts b/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts index 8bab4df9006f5..39f398354422f 100644 --- a/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts +++ b/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts @@ -36,11 +36,9 @@ export async function createOrUpdateIndex({ delete settings?.index?.number_of_shards; delete settings?.index?.sort; - const indexExists = ( - await client.indices.exists({ - index: indexName, - }) - ).body as unknown; + const indexExists = await client.indices.exists({ + index: indexName, + }); if (!indexExists) { await client.indices.create({ 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 42833d28adcb2..3ee5642852c06 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,7 @@ */ import { Client } from '@elastic/elasticsearch'; -import { ApiKeyAuth, BasicAuth } from '@elastic/elasticsearch/lib/pool'; +import type { ClientOptions } from '@elastic/elasticsearch/lib/client'; import { ESSearchResponse, ESSearchRequest, @@ -19,11 +19,13 @@ export function getEsClient({ auth, }: { node: string; - auth?: BasicAuth | ApiKeyAuth; -}) { + auth?: ClientOptions['auth']; + // Should be refactored + // The inferred type of 'getEsClient' references an inaccessible 'unique symbol' type. A type annotation is necessary. +}): any { const client = new Client({ node, - ssl: { + tls: { rejectUnauthorized: false, }, requestTimeout: 120000, @@ -36,14 +38,11 @@ export function getEsClient({ TDocument = unknown, TSearchRequest extends ESSearchRequest = ESSearchRequest >(request: TSearchRequest) { - const response = await originalSearch(request); + const response = await originalSearch(request); return { ...response, - body: response.body as unknown as ESSearchResponse< - TDocument, - TSearchRequest - >, + body: response as unknown as ESSearchResponse, }; } diff --git a/x-pack/plugins/apm/scripts/test/e2e.js b/x-pack/plugins/apm/scripts/test/e2e.js index 629cdc2498414..b3ce510a8e569 100644 --- a/x-pack/plugins/apm/scripts/test/e2e.js +++ b/x-pack/plugins/apm/scripts/test/e2e.js @@ -12,6 +12,11 @@ const yargs = require('yargs'); const childProcess = require('child_process'); const { argv } = yargs(process.argv.slice(2)) + .option('kibana-install-dir', { + default: '', + type: 'string', + description: 'Path to the Kibana install directory', + }) .option('server', { default: false, type: 'boolean', @@ -30,7 +35,7 @@ const { argv } = yargs(process.argv.slice(2)) }) .help(); -const { server, runner, open } = argv; +const { server, runner, open, kibanaInstallDir } = argv; const e2eDir = path.join(__dirname, '../../ftr_e2e'); @@ -44,6 +49,6 @@ if (server) { const config = open ? './cypress_open.ts' : './cypress_run.ts'; childProcess.execSync( - `node ../../../../scripts/${ftrScript} --config ${config}`, + `node ../../../../scripts/${ftrScript} --config ${config} --kibana-install-dir '${kibanaInstallDir}'`, { cwd: e2eDir, stdio: 'inherit' } ); diff --git a/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts b/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts index 6397c79ce4ffb..990376ca3e6ba 100644 --- a/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts +++ b/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts @@ -17,7 +17,6 @@ import { argv } from 'yargs'; import { Logger } from 'kibana/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { CollectTelemetryParams } from '../../server/lib/apm_telemetry/collect_data_telemetry'; -import { unwrapEsResponse } from '../../../observability/common/utils/unwrap_es_response'; import { downloadTelemetryTemplate } from '../shared/download-telemetry-template'; import { mergeApmTelemetryMapping } from '../../common/apm_telemetry'; import { generateSampleDocuments } from './generate-sample-documents'; @@ -87,18 +86,13 @@ async function uploadData() { apmAgentConfigurationIndex: '.apm-agent-configuration', }, search: (body) => { - return unwrapEsResponse(client.search(body)) as Promise; + return client.search(body) as Promise; }, indicesStats: (body) => { - return unwrapEsResponse(client.indices.stats(body)); + return client.indices.stats(body); }, transportRequest: ((params) => { - return unwrapEsResponse( - client.transport.request({ - method: params.method, - path: params.path, - }) - ); + return; }) as CollectTelemetryParams['transportRequest'], }, }); diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 1ed54be0271dd..6bf3b2cb493f1 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -62,23 +62,38 @@ export const config: PluginConfigDescriptor = { deprecations: ({ renameFromRoot, deprecateFromRoot, unusedFromRoot }) => [ renameFromRoot( 'apm_oss.transactionIndices', - 'xpack.apm.indices.transaction' + 'xpack.apm.indices.transaction', + { level: 'warning' } ), - renameFromRoot('apm_oss.spanIndices', 'xpack.apm.indices.span'), - renameFromRoot('apm_oss.errorIndices', 'xpack.apm.indices.error'), - renameFromRoot('apm_oss.metricsIndices', 'xpack.apm.indices.metric'), - renameFromRoot('apm_oss.sourcemapIndices', 'xpack.apm.indices.sourcemap'), - renameFromRoot('apm_oss.onboardingIndices', 'xpack.apm.indices.onboarding'), - deprecateFromRoot('apm_oss.enabled', '8.0.0'), - unusedFromRoot('apm_oss.fleetMode'), - unusedFromRoot('apm_oss.indexPattern'), + renameFromRoot('apm_oss.spanIndices', 'xpack.apm.indices.span', { + level: 'warning', + }), + renameFromRoot('apm_oss.errorIndices', 'xpack.apm.indices.error', { + level: 'warning', + }), + renameFromRoot('apm_oss.metricsIndices', 'xpack.apm.indices.metric', { + level: 'warning', + }), + renameFromRoot('apm_oss.sourcemapIndices', 'xpack.apm.indices.sourcemap', { + level: 'warning', + }), + renameFromRoot( + 'apm_oss.onboardingIndices', + 'xpack.apm.indices.onboarding', + { level: 'warning' } + ), + deprecateFromRoot('apm_oss.enabled', '8.0.0', { level: 'warning' }), + unusedFromRoot('apm_oss.fleetMode', { level: 'warning' }), + unusedFromRoot('apm_oss.indexPattern', { level: 'warning' }), renameFromRoot( 'xpack.apm.maxServiceEnvironments', - `uiSettings.overrides[${maxSuggestions}]` + `uiSettings.overrides[${maxSuggestions}]`, + { level: 'warning' } ), renameFromRoot( 'xpack.apm.maxServiceSelections', - `uiSettings.overrides[${maxSuggestions}]` + `uiSettings.overrides[${maxSuggestions}]`, + { level: 'warning' } ), ], exposeToBrowser: { diff --git a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts index 1f8b88b3db3e7..8767b5a60d9b2 100644 --- a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts +++ b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { rangeQuery } from '../../../../../observability/server'; import { SERVICE_NAME, @@ -14,11 +14,11 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { AlertParams } from '../../../routes/alerts/chart_preview'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, getSearchAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { Setup } from '../../helpers/setup_request'; export async function getTransactionDurationChartPreview({ @@ -52,17 +52,14 @@ export async function getTransactionDurationChartPreview({ : []), ...rangeQuery(start, end), ...environmentQuery(environment), - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ] as QueryDslQueryContainer[], }, }; - const transactionDurationField = - getTransactionDurationFieldForAggregatedTransactions( - searchAggregatedTransactions - ); + const transactionDurationField = getTransactionDurationFieldForTransactions( + searchAggregatedTransactions + ); const aggs = { timeseries: { @@ -90,11 +87,7 @@ export async function getTransactionDurationChartPreview({ }; const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, query, aggs }, }; diff --git a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts index 1690c92b23e66..d3f03c597e8fb 100644 --- a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts @@ -13,10 +13,10 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { AlertParams } from '../../../routes/alerts/chart_preview'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, getSearchAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { Setup } from '../../helpers/setup_request'; import { calculateFailedTransactionRate, @@ -45,11 +45,7 @@ export async function getTransactionErrorRateChartPreview({ const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, @@ -62,7 +58,7 @@ export async function getTransactionErrorRateChartPreview({ : []), ...rangeQuery(start, end), ...environmentQuery(environment), - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ], 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 df4de254346c9..3500dc8fee921 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 @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import type { ALERT_EVALUATION_THRESHOLD as ALERT_EVALUATION_THRESHOLD_TYPED, @@ -41,9 +41,9 @@ import { ProcessorEvent } from '../../../common/processor_event'; import { environmentQuery } from '../../../common/utils/environment_query'; import { getDurationFormatter } from '../../../common/utils/formatters'; import { - getDocumentTypeFilterForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, +} from '../helpers/transactions'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; import { alertingEsClient } from './alerting_es_client'; @@ -122,7 +122,7 @@ export function registerTransactionDurationAlertType({ ? indices.metric : indices.transaction; - const field = getTransactionDurationFieldForAggregatedTransactions( + const field = getTransactionDurationFieldForTransactions( searchAggregatedTransactions ); @@ -140,7 +140,7 @@ export function registerTransactionDurationAlertType({ }, }, }, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), { term: { [SERVICE_NAME]: alertParams.serviceName } }, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts index 08203646d9004..2809d7feadb37 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { compact } from 'lodash'; import { ESSearchResponse } from 'src/core/types/elasticsearch'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ALERT_EVALUATION_THRESHOLD as ALERT_EVALUATION_THRESHOLD_TYPED, ALERT_EVALUATION_VALUE as ALERT_EVALUATION_VALUE_TYPED, 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 598487d02625a..5ba7ed5321d70 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 @@ -46,7 +46,7 @@ import { apmActionVariables } from './action_variables'; import { alertingEsClient } from './alerting_es_client'; import { RegisterRuleDependencies } from './register_apm_alerts'; import { SearchAggregatedTransactionSetting } from '../../../common/aggregated_transactions'; -import { getDocumentTypeFilterForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getDocumentTypeFilterForTransactions } from '../helpers/transactions'; import { asPercent } from '../../../../observability/common/utils/formatters'; const ALERT_EVALUATION_THRESHOLD: typeof ALERT_EVALUATION_THRESHOLD_TYPED = @@ -131,7 +131,7 @@ export function registerTransactionErrorRateAlertType({ }, }, }, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), { 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 22a2090dbb6cd..9b5820767690f 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 @@ -7,7 +7,7 @@ import { merge } from 'lodash'; import { Logger } from 'kibana/server'; -import { IndicesStats } from '@elastic/elasticsearch/api/requestParams'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ESSearchRequest, ESSearchResponse, @@ -22,7 +22,7 @@ type TelemetryTaskExecutor = (params: { params: TSearchRequest ): Promise>; indicesStats( - params: IndicesStats + params: estypes.IndicesStatsRequest // promise returned by client has an abort property // so we cannot use its ReturnType ): Promise<{ 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 8764223ad1ebb..f06226c864a98 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 @@ * 2.0. */ import { flatten, merge, sortBy, sum, pickBy } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; import { ProcessorEvent } from '../../../../common/processor_event'; import { TelemetryTask } from '.'; @@ -599,7 +599,7 @@ export const tasks: TelemetryTask[] = [ executor: async ({ search, indices }) => { const response = await search({ index: [indices.transaction, indices.span, indices.error], - terminateAfter: 1, + terminate_after: 1, body: { query: { exists: { diff --git a/x-pack/plugins/apm/server/lib/connections/exclude_rum_exit_spans_query.ts b/x-pack/plugins/apm/server/lib/connections/exclude_rum_exit_spans_query.ts index 89a510fe508c6..4e15500a59466 100644 --- a/x-pack/plugins/apm/server/lib/connections/exclude_rum_exit_spans_query.ts +++ b/x-pack/plugins/apm/server/lib/connections/exclude_rum_exit_spans_query.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AGENT_NAME } from '../../../common/elasticsearch_fieldnames'; import { RUM_AGENT_NAMES } from '../../../common/agent_name'; diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts index be6518708eddb..2eb0ed3db02bd 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import objectHash from 'object-hash'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts index 4f48f3388c017..ff46db949d122 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts @@ -7,7 +7,7 @@ import { sum } from 'lodash'; import objectHash from 'object-hash'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts index 03b94defda6dd..5c1c628762edb 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts @@ -7,7 +7,7 @@ import { ValuesType } from 'utility-types'; import { merge } from 'lodash'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { joinByKey } from '../../../../common/utils/join_by_key'; import { Setup } from '../../helpers/setup_request'; import { getStats } from './get_stats'; diff --git a/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts b/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts index 1ddc3f7ed888c..d6c53aeea078e 100644 --- a/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts +++ b/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts @@ -12,7 +12,7 @@ import { SERVICE_ENVIRONMENT, } from '../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; /** * This is used for getting *all* environments, and does not filter by range. @@ -45,9 +45,7 @@ export async function getAllEnvironments({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/environments/get_environments.ts b/x-pack/plugins/apm/server/lib/environments/get_environments.ts index 08f6f089e8d08..678cfd891ae57 100644 --- a/x-pack/plugins/apm/server/lib/environments/get_environments.ts +++ b/x-pack/plugins/apm/server/lib/environments/get_environments.ts @@ -12,7 +12,7 @@ import { import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { ProcessorEvent } from '../../../common/processor_event'; import { rangeQuery } from '../../../../observability/server'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; /** @@ -51,9 +51,7 @@ export async function getEnvironments({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.metric, ProcessorEvent.error, ], diff --git a/x-pack/plugins/apm/server/lib/event_metadata/get_event_metadata.ts b/x-pack/plugins/apm/server/lib/event_metadata/get_event_metadata.ts index 97e2e1356363f..b9e0dee52a42e 100644 --- a/x-pack/plugins/apm/server/lib/event_metadata/get_event_metadata.ts +++ b/x-pack/plugins/apm/server/lib/event_metadata/get_event_metadata.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ERROR_ID, SPAN_ID, diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/cancel_es_request_on_abort.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/cancel_es_request_on_abort.ts index a14564fc8e268..41dc33dfa193f 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/cancel_es_request_on_abort.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/cancel_es_request_on_abort.ts @@ -5,24 +5,18 @@ * 2.0. */ -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; -import { KibanaRequest } from 'src/core/server'; +import type { KibanaRequest } from 'src/core/server'; -export function cancelEsRequestOnAbort>( +export function cancelEsRequestOnAbort>( promise: T, - request: KibanaRequest + request: KibanaRequest, + controller: AbortController ) { const subscription = request.events.aborted$.subscribe(() => { - promise.abort(); + controller.abort(); }); - // using .catch() here means unsubscribe will be called - // after it has thrown an error, so we use .then(onSuccess, onFailure) - // syntax - promise.then( - () => subscription.unsubscribe(), - () => subscription.unsubscribe() - ); + promise.finally(() => subscription.unsubscribe()); return promise; } diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts index 8f03aceef3348..e9280ba3e5976 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { setTimeout as setTimeoutPromise } from 'timers/promises'; import { contextServiceMock, executionContextServiceMock, @@ -34,17 +34,19 @@ describe('createApmEventClient', () => { }); const router = createRouter('/'); - const abort = jest.fn(); + let abortSignal: AbortSignal | undefined; router.get( { path: '/', validate: false }, async (context, request, res) => { const eventClient = createApmEventClient({ esClient: { - search: () => { - return Object.assign( - new Promise((resolve) => setTimeout(resolve, 3000)), - { abort } - ); + search: async ( + params: any, + { signal }: { signal: AbortSignal } + ) => { + abortSignal = signal; + await setTimeoutPromise(3_000); + return {}; }, } as any, debug: false, @@ -67,6 +69,8 @@ describe('createApmEventClient', () => { await server.start(); + expect(abortSignal?.aborted).toBeFalsy(); + const incomingRequest = supertest(innerServer.listener) .get('/') // end required to send request @@ -83,6 +87,6 @@ describe('createApmEventClient', () => { }, 100); }); - expect(abort).toHaveBeenCalled(); + expect(abortSignal?.aborted).toBe(true); }); }); 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 b2b2a0b869c80..26b00b075a5c8 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 @@ -8,7 +8,7 @@ import type { TermsEnumRequest, TermsEnumResponse, -} from '@elastic/elasticsearch/api/types'; +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ValuesType } from 'utility-types'; import { withApmSpan } from '../../../../utils/with_apm_span'; import { Profile } from '../../../../../typings/es_schemas/ui/profile'; @@ -110,9 +110,14 @@ export function createApmEventClient({ return callAsyncWithDebug({ cb: () => { - const searchPromise = withApmSpan(operationName, () => - cancelEsRequestOnAbort(esClient.search(searchParams), request) - ); + const searchPromise = withApmSpan(operationName, () => { + const controller = new AbortController(); + return cancelEsRequestOnAbort( + esClient.search(searchParams, { signal: controller.signal }), + request, + controller + ); + }); return unwrapEsResponse(searchPromise); }, @@ -143,15 +148,20 @@ export function createApmEventClient({ return callAsyncWithDebug({ cb: () => { const { apm, ...rest } = params; - const termsEnumPromise = withApmSpan(operationName, () => - cancelEsRequestOnAbort( - esClient.termsEnum({ - index: Array.isArray(index) ? index.join(',') : index, - ...rest, - }), - request - ) - ); + const termsEnumPromise = withApmSpan(operationName, () => { + const controller = new AbortController(); + return cancelEsRequestOnAbort( + esClient.termsEnum( + { + index: Array.isArray(index) ? index.join(',') : index, + ...rest, + }, + { signal: controller.signal } + ), + request, + controller + ); + }); return unwrapEsResponse(termsEnumPromise); }, 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 34801cdf94750..621f65f74d9f4 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 @@ -5,8 +5,7 @@ * 2.0. */ -import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { unwrapEsResponse } from '../../../../../../observability/server'; import { APMRouteHandlerResources } from '../../../../routes/typings'; import { @@ -39,12 +38,17 @@ export function createInternalESClient({ params, }: { requestType: string; - cb: () => TransportRequestPromise; + cb: (signal: AbortSignal) => Promise; params: Record; } ) { return callAsyncWithDebug({ - cb: () => unwrapEsResponse(cancelEsRequestOnAbort(cb(), request)), + cb: () => { + const controller = new AbortController(); + return unwrapEsResponse( + cancelEsRequestOnAbort(cb(controller.signal), request, controller) + ); + }, getDebugMessage: () => ({ title: getDebugTitle(request), body: getDebugBody({ params, requestType, operationName }), @@ -68,14 +72,14 @@ export function createInternalESClient({ ): Promise> => { return callEs(operationName, { requestType: 'search', - cb: () => asInternalUser.search(params), + cb: (signal) => asInternalUser.search(params, { signal }), params, }); }, index: (operationName: string, params: APMIndexDocumentParams) => { return callEs(operationName, { requestType: 'index', - cb: () => asInternalUser.index(params), + cb: (signal) => asInternalUser.index(params, { signal }), params, }); }, @@ -85,7 +89,7 @@ export function createInternalESClient({ ): Promise<{ result: string }> => { return callEs(operationName, { requestType: 'delete', - cb: () => asInternalUser.delete(params), + cb: (signal) => asInternalUser.delete(params, { signal }), params, }); }, @@ -95,7 +99,7 @@ export function createInternalESClient({ ) => { return callEs(operationName, { requestType: 'indices.create', - cb: () => asInternalUser.indices.create(params), + cb: (signal) => asInternalUser.indices.create(params, { signal }), params, }); }, diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts index 5bd883c6381d3..52e9e5a8ea74a 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts @@ -117,23 +117,28 @@ describe('setupRequest', () => { expect( mockResources.context.core.elasticsearch.client.asCurrentUser.search - ).toHaveBeenCalledWith({ - index: ['apm-*'], - body: { - foo: 'bar', - query: { - bool: { - filter: [ - { terms: { 'processor.event': ['transaction'] } }, - { range: { 'observer.version_major': { gte: 7 } } }, - ], + ).toHaveBeenCalledWith( + { + index: ['apm-*'], + body: { + foo: 'bar', + query: { + bool: { + filter: [ + { terms: { 'processor.event': ['transaction'] } }, + { range: { 'observer.version_major': { gte: 7 } } }, + ], + }, }, }, + ignore_unavailable: true, + ignore_throttled: true, + preference: 'any', }, - ignore_unavailable: true, - ignore_throttled: true, - preference: 'any', - }); + { + signal: expect.any(Object), + } + ); }); it('calls callWithInternalUser', async () => { @@ -145,12 +150,17 @@ describe('setupRequest', () => { } as any); expect( mockResources.context.core.elasticsearch.client.asInternalUser.search - ).toHaveBeenCalledWith({ - index: ['apm-*'], - body: { - foo: 'bar', + ).toHaveBeenCalledWith( + { + index: ['apm-*'], + body: { + foo: 'bar', + }, }, - }); + { + signal: expect.any(Object), + } + ); }); }); diff --git a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap similarity index 95% rename from x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap rename to x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap index 2b629e9849d0d..56d735b5df115 100644 --- a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap @@ -32,7 +32,7 @@ Object { }, }, }, - "terminateAfter": 1, + "terminate_after": 1, } `; @@ -56,7 +56,7 @@ Object { }, }, }, - "terminateAfter": 1, + "terminate_after": 1, } `; @@ -83,7 +83,7 @@ Array [ }, }, }, - "terminateAfter": 1, + "terminate_after": 1, }, ], Array [ @@ -101,7 +101,7 @@ Array [ }, }, }, - "terminateAfter": 1, + "terminate_after": 1, }, ], ] diff --git a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/get_is_using_transaction_events.test.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts similarity index 100% rename from x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/get_is_using_transaction_events.test.ts rename to x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts diff --git a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/get_is_using_transaction_events.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts similarity index 98% rename from x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/get_is_using_transaction_events.ts rename to x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts index 66e9697ab7c91..75be545a7e427 100644 --- a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/get_is_using_transaction_events.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts @@ -83,7 +83,7 @@ async function getHasTransactions({ }, }, }, - terminateAfter: 1, + terminate_after: 1, }); return response.hits.total.value > 0; diff --git a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts similarity index 92% rename from x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts rename to x-pack/plugins/apm/server/lib/helpers/transactions/index.ts index a58a95dd43fcc..473d34cd5b6fc 100644 --- a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts @@ -43,7 +43,7 @@ export async function getHasAggregatedTransactions({ }, }, }, - terminateAfter: 1, + terminate_after: 1, } ); @@ -77,7 +77,7 @@ export async function getSearchAggregatedTransactions({ ); } -export function getTransactionDurationFieldForAggregatedTransactions( +export function getTransactionDurationFieldForTransactions( searchAggregatedTransactions: boolean ) { return searchAggregatedTransactions @@ -85,7 +85,7 @@ export function getTransactionDurationFieldForAggregatedTransactions( : TRANSACTION_DURATION; } -export function getDocumentTypeFilterForAggregatedTransactions( +export function getDocumentTypeFilterForTransactions( searchAggregatedTransactions: boolean ) { return searchAggregatedTransactions @@ -93,7 +93,7 @@ export function getDocumentTypeFilterForAggregatedTransactions( : []; } -export function getProcessorEventForAggregatedTransactions( +export function getProcessorEventForTransactions( searchAggregatedTransactions: boolean ): ProcessorEvent.metric | ProcessorEvent.transaction { return searchAggregatedTransactions diff --git a/x-pack/plugins/apm/server/lib/latency/get_overall_latency_distribution.ts b/x-pack/plugins/apm/server/lib/latency/get_overall_latency_distribution.ts index 787304c3f8dcd..ad1914d921211 100644 --- a/x-pack/plugins/apm/server/lib/latency/get_overall_latency_distribution.ts +++ b/x-pack/plugins/apm/server/lib/latency/get_overall_latency_distribution.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ProcessorEvent } from '../../../common/processor_event'; diff --git a/x-pack/plugins/apm/server/lib/latency/get_percentile_threshold_value.ts b/x-pack/plugins/apm/server/lib/latency/get_percentile_threshold_value.ts index 0d417a370e0b6..996e039841b88 100644 --- a/x-pack/plugins/apm/server/lib/latency/get_percentile_threshold_value.ts +++ b/x-pack/plugins/apm/server/lib/latency/get_percentile_threshold_value.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ProcessorEvent } from '../../../common/processor_event'; diff --git a/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts b/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts index a181b1a41fbc7..3eb11f668115d 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts @@ -9,7 +9,7 @@ import { ProcessorEvent } from '../../../common/processor_event'; import { rangeQuery } from '../../../../observability/server'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { Setup } from '../helpers/setup_request'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; export async function getServiceCount({ setup, @@ -27,9 +27,7 @@ export async function getServiceCount({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts b/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts index 8c64670f5d2e9..829afa8330164 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts @@ -13,9 +13,9 @@ import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; import { rangeQuery } from '../../../../observability/server'; import { Setup } from '../helpers/setup_request'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { calculateThroughputWithInterval, calculateThroughputWithRange, @@ -43,9 +43,7 @@ export async function getTransactionsPerMinute({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -54,7 +52,7 @@ export async function getTransactionsPerMinute({ bool: { filter: [ ...rangeQuery(start, end), - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ], diff --git a/x-pack/plugins/apm/server/lib/observability_overview/has_data.ts b/x-pack/plugins/apm/server/lib/observability_overview/has_data.ts index 3b6993695f3de..f09b67ec98dfb 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/has_data.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/has_data.ts @@ -19,7 +19,7 @@ export async function getHasData({ setup }: { setup: Setup }) { ProcessorEvent.metric, ], }, - terminateAfter: 1, + terminate_after: 1, body: { size: 0, }, diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_boolean_field_stats.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_boolean_field_stats.ts index 551ecfe3cd4ea..da5493376426c 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_boolean_field_stats.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_boolean_field_stats.ts @@ -6,8 +6,8 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { SearchRequest } from '@elastic/elasticsearch/api/types'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + import { buildSamplerAggregation } from '../../utils/field_stats_utils'; import { FieldValuePair } from '../../../../../common/search_strategies/types'; import { @@ -22,7 +22,7 @@ export const getBooleanFieldStatsRequest = ( params: FieldStatsCommonRequestParams, fieldName: string, termFilters?: FieldValuePair[] -): SearchRequest => { +): estypes.SearchRequest => { const query = getQueryWithParams({ params, termFilters }); const { index, samplerShardSize } = params; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_field_stats.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_field_stats.test.ts index d3cee1c4ca596..2775d755c9907 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_field_stats.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_field_stats.test.ts @@ -9,7 +9,7 @@ import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values import { getNumericFieldStatsRequest } from './get_numeric_field_stats'; import { getKeywordFieldStatsRequest } from './get_keyword_field_stats'; import { getBooleanFieldStatsRequest } from './get_boolean_field_stats'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from 'kibana/server'; import { fetchFieldsStats } from './get_fields_stats'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_keyword_field_stats.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_keyword_field_stats.ts index b15449657cba5..a9c727457d0ae 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_keyword_field_stats.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_keyword_field_stats.ts @@ -6,8 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { SearchRequest } from '@elastic/elasticsearch/api/types'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FieldValuePair } from '../../../../../common/search_strategies/types'; import { getQueryWithParams } from '../get_query_with_params'; import { buildSamplerAggregation } from '../../utils/field_stats_utils'; @@ -22,7 +21,7 @@ export const getKeywordFieldStatsRequest = ( params: FieldStatsCommonRequestParams, fieldName: string, termFilters?: FieldValuePair[] -): SearchRequest => { +): estypes.SearchRequest => { const query = getQueryWithParams({ params, termFilters }); const { index, samplerShardSize } = params; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_numeric_field_stats.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_numeric_field_stats.ts index bab4a1af29b65..c45d4356cfe23 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_numeric_field_stats.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/field_stats/get_numeric_field_stats.ts @@ -6,9 +6,8 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { SearchRequest } from '@elastic/elasticsearch/api/types'; import { find, get } from 'lodash'; -import { estypes } from '@elastic/elasticsearch/index'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { NumericFieldStats, FieldStatsCommonRequestParams, @@ -80,7 +79,7 @@ export const fetchNumericFieldStats = async ( field: FieldValuePair, termFilters?: FieldValuePair[] ): Promise => { - const request: SearchRequest = getNumericFieldStatsRequest( + const request: estypes.SearchRequest = getNumericFieldStatsRequest( params, field.fieldName, termFilters diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/get_query_with_params.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/get_query_with_params.ts index 31a98b0a6bb18..297fd68a7503f 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/get_query_with_params.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/get_query_with_params.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { FieldValuePair, SearchStrategyParams, diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.test.ts index 40fcc17444492..6cbf97a163871 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.ts index 24db25f8afd89..a150d23b27113 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_correlation.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_failure_correlation.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_failure_correlation.ts index 64249a0f3547e..10a098c4a3ffc 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_failure_correlation.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_failure_correlation.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from 'kibana/server'; import { SearchStrategyParams } from '../../../../common/search_strategies/types'; import { EVENT_OUTCOME } from '../../../../common/elasticsearch_fieldnames'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.test.ts index bae42666e6db0..311016a1b0834 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.ts index 390243295c4f0..292be1b5817aa 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_candidates.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.test.ts index ab7a0b4e02072..bb3aa40b328af 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.ts index 296abfd2d8653..39d6aea2f38bd 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_field_value_pairs.ts @@ -7,7 +7,7 @@ import type { ElasticsearchClient } from 'src/core/server'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { FieldValuePair, diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.test.ts index 9c704ef7b489a..5c18b21fc029c 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.ts index ccea480052c9b..555465466498a 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_fractions.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SearchStrategyParams } from '../../../../common/search_strategies/types'; import { TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.test.ts index 7cc6106f671a7..3c5726ee586da 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.ts index 5fb7ef76fc728..4e40834acccd1 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.test.ts index 41a2fa9a5039e..3a79b4375e4a5 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.ts index 439bb9e4b9cd6..176e7befda53b 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_range_steps.ts @@ -7,7 +7,7 @@ import { scaleLog } from 'd3-scale'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.test.ts index 00e8c26497eb2..27fd0dc31432d 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.ts index d526c63c7de34..500714ffdf0d5 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histograms_generator.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.test.ts index 57e3e6cadb9bc..67b2f580e3f4d 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.ts index 70b5b70ce8912..4e1a7b2015614 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_percentiles.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.test.ts index 7d67e80ae3398..3cafc17e2681b 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.ts index a530c997876c4..8b359c3665eaf 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_ranges.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts index 034bd2a60ad19..ccccdeab5132d 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SearchStrategyDependencies } from 'src/plugins/data/server'; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/utils/compute_expectations_and_ranges.ts b/x-pack/plugins/apm/server/lib/search_strategies/utils/compute_expectations_and_ranges.ts index 9ab9689fd6d30..1754a35280f86 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/utils/compute_expectations_and_ranges.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/utils/compute_expectations_and_ranges.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { PERCENTILES_STEP } from '../constants'; export const computeExpectationsAndRanges = ( diff --git a/x-pack/plugins/apm/server/lib/search_strategies/utils/field_stats_utils.ts b/x-pack/plugins/apm/server/lib/search_strategies/utils/field_stats_utils.ts index 2eb67ec501bab..7f98f771c50e2 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/utils/field_stats_utils.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/utils/field_stats_utils.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + /* * Contains utility functions for building and processing queries. */ 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 9b2d79dc726ee..2ed1966dcacbd 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 @@ -7,7 +7,7 @@ import Boom from '@hapi/boom'; import { sortBy, uniqBy } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ESSearchResponse } from '../../../../../../src/core/types/elasticsearch'; import { MlPluginSetup } from '../../../../ml/server'; import { PromiseReturnType } from '../../../../observability/typings/common'; 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 78ca3fad63189..43147684ef3f7 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 @@ -23,10 +23,10 @@ import { rangeQuery } from '../../../../observability/server'; import { environmentQuery } from '../../../common/utils/environment_query'; import { withApmSpan } from '../../utils/with_apm_span'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; import { percentCgroupMemoryUsedScript, @@ -131,11 +131,7 @@ async function getTransactionStats({ const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, @@ -143,7 +139,7 @@ async function getTransactionStats({ bool: { filter: [ ...filter, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), { @@ -161,7 +157,7 @@ async function getTransactionStats({ aggs: { duration: { avg: { - field: getTransactionDurationFieldForAggregatedTransactions( + field: getTransactionDurationFieldForTransactions( searchAggregatedTransactions ), }, diff --git a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap index 99891807e689b..d6d6219440dad 100644 --- a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap @@ -12,7 +12,7 @@ Object { "body": Object { "size": 0, }, - "terminateAfter": 1, + "terminate_after": 1, } `; @@ -49,7 +49,7 @@ Object { }, "size": 0, }, - "terminateAfter": 1, + "terminate_after": 1, } `; @@ -99,7 +99,7 @@ Object { }, "size": 1, }, - "terminateAfter": 1, + "terminate_after": 1, } `; 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 3af9b557dd127..22b37e33a26e2 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 @@ -15,9 +15,9 @@ import { import { rangeQuery } from '../../../../../observability/server'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { Setup } from '../../helpers/setup_request'; export async function getDerivedServiceAnnotations({ @@ -39,9 +39,7 @@ export async function getDerivedServiceAnnotations({ const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...environmentQuery(environment), ]; @@ -50,9 +48,7 @@ export async function getDerivedServiceAnnotations({ await apmEventClient.search('get_derived_service_annotations', { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -83,9 +79,7 @@ export async function getDerivedServiceAnnotations({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { 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 d44468bb0bb60..ac1c2653bf148 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,7 +5,7 @@ * 2.0. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { ElasticsearchClient, Logger } from 'kibana/server'; import { rangeQuery } from '../../../../../observability/server'; import { environmentQuery } from '../../../../common/utils/environment_query'; @@ -75,7 +75,7 @@ export function getStoredAnnotations({ // so we should handle this error gracefully if ( error instanceof WrappedElasticsearchClientError && - error.originalError instanceof ResponseError + error.originalError instanceof errors.ResponseError ) { const type = error.originalError.body.error.type; diff --git a/x-pack/plugins/apm/server/lib/services/get_service_agent.ts b/x-pack/plugins/apm/server/lib/services/get_service_agent.ts index a9bb3c8f3103f..4c9ff9f124b10 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_agent.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_agent.ts @@ -13,7 +13,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { rangeQuery } from '../../../../observability/server'; import { Setup } from '../helpers/setup_request'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; interface ServiceAgent { agent?: { @@ -42,13 +42,11 @@ export async function getServiceAgent({ const { apmEventClient } = setup; const params = { - terminateAfter: 1, + terminate_after: 1, apm: { events: [ ProcessorEvent.error, - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.metric, ], }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts index ba122ea5ad0e6..d349ca3ce0399 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts @@ -15,9 +15,9 @@ import { rangeQuery } from '../../../../observability/server'; import { Setup } from '../helpers/setup_request'; import { maybe } from '../../../common/utils/maybe'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; export async function getServiceInstanceMetadataDetails({ serviceName, @@ -84,16 +84,14 @@ export async function getServiceInstanceMetadataDetails({ 'get_service_instance_metadata_details_application_transaction_metric', { apm: { - events: [getProcessorEventForAggregatedTransactions(true)], + events: [getProcessorEventForTransactions(true)], }, body: { terminate_after: 1, size: 1, query: { bool: { - filter: filter.concat( - getDocumentTypeFilterForAggregatedTransactions(true) - ), + filter: filter.concat(getDocumentTypeFilterForTransactions(true)), }, }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instances_transaction_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instances_transaction_statistics.ts index ec76e0d35e5c0..b0f64036a1845 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instances_transaction_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instances_transaction_statistics.ts @@ -17,10 +17,10 @@ import { Coordinate } from '../../../../typings/timeseries'; import { kqlQuery, rangeQuery } from '../../../../../observability/server'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { calculateThroughput } from '../../helpers/calculate_throughput'; import { getBucketSizeForAggregatedTransactions } from '../../helpers/get_bucket_size_for_aggregated_transactions'; import { @@ -89,7 +89,7 @@ export async function getServiceInstancesTransactionStatistics< } ); - const field = getTransactionDurationFieldForAggregatedTransactions( + const field = getTransactionDurationFieldForTransactions( searchAggregatedTransactions ); @@ -109,15 +109,11 @@ export async function getServiceInstancesTransactionStatistics< filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...rangeQuery(start, end), ...environmentQuery(environment), ...kqlQuery(kuery), - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...(isComparisonSearch && serviceNodeIds ? [{ terms: { [SERVICE_NODE_NAME]: serviceNodeIds } }] : []), @@ -154,9 +150,7 @@ export async function getServiceInstancesTransactionStatistics< { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { size: 0, query, aggs }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts index 7a39e953ad496..e2852a51b0c06 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts @@ -22,7 +22,7 @@ import { import { ContainerType } from '../../../common/service_metadata'; import { rangeQuery } from '../../../../observability/server'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; import { should } from './get_service_metadata_icons'; @@ -81,9 +81,7 @@ export async function getServiceMetadataDetails({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts index 26a3090946ff8..2c93a298cb134 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts @@ -18,7 +18,7 @@ import { import { ContainerType } from '../../../common/service_metadata'; import { rangeQuery } from '../../../../observability/server'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; type ServiceMetadataIconsRaw = Pick< @@ -63,9 +63,7 @@ export async function getServiceMetadataIcons({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts index feab6d78f02c8..35256e6a7ecd6 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts @@ -19,10 +19,10 @@ import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { environmentQuery } from '../../../common/utils/environment_query'; import { Coordinate } from '../../../typings/timeseries'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { getBucketSizeForAggregatedTransactions } from '../helpers/get_bucket_size_for_aggregated_transactions'; import { getLatencyAggregation, @@ -72,7 +72,7 @@ export async function getServiceTransactionGroupDetailedStatistics({ searchAggregatedTransactions, }); - const field = getTransactionDurationFieldForAggregatedTransactions( + const field = getTransactionDurationFieldForTransactions( searchAggregatedTransactions ); @@ -81,9 +81,7 @@ export async function getServiceTransactionGroupDetailedStatistics({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -93,7 +91,7 @@ export async function getServiceTransactionGroupDetailedStatistics({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts index fbc1e2880495b..7f624693a3b9c 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts @@ -16,10 +16,10 @@ import { LatencyAggregationType } from '../../../common/latency_aggregation_type import { rangeQuery, kqlQuery } from '../../../../observability/server'; import { environmentQuery } from '../../../common/utils/environment_query'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { calculateThroughput } from '../helpers/calculate_throughput'; import { getLatencyAggregation, @@ -59,7 +59,7 @@ export async function getServiceTransactionGroups({ const { apmEventClient, config } = setup; const bucketSize = config.ui.transactionGroupBucketSize; - const field = getTransactionDurationFieldForAggregatedTransactions( + const field = getTransactionDurationFieldForTransactions( searchAggregatedTransactions ); @@ -68,9 +68,7 @@ export async function getServiceTransactionGroups({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -80,7 +78,7 @@ export async function getServiceTransactionGroups({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts index 9e3d39e7f2801..1c2d1c9207bc3 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts @@ -12,9 +12,9 @@ import { import { rangeQuery } from '../../../../observability/server'; import { Setup } from '../helpers/setup_request'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; export async function getServiceTransactionTypes({ setup, @@ -33,18 +33,14 @@ export async function getServiceTransactionTypes({ const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, query: { bool: { filter: [ - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), { term: { [SERVICE_NAME]: serviceName } }, diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_legacy_data_status.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_legacy_data_status.ts index cf80222dc8303..5b94bb2314258 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_legacy_data_status.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_legacy_data_status.ts @@ -19,7 +19,7 @@ export async function getLegacyDataStatus( const { apmEventClient } = setup; const params = { - terminateAfter: 1, + terminate_after: 1, apm: { events: [ProcessorEvent.transaction], includeLegacyData: true, diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts index 24d2640024d28..36903f9ca229f 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts @@ -19,10 +19,10 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { calculateThroughput } from '../../helpers/calculate_throughput'; import { calculateFailedTransactionRate, @@ -56,7 +56,7 @@ export async function getServiceTransactionStats({ const metrics = { avg_duration: { avg: { - field: getTransactionDurationFieldForAggregatedTransactions( + field: getTransactionDurationFieldForTransactions( searchAggregatedTransactions ), }, @@ -69,9 +69,7 @@ export async function getServiceTransactionStats({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -79,7 +77,7 @@ export async function getServiceTransactionStats({ query: { bool: { filter: [ - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/lib/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts index 14a37600bb4c3..686555e7764ab 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts @@ -18,10 +18,10 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../../helpers/transactions'; import { calculateThroughput } from '../../helpers/calculate_throughput'; import { getBucketSizeForAggregatedTransactions } from '../../helpers/get_bucket_size_for_aggregated_transactions'; import { Setup } from '../../helpers/setup_request'; @@ -61,7 +61,7 @@ export async function getServiceTransactionDetailedStatistics({ const metrics = { avg_duration: { avg: { - field: getTransactionDurationFieldForAggregatedTransactions( + field: getTransactionDurationFieldForTransactions( searchAggregatedTransactions ), }, @@ -74,9 +74,7 @@ export async function getServiceTransactionDetailedStatistics({ { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ], }, body: { @@ -84,7 +82,7 @@ export async function getServiceTransactionDetailedStatistics({ query: { bool: { filter: [ - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ...rangeQuery(startWithOffset, endWithOffset), diff --git a/x-pack/plugins/apm/server/lib/services/get_throughput.ts b/x-pack/plugins/apm/server/lib/services/get_throughput.ts index 669203ad198b9..e31e9dd3b8c9f 100644 --- a/x-pack/plugins/apm/server/lib/services/get_throughput.ts +++ b/x-pack/plugins/apm/server/lib/services/get_throughput.ts @@ -14,9 +14,9 @@ import { import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { environmentQuery } from '../../../common/utils/environment_query'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; import { calculateThroughputWithInterval } from '../helpers/calculate_throughput'; @@ -52,9 +52,7 @@ export async function getThroughput({ const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...rangeQuery(start, end), ...environmentQuery(environment), ...kqlQuery(kuery), @@ -70,11 +68,7 @@ export async function getThroughput({ const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts index f43938891f1f0..a14019f4dbdec 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts @@ -36,7 +36,6 @@ const mappings: Mappings = { dynamic_templates: [ { // force string to keyword (instead of default of text + keyword) - // @ts-expect-error @elastic/elasticsearch expects here mapping: MappingPropertyBase strings: { match_mapping_type: 'string', mapping: { diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts index 0b6dd10b42e25..6ea3e2a578050 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts @@ -20,7 +20,7 @@ export async function getAgentNameByService({ const { apmEventClient } = setup; const params = { - terminateAfter: 1, + terminate_after: 1, apm: { events: [ ProcessorEvent.transaction, diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts index 282eacbec66d1..06bd900872a20 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts @@ -10,7 +10,7 @@ import { Setup } from '../../helpers/setup_request'; import { PromiseReturnType } from '../../../../../observability/typings/common'; import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { ALL_OPTION_VALUE } from '../../../../common/agent_configuration/all_option'; -import { getProcessorEventForAggregatedTransactions } from '../../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../../helpers/transactions'; export type AgentConfigurationServicesAPIResponse = PromiseReturnType< typeof getServiceNames @@ -30,9 +30,7 @@ export async function getServiceNames({ const params = { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/__snapshots__/get_transaction.test.ts.snap b/x-pack/plugins/apm/server/lib/settings/custom_link/__snapshots__/get_transaction.test.ts.snap index 0649c8c38d29a..921129cf2c1da 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/__snapshots__/get_transaction.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/__snapshots__/get_transaction.test.ts.snap @@ -44,7 +44,7 @@ Object { }, }, "size": 1, - "terminateAfter": 1, + "terminate_after": 1, } `; @@ -63,6 +63,6 @@ Object { }, }, "size": 1, - "terminateAfter": 1, + "terminate_after": 1, } `; diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/create_custom_link_index.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/create_custom_link_index.ts index 085bb2b4be40d..752a7769caea0 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/create_custom_link_index.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/create_custom_link_index.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient, Logger } from 'src/core/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createOrUpdateIndex, Mappings, diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.ts index 91bc8c85bc014..1c3d1465527ba 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.ts @@ -32,7 +32,7 @@ export async function getTransaction({ ); const params = { - terminateAfter: 1, + terminate_after: 1, apm: { events: [ProcessorEvent.transaction as const], }, diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.ts index d477da85e0d9b..633545e16acfd 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { CustomLink, CustomLinkES, diff --git a/x-pack/plugins/apm/server/lib/suggestions/get_suggestions.ts b/x-pack/plugins/apm/server/lib/suggestions/get_suggestions.ts index acd44366ef4c3..5ea28debc4437 100644 --- a/x-pack/plugins/apm/server/lib/suggestions/get_suggestions.ts +++ b/x-pack/plugins/apm/server/lib/suggestions/get_suggestions.ts @@ -6,7 +6,7 @@ */ import { ProcessorEvent } from '../../../common/processor_event'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; export async function getSuggestions({ @@ -27,9 +27,7 @@ export async function getSuggestions({ const response = await apmEventClient.termsEnum('get_suggestions', { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.error, ProcessorEvent.metric, ], diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts index 60a28fd9abdbd..55204786b8e67 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ProcessorEvent } from '../../../common/processor_event'; import { TRACE_ID, 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 dc7cc0f804469..200d3d6ac7459 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { sortBy } from 'lodash'; import moment from 'moment'; import { Unionize } from 'utility-types'; @@ -22,9 +22,9 @@ import { environmentQuery } from '../../../common/utils/environment_query'; import { joinByKey } from '../../../common/utils/join_by_key'; import { withApmSpan } from '../../utils/with_apm_span'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { Setup } from '../helpers/setup_request'; import { getAverages, getCounts, getSums } from './get_transaction_group_stats'; @@ -75,11 +75,7 @@ function getRequest(topTraceOptions: TopTraceOptions) { return { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, @@ -87,7 +83,7 @@ function getRequest(topTraceOptions: TopTraceOptions) { bool: { filter: [ ...transactionNameFilter, - ...getDocumentTypeFilterForAggregatedTransactions( + ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts index d57b0400abed9..e85bd61ac440a 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts @@ -17,9 +17,9 @@ import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { environmentQuery } from '../../../common/utils/environment_query'; import { Coordinate } from '../../../typings/timeseries'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, -} from '../helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getProcessorEventForTransactions, +} from '../helpers/transactions'; import { getBucketSizeForAggregatedTransactions } from '../helpers/get_bucket_size_for_aggregated_transactions'; import { Setup } from '../helpers/setup_request'; import { @@ -71,9 +71,7 @@ export async function getErrorRate({ }, ...transactionNamefilter, ...transactionTypefilter, - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...rangeQuery(start, end), ...environmentQuery(environment), ...kqlQuery(kuery), @@ -83,11 +81,7 @@ export async function getErrorRate({ const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, 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 980d8f10610c8..c79dde721d138 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,11 +6,11 @@ */ import { merge } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; import { arrayUnionToCallable } from '../../../common/utils/array_union_to_callable'; import { TransactionGroupRequestBase, TransactionGroupSetup } from './fetcher'; -import { getTransactionDurationFieldForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { getTransactionDurationFieldForTransactions } from '../helpers/transactions'; interface MetricParams { request: TransactionGroupRequestBase; @@ -46,7 +46,7 @@ export async function getAverages({ const params = mergeRequestWithAggs(request, { avg: { avg: { - field: getTransactionDurationFieldForAggregatedTransactions( + field: getTransactionDurationFieldForTransactions( searchAggregatedTransactions ), }, @@ -110,7 +110,7 @@ export async function getSums({ const params = mergeRequestWithAggs(request, { sum: { sum: { - field: getTransactionDurationFieldForAggregatedTransactions( + field: getTransactionDurationFieldForTransactions( searchAggregatedTransactions ), }, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts index a61e0614f5b1a..2fcbf5842d746 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ESSearchResponse } from '../../../../../../../src/core/types/elasticsearch'; import { PromiseReturnType } from '../../../../../observability/typings/common'; import { rangeQuery } from '../../../../../observability/server'; diff --git a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts index 01e2d905bbf21..c4bae841764cf 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts @@ -17,10 +17,10 @@ import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset import { kqlQuery, rangeQuery } from '../../../../../observability/server'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { - getDocumentTypeFilterForAggregatedTransactions, - getProcessorEventForAggregatedTransactions, - getTransactionDurationFieldForAggregatedTransactions, -} from '../../../lib/helpers/aggregated_transactions'; + getDocumentTypeFilterForTransactions, + getTransactionDurationFieldForTransactions, + getProcessorEventForTransactions, +} from '../../../lib/helpers/transactions'; import { Setup } from '../../../lib/helpers/setup_request'; import { getBucketSizeForAggregatedTransactions } from '../../helpers/get_bucket_size_for_aggregated_transactions'; import { @@ -63,9 +63,7 @@ function searchLatency({ const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, - ...getDocumentTypeFilterForAggregatedTransactions( - searchAggregatedTransactions - ), + ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ...rangeQuery(start, end), ...environmentQuery(environment), ...kqlQuery(kuery), @@ -79,18 +77,13 @@ function searchLatency({ filter.push({ term: { [TRANSACTION_TYPE]: transactionType } }); } - const transactionDurationField = - getTransactionDurationFieldForAggregatedTransactions( - searchAggregatedTransactions - ); + const transactionDurationField = getTransactionDurationFieldForTransactions( + searchAggregatedTransactions + ); const params = { apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], + events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { size: 0, diff --git a/x-pack/plugins/apm/server/lib/transactions/trace_samples/get_trace_samples/index.ts b/x-pack/plugins/apm/server/lib/transactions/trace_samples/get_trace_samples/index.ts index 79eebf0813e36..b085c0fc4a839 100644 --- a/x-pack/plugins/apm/server/lib/transactions/trace_samples/get_trace_samples/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/trace_samples/get_trace_samples/index.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { withApmSpan } from '../../../../utils/with_apm_span'; import { SERVICE_NAME, diff --git a/x-pack/plugins/apm/server/projections/metrics.ts b/x-pack/plugins/apm/server/projections/metrics.ts index ce5a506752b65..417281f2de487 100644 --- a/x-pack/plugins/apm/server/projections/metrics.ts +++ b/x-pack/plugins/apm/server/projections/metrics.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SERVICE_NAME, SERVICE_NODE_NAME, diff --git a/x-pack/plugins/apm/server/projections/services.ts b/x-pack/plugins/apm/server/projections/services.ts index afa6f4ba752f0..139c86acd5144 100644 --- a/x-pack/plugins/apm/server/projections/services.ts +++ b/x-pack/plugins/apm/server/projections/services.ts @@ -9,7 +9,7 @@ import { Setup } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME } from '../../common/elasticsearch_fieldnames'; import { rangeQuery, kqlQuery } from '../../../observability/server'; import { ProcessorEvent } from '../../common/processor_event'; -import { getProcessorEventForAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getProcessorEventForTransactions } from '../lib/helpers/transactions'; export function getServicesProjection({ kuery, @@ -27,9 +27,7 @@ export function getServicesProjection({ return { apm: { events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), + getProcessorEventForTransactions(searchAggregatedTransactions), ProcessorEvent.metric as const, ProcessorEvent.error as const, ], diff --git a/x-pack/plugins/apm/server/projections/typings.ts b/x-pack/plugins/apm/server/projections/typings.ts index 0843fa4c9dd64..d252fd311b4fe 100644 --- a/x-pack/plugins/apm/server/projections/typings.ts +++ b/x-pack/plugins/apm/server/projections/typings.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AggregationOptionsByType } from '../../../../../src/core/types/elasticsearch'; import { APMEventESSearchRequest } from '../lib/helpers/create_es_client/create_apm_event_client'; diff --git a/x-pack/plugins/apm/server/routes/backends.ts b/x-pack/plugins/apm/server/routes/backends.ts index feb4ca8bb978c..03466c7443665 100644 --- a/x-pack/plugins/apm/server/routes/backends.ts +++ b/x-pack/plugins/apm/server/routes/backends.ts @@ -65,13 +65,14 @@ const topBackendsRoute = createApmServerRoute({ }); const upstreamServicesForBackendRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/backends/{backendName}/upstream_services', + endpoint: 'GET /internal/apm/backends/upstream_services', params: t.intersection([ t.type({ - path: t.type({ - backendName: t.string, - }), - query: t.intersection([rangeRt, t.type({ numBuckets: toNumberRt })]), + query: t.intersection([ + t.type({ backendName: t.string }), + rangeRt, + t.type({ numBuckets: toNumberRt }), + ]), }), t.partial({ query: t.intersection([environmentRt, offsetRt, kueryRt]), @@ -83,8 +84,15 @@ const upstreamServicesForBackendRoute = createApmServerRoute({ handler: async (resources) => { const setup = await setupRequest(resources); const { - path: { backendName }, - query: { environment, offset, numBuckets, kuery, start, end }, + query: { + backendName, + environment, + offset, + numBuckets, + kuery, + start, + end, + }, } = resources.params; const opts = { @@ -121,12 +129,9 @@ const upstreamServicesForBackendRoute = createApmServerRoute({ }); const backendMetadataRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/backends/{backendName}/metadata', + endpoint: 'GET /internal/apm/backends/metadata', params: t.type({ - path: t.type({ - backendName: t.string, - }), - query: rangeRt, + query: t.intersection([t.type({ backendName: t.string }), rangeRt]), }), options: { tags: ['access:apm'], @@ -134,9 +139,8 @@ const backendMetadataRoute = createApmServerRoute({ handler: async (resources) => { const setup = await setupRequest(resources); const { params } = resources; - const { backendName } = params.path; - const { start, end } = params.query; + const { backendName, start, end } = params.query; const metadata = await getMetadataForBackend({ backendName, @@ -150,12 +154,15 @@ const backendMetadataRoute = createApmServerRoute({ }); const backendLatencyChartsRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/latency', + endpoint: 'GET /internal/apm/backends/charts/latency', params: t.type({ - path: t.type({ - backendName: t.string, - }), - query: t.intersection([rangeRt, kueryRt, environmentRt, offsetRt]), + query: t.intersection([ + t.type({ backendName: t.string }), + rangeRt, + kueryRt, + environmentRt, + offsetRt, + ]), }), options: { tags: ['access:apm'], @@ -163,8 +170,8 @@ const backendLatencyChartsRoute = createApmServerRoute({ handler: async (resources) => { const setup = await setupRequest(resources); const { params } = resources; - const { backendName } = params.path; - const { kuery, environment, offset, start, end } = params.query; + const { backendName, kuery, environment, offset, start, end } = + params.query; const [currentTimeseries, comparisonTimeseries] = await Promise.all([ getLatencyChartsForBackend({ @@ -193,12 +200,15 @@ const backendLatencyChartsRoute = createApmServerRoute({ }); const backendThroughputChartsRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/throughput', + endpoint: 'GET /internal/apm/backends/charts/throughput', params: t.type({ - path: t.type({ - backendName: t.string, - }), - query: t.intersection([rangeRt, kueryRt, environmentRt, offsetRt]), + query: t.intersection([ + t.type({ backendName: t.string }), + rangeRt, + kueryRt, + environmentRt, + offsetRt, + ]), }), options: { tags: ['access:apm'], @@ -206,8 +216,8 @@ const backendThroughputChartsRoute = createApmServerRoute({ handler: async (resources) => { const setup = await setupRequest(resources); const { params } = resources; - const { backendName } = params.path; - const { kuery, environment, offset, start, end } = params.query; + const { backendName, kuery, environment, offset, start, end } = + params.query; const [currentTimeseries, comparisonTimeseries] = await Promise.all([ getThroughputChartsForBackend({ @@ -236,12 +246,15 @@ const backendThroughputChartsRoute = createApmServerRoute({ }); const backendFailedTransactionRateChartsRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/backends/{backendName}/charts/error_rate', + endpoint: 'GET /internal/apm/backends/charts/error_rate', params: t.type({ - path: t.type({ - backendName: t.string, - }), - query: t.intersection([rangeRt, kueryRt, environmentRt, offsetRt]), + query: t.intersection([ + t.type({ backendName: t.string }), + rangeRt, + kueryRt, + environmentRt, + offsetRt, + ]), }), options: { tags: ['access:apm'], @@ -249,8 +262,8 @@ const backendFailedTransactionRateChartsRoute = createApmServerRoute({ handler: async (resources) => { const setup = await setupRequest(resources); const { params } = resources; - const { backendName } = params.path; - const { kuery, environment, offset, start, end } = params.query; + const { backendName, kuery, environment, offset, start, end } = + params.query; const [currentTimeseries, comparisonTimeseries] = await Promise.all([ getErrorRateChartsForBackend({ diff --git a/x-pack/plugins/apm/server/routes/environments.ts b/x-pack/plugins/apm/server/routes/environments.ts index 59e75f6f9c341..e54ad79f177c4 100644 --- a/x-pack/plugins/apm/server/routes/environments.ts +++ b/x-pack/plugins/apm/server/routes/environments.ts @@ -7,7 +7,7 @@ import * as t from 'io-ts'; import { maxSuggestions } from '../../../observability/common'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getEnvironments } from '../lib/environments/get_environments'; import { rangeRt } from './default_api_types'; diff --git a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts index ba74cc0b7a88a..99c6a290e34b1 100644 --- a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts +++ b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { getIsUsingTransactionEvents } from '../lib/helpers/aggregated_transactions/get_is_using_transaction_events'; +import { getIsUsingTransactionEvents } from '../lib/helpers/transactions/get_is_using_transaction_events'; import { setupRequest } from '../lib/helpers/setup_request'; import { createApmServerRoute } from './create_apm_server_route'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; diff --git a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts index 13591b47a8584..54960c3e48b60 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts @@ -13,7 +13,7 @@ export async function hasHistoricalAgentData(setup: Setup) { const { apmEventClient } = setup; const params = { - terminateAfter: 1, + terminate_after: 1, apm: { events: [ ProcessorEvent.error, diff --git a/x-pack/plugins/apm/server/routes/observability_overview.ts b/x-pack/plugins/apm/server/routes/observability_overview.ts index 0dbebd061e8be..2aff798f9ad0b 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview.ts @@ -12,7 +12,7 @@ import { getServiceCount } from '../lib/observability_overview/get_service_count import { getTransactionsPerMinute } from '../lib/observability_overview/get_transactions_per_minute'; import { getHasData } from '../lib/observability_overview/has_data'; import { rangeRt } from './default_api_types'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { withApmSpan } from '../utils/with_apm_span'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; import { createApmServerRoute } from './create_apm_server_route'; diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.ts b/x-pack/plugins/apm/server/routes/register_routes/index.ts index d3587f1fcbe4b..576c23dc0882f 100644 --- a/x-pack/plugins/apm/server/routes/register_routes/index.ts +++ b/x-pack/plugins/apm/server/routes/register_routes/index.ts @@ -8,7 +8,7 @@ import Boom from '@hapi/boom'; import * as t from 'io-ts'; import { KibanaRequest, RouteRegistrar } from 'src/core/server'; -import { RequestAbortedError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import agent from 'elastic-apm-node'; import { ServerRouteRepository } from '@kbn/server-route-repository'; import { merge } from 'lodash'; @@ -170,7 +170,7 @@ export function registerRoutes({ }, }; - if (error instanceof RequestAbortedError) { + if (error instanceof errors.RequestAbortedError) { return response.custom(merge(opts, CLIENT_CLOSED_REQUEST)); } diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 17fb9d7c98c5f..3711ee20d814b 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -10,7 +10,7 @@ import * as t from 'io-ts'; import { isActivePlatinumLicense } from '../../common/license_check'; import { invalidLicenseMessage } from '../../common/service_map'; import { notifyFeatureUsage } from '../feature'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceMap } from '../lib/service_map/get_service_map'; import { getServiceMapBackendNodeInfo } from '../lib/service_map/get_service_map_backend_node_info'; @@ -114,12 +114,13 @@ const serviceMapServiceNodeRoute = createApmServerRoute({ }); const serviceMapBackendNodeRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/service-map/backend/{backendName}', + endpoint: 'GET /internal/apm/service-map/backend', params: t.type({ - path: t.type({ - backendName: t.string, - }), - query: t.intersection([environmentRt, rangeRt]), + query: t.intersection([ + t.type({ backendName: t.string }), + environmentRt, + rangeRt, + ]), }), options: { tags: ['access:apm'] }, handler: async (resources) => { @@ -134,8 +135,7 @@ const serviceMapBackendNodeRoute = createApmServerRoute({ const setup = await setupRequest(resources); const { - path: { backendName }, - query: { environment, start, end }, + query: { backendName, environment, start, end }, } = params; return getServiceMapBackendNodeInfo({ diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index f1f29dc2f036c..257aec216eb06 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -11,7 +11,7 @@ import * as t from 'io-ts'; import { uniq } from 'lodash'; import { latencyAggregationTypeRt } from '../../common/latency_aggregation_types'; import { ProfilingValueType } from '../../common/profiling'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceAnnotations } from '../lib/services/annotations'; import { getServices } from '../lib/services/get_services'; diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts index a904e5e03b531..0488d0ebd01bd 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts @@ -24,7 +24,7 @@ import { serviceRt, agentConfigurationIntakeRt, } from '../../../common/agent_configuration/runtime_types/agent_configuration_intake_rt'; -import { getSearchAggregatedTransactions } from '../../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../../lib/helpers/transactions'; import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; import { syncAgentConfigsToApmPackagePolicies } from '../../lib/fleet/sync_agent_configs_to_apm_package_policies'; diff --git a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts index 78db4e0c14b36..f614f35810c57 100644 --- a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts +++ b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts @@ -16,7 +16,7 @@ import { createAnomalyDetectionJobs } from '../../lib/anomaly_detection/create_a import { setupRequest } from '../../lib/helpers/setup_request'; import { getAllEnvironments } from '../../lib/environments/get_all_environments'; import { hasLegacyJobs } from '../../lib/anomaly_detection/has_legacy_jobs'; -import { getSearchAggregatedTransactions } from '../../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../../lib/helpers/transactions'; import { notifyFeatureUsage } from '../../feature'; import { withApmSpan } from '../../utils/with_apm_span'; import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; diff --git a/x-pack/plugins/apm/server/routes/suggestions.ts b/x-pack/plugins/apm/server/routes/suggestions.ts index 8b82601650a48..4834d894f364a 100644 --- a/x-pack/plugins/apm/server/routes/suggestions.ts +++ b/x-pack/plugins/apm/server/routes/suggestions.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { maxSuggestions } from '../../../observability/common'; import { getSuggestions } from '../lib/suggestions/get_suggestions'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { createApmServerRoute } from './create_apm_server_route'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; diff --git a/x-pack/plugins/apm/server/routes/traces.ts b/x-pack/plugins/apm/server/routes/traces.ts index a71b7eefeed3f..cc800c348b165 100644 --- a/x-pack/plugins/apm/server/routes/traces.ts +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -11,7 +11,7 @@ import { getTraceItems } from '../lib/traces/get_trace_items'; import { getTopTransactionGroupList } from '../lib/transaction_groups'; import { createApmServerRoute } from './create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { getRootTransactionByTraceId } from '../lib/transactions/get_transaction_by_trace'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; import { getTransaction } from '../lib/transactions/get_transaction'; diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index 0e24d64d8c6c7..56b7ead2254d3 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -11,7 +11,7 @@ import { LatencyAggregationType, latencyAggregationTypeRt, } from '../../common/latency_aggregation_types'; -import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; +import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceTransactionGroups } from '../lib/services/get_service_transaction_groups'; import { getServiceTransactionGroupDetailedStatisticsPeriods } from '../lib/services/get_service_transaction_group_detailed_statistics'; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts index ac2e8e8babee1..f1ede936c6ace 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts @@ -6,12 +6,11 @@ */ import { ExpressionTypeDefinition } from '../../../../../src/plugins/expressions'; -import { EmbeddableInput } from '../../../../../src/plugins/embeddable/common/'; +import { EmbeddableInput } from '../../types'; import { EmbeddableTypes } from './embeddable_types'; export const EmbeddableExpressionType = 'embeddable'; export { EmbeddableTypes, EmbeddableInput }; - export interface EmbeddableExpression { /** * The type of the expression result diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts index 2cfdebafb70df..d6d7a0f867849 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts @@ -6,7 +6,6 @@ */ import { functions as commonFunctions } from '../common'; -import { functions as externalFunctions } from '../external'; import { location } from './location'; import { markdown } from './markdown'; import { urlparam } from './urlparam'; @@ -14,13 +13,4 @@ import { escount } from './escount'; import { esdocs } from './esdocs'; import { essql } from './essql'; -export const functions = [ - location, - markdown, - urlparam, - escount, - esdocs, - essql, - ...commonFunctions, - ...externalFunctions, -]; +export const functions = [location, markdown, urlparam, escount, esdocs, essql, ...commonFunctions]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts new file mode 100644 index 0000000000000..001fb0e3f62e3 --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { embeddableFunctionFactory } from './embeddable'; +import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; +import { ExpressionValueFilter } from '../../../types'; +import { encode } from '../../../common/lib/embeddable_dataurl'; +import { InitializeArguments } from '.'; + +const filterContext: ExpressionValueFilter = { + type: 'filter', + and: [ + { + type: 'filter', + and: [], + value: 'filter-value', + column: 'filter-column', + filterType: 'exactly', + }, + { + type: 'filter', + and: [], + column: 'time-column', + filterType: 'time', + from: '2019-06-04T04:00:00.000Z', + to: '2019-06-05T04:00:00.000Z', + }, + ], +}; + +describe('embeddable', () => { + const fn = embeddableFunctionFactory({} as InitializeArguments)().fn; + const config = { + id: 'some-id', + timerange: { from: '15m', to: 'now' }, + title: 'test embeddable', + }; + + const args = { + config: encode(config), + type: 'visualization', + }; + + it('accepts null context', () => { + const expression = fn(null, args, {} as any); + + expect(expression.input.filters).toEqual([]); + }); + + it('accepts filter context', () => { + const expression = fn(filterContext, args, {} as any); + const embeddableFilters = getQueryFilters(filterContext.and); + + expect(expression.input.filters).toEqual(embeddableFilters); + }); +}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts new file mode 100644 index 0000000000000..7ef8f0a09eb90 --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; +import { ExpressionValueFilter, EmbeddableInput } from '../../../types'; +import { EmbeddableExpressionType, EmbeddableExpression } from '../../expression_types'; +import { getFunctionHelp } from '../../../i18n'; +import { SavedObjectReference } from '../../../../../../src/core/types'; +import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; +import { decode, encode } from '../../../common/lib/embeddable_dataurl'; +import { InitializeArguments } from '.'; + +export interface Arguments { + config: string; + type: string; +} + +const defaultTimeRange = { + from: 'now-15m', + to: 'now', +}; + +const baseEmbeddableInput = { + timeRange: defaultTimeRange, + disableTriggers: true, + renderMode: 'noInteractivity', +}; + +type Return = EmbeddableExpression; + +type EmbeddableFunction = ExpressionFunctionDefinition< + 'embeddable', + ExpressionValueFilter | null, + Arguments, + Return +>; + +export function embeddableFunctionFactory({ + embeddablePersistableStateService, +}: InitializeArguments): () => EmbeddableFunction { + return function embeddable(): EmbeddableFunction { + const { help, args: argHelp } = getFunctionHelp().embeddable; + + return { + name: 'embeddable', + help, + args: { + config: { + aliases: ['_'], + types: ['string'], + required: true, + help: argHelp.config, + }, + type: { + types: ['string'], + required: true, + help: argHelp.type, + }, + }, + context: { + types: ['filter'], + }, + type: EmbeddableExpressionType, + fn: (input, args) => { + const filters = input ? input.and : []; + + const embeddableInput = decode(args.config) as EmbeddableInput; + + return { + type: EmbeddableExpressionType, + input: { + ...baseEmbeddableInput, + ...embeddableInput, + filters: getQueryFilters(filters), + }, + generatedAt: Date.now(), + embeddableType: args.type, + }; + }, + + extract(state) { + const input = decode(state.config[0] as string); + + // extracts references for by-reference embeddables + if (input.savedObjectId) { + const refName = 'embeddable.savedObjectId'; + + const references: SavedObjectReference[] = [ + { + name: refName, + type: state.type[0] as string, + id: input.savedObjectId as string, + }, + ]; + + return { + state, + references, + }; + } + + // extracts references for by-value embeddables + const { state: extractedState, references: extractedReferences } = + embeddablePersistableStateService.extract({ + ...input, + type: state.type[0], + }); + + const { type, ...extractedInput } = extractedState; + + return { + state: { ...state, config: [encode(extractedInput)], type: [type] }, + references: extractedReferences, + }; + }, + + inject(state, references) { + const input = decode(state.config[0] as string); + const savedObjectReference = references.find( + (ref) => ref.name === 'embeddable.savedObjectId' + ); + + // injects saved object id for by-references embeddable + if (savedObjectReference) { + input.savedObjectId = savedObjectReference.id; + state.config[0] = encode(input); + state.type[0] = savedObjectReference.type; + } else { + // injects references for by-value embeddables + const { type, ...injectedInput } = embeddablePersistableStateService.inject( + { ...input, type: state.type[0] }, + references + ); + state.config[0] = encode(injectedInput); + state.type[0] = type; + } + return state; + }, + }; + }; +} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts index 407a0e2ebfe05..1d69e181b5fd9 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts @@ -5,9 +5,26 @@ * 2.0. */ +import { EmbeddableStart } from 'src/plugins/embeddable/public'; +import { embeddableFunctionFactory } from './embeddable'; import { savedLens } from './saved_lens'; import { savedMap } from './saved_map'; import { savedSearch } from './saved_search'; import { savedVisualization } from './saved_visualization'; -export const functions = [savedLens, savedMap, savedVisualization, savedSearch]; +export interface InitializeArguments { + embeddablePersistableStateService: { + extract: EmbeddableStart['extract']; + inject: EmbeddableStart['inject']; + }; +} + +export function initFunctions(initialize: InitializeArguments) { + return [ + embeddableFunctionFactory(initialize), + savedLens, + savedMap, + savedSearch, + savedVisualization, + ]; +} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts index 082a69a874cae..67947691f7757 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts @@ -9,9 +9,8 @@ import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; import { PaletteOutput } from 'src/plugins/charts/common'; import { Filter as DataFilter } from '@kbn/es-query'; import { TimeRange } from 'src/plugins/data/common'; -import { EmbeddableInput } from 'src/plugins/embeddable/common'; import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; -import { ExpressionValueFilter, TimeRange as TimeRangeArg } from '../../../types'; +import { ExpressionValueFilter, EmbeddableInput, TimeRange as TimeRangeArg } from '../../../types'; import { EmbeddableTypes, EmbeddableExpressionType, @@ -27,7 +26,7 @@ interface Arguments { } export type SavedLensInput = EmbeddableInput & { - id: string; + savedObjectId: string; timeRange?: TimeRange; filters: DataFilter[]; palette?: PaletteOutput; @@ -73,18 +72,19 @@ export function savedLens(): ExpressionFunctionDefinition< }, }, type: EmbeddableExpressionType, - fn: (input, args) => { + fn: (input, { id, timerange, title, palette }) => { const filters = input ? input.and : []; return { type: EmbeddableExpressionType, input: { - id: args.id, + id, + savedObjectId: id, filters: getQueryFilters(filters), - timeRange: args.timerange || defaultTimeRange, - title: args.title === null ? undefined : args.title, + timeRange: timerange || defaultTimeRange, + title: title === null ? undefined : title, disableTriggers: true, - palette: args.palette, + palette, }, embeddableType: EmbeddableTypes.lens, generatedAt: Date.now(), diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts index 538ed3f919823..a7471c755155c 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts @@ -30,7 +30,7 @@ const defaultTimeRange = { to: 'now', }; -type Output = EmbeddableExpression; +type Output = EmbeddableExpression; export function savedMap(): ExpressionFunctionDefinition< 'savedMap', @@ -85,8 +85,9 @@ export function savedMap(): ExpressionFunctionDefinition< return { type: EmbeddableExpressionType, input: { - attributes: { title: '' }, id: args.id, + attributes: { title: '' }, + savedObjectId: args.id, filters: getQueryFilters(filters), timeRange: args.timerange || defaultTimeRange, refreshConfig: { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts index 5c0442b43250c..31e3fb2a8c564 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts @@ -25,7 +25,7 @@ interface Arguments { title: string | null; } -type Output = EmbeddableExpression; +type Output = EmbeddableExpression; const defaultTimeRange = { from: 'now-15m', @@ -94,6 +94,7 @@ export function savedVisualization(): ExpressionFunctionDefinition< type: EmbeddableExpressionType, input: { id, + savedObjectId: id, disableTriggers: true, timeRange: timerange || defaultTimeRange, filters: getQueryFilters(filters), diff --git a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts index 91c573fc4148b..591795637aebe 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts @@ -7,12 +7,14 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ChartsPluginStart } from 'src/plugins/charts/public'; +import { PresentationUtilPluginStart } from 'src/plugins/presentation_util/public'; import { CanvasSetup } from '../public'; import { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; import { UiActionsStart } from '../../../../src/plugins/ui_actions/public'; import { Start as InspectorStart } from '../../../../src/plugins/inspector/public'; import { functions } from './functions/browser'; +import { initFunctions } from './functions/external'; import { typeFunctions } from './expression_types'; import { renderFunctions, renderFunctionFactories } from './renderers'; @@ -25,6 +27,7 @@ export interface StartDeps { uiActions: UiActionsStart; inspector: InspectorStart; charts: ChartsPluginStart; + presentationUtil: PresentationUtilPluginStart; } export type SetupInitializer = (core: CoreSetup, plugins: SetupDeps) => T; @@ -39,6 +42,13 @@ export class CanvasSrcPlugin implements Plugin plugins.canvas.addRenderers(renderFunctions); core.getStartServices().then(([coreStart, depsStart]) => { + const externalFunctions = initFunctions({ + embeddablePersistableStateService: { + extract: depsStart.embeddable.extract, + inject: depsStart.embeddable.inject, + }, + }); + plugins.canvas.addFunctions(externalFunctions); plugins.canvas.addRenderers( renderFunctionFactories.map((factory: any) => factory(coreStart, depsStart)) ); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index 73e839433c25e..953746c280840 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -13,16 +13,17 @@ import { IEmbeddable, EmbeddableFactory, EmbeddableFactoryNotFoundError, + isErrorEmbeddable, } from '../../../../../../src/plugins/embeddable/public'; import { EmbeddableExpression } from '../../expression_types/embeddable'; import { RendererStrings } from '../../../i18n'; import { embeddableInputToExpression } from './embeddable_input_to_expression'; -import { EmbeddableInput } from '../../expression_types'; -import { RendererFactory } from '../../../types'; +import { RendererFactory, EmbeddableInput } from '../../../types'; import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; const { embeddable: strings } = RendererStrings; +// registry of references to embeddables on the workpad const embeddablesRegistry: { [key: string]: IEmbeddable | Promise; } = {}; @@ -30,11 +31,11 @@ const embeddablesRegistry: { const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => { const I18nContext = core.i18n.Context; - return (embeddableObject: IEmbeddable, domNode: HTMLElement) => { + return (embeddableObject: IEmbeddable) => { return (
@@ -56,6 +57,9 @@ export const embeddableRendererFactory = ( reuseDomNode: true, render: async (domNode, { input, embeddableType }, handlers) => { const uniqueId = handlers.getElementId(); + const isByValueEnabled = plugins.presentationUtil.labsService.isProjectEnabled( + 'labs:canvas:byValueEmbeddable' + ); if (!embeddablesRegistry[uniqueId]) { const factory = Array.from(plugins.embeddable.getEmbeddableFactories()).find( @@ -67,15 +71,27 @@ export const embeddableRendererFactory = ( throw new EmbeddableFactoryNotFoundError(embeddableType); } - const embeddablePromise = factory - .createFromSavedObject(input.id, input) - .then((embeddable) => { - embeddablesRegistry[uniqueId] = embeddable; - return embeddable; - }); - embeddablesRegistry[uniqueId] = embeddablePromise; - - const embeddableObject = await (async () => embeddablePromise)(); + const embeddableInput = { ...input, id: uniqueId }; + + const embeddablePromise = input.savedObjectId + ? factory + .createFromSavedObject(input.savedObjectId, embeddableInput) + .then((embeddable) => { + // stores embeddable in registrey + embeddablesRegistry[uniqueId] = embeddable; + return embeddable; + }) + : factory.create(embeddableInput).then((embeddable) => { + if (!embeddable || isErrorEmbeddable(embeddable)) { + return; + } + // stores embeddable in registry + embeddablesRegistry[uniqueId] = embeddable as IEmbeddable; + return embeddable; + }); + embeddablesRegistry[uniqueId] = embeddablePromise as Promise; + + const embeddableObject = (await (async () => embeddablePromise)()) as IEmbeddable; const palettes = await plugins.charts.palettes.getPalettes(); @@ -86,7 +102,8 @@ export const embeddableRendererFactory = ( const updatedExpression = embeddableInputToExpression( updatedInput, embeddableType, - palettes + palettes, + isByValueEnabled ); if (updatedExpression) { @@ -94,15 +111,7 @@ export const embeddableRendererFactory = ( } }); - ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => - handlers.done() - ); - - handlers.onResize(() => { - ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => - handlers.done() - ); - }); + ReactDOM.render(renderEmbeddable(embeddableObject), domNode, () => handlers.done()); handlers.onDestroy(() => { subscription.unsubscribe(); @@ -115,6 +124,7 @@ export const embeddableRendererFactory = ( } else { const embeddable = embeddablesRegistry[uniqueId]; + // updating embeddable input with changes made to expression or filters if ('updateInput' in embeddable) { embeddable.updateInput(input); embeddable.reload(); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts index 41cefad6a470f..80830eac24021 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts @@ -10,6 +10,7 @@ import { EmbeddableTypes, EmbeddableInput } from '../../expression_types'; import { toExpression as mapToExpression } from './input_type_to_expression/map'; import { toExpression as visualizationToExpression } from './input_type_to_expression/visualization'; import { toExpression as lensToExpression } from './input_type_to_expression/lens'; +import { toExpression as genericToExpression } from './input_type_to_expression/embeddable'; export const inputToExpressionTypeMap = { [EmbeddableTypes.map]: mapToExpression, @@ -23,8 +24,13 @@ export const inputToExpressionTypeMap = { export function embeddableInputToExpression( input: EmbeddableInput, embeddableType: string, - palettes: PaletteRegistry + palettes: PaletteRegistry, + useGenericEmbeddable?: boolean ): string | undefined { + if (useGenericEmbeddable) { + return genericToExpression(input, embeddableType); + } + if (inputToExpressionTypeMap[embeddableType]) { return inputToExpressionTypeMap[embeddableType](input as any, palettes); } diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts new file mode 100644 index 0000000000000..4b78acec8750a --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { toExpression } from './embeddable'; +import { EmbeddableInput } from '../../../../types'; +import { decode } from '../../../../common/lib/embeddable_dataurl'; +import { fromExpression } from '@kbn/interpreter/common'; + +describe('toExpression', () => { + describe('by-reference embeddable input', () => { + const baseEmbeddableInput = { + id: 'elementId', + savedObjectId: 'embeddableId', + filters: [], + }; + + it('converts to an embeddable expression', () => { + const input: EmbeddableInput = baseEmbeddableInput; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + expect(ast.type).toBe('expression'); + expect(ast.chain[0].function).toBe('embeddable'); + expect(ast.chain[0].arguments.type[0]).toBe('visualization'); + + const config = decode(ast.chain[0].arguments.config[0] as string); + + expect(config.savedObjectId).toStrictEqual(input.savedObjectId); + }); + + it('includes optional input values', () => { + const input: EmbeddableInput = { + ...baseEmbeddableInput, + title: 'title', + timeRange: { + from: 'now-1h', + to: 'now', + }, + }; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + const config = decode(ast.chain[0].arguments.config[0] as string); + + expect(config).toHaveProperty('title', input.title); + expect(config).toHaveProperty('timeRange'); + expect(config.timeRange).toHaveProperty('from', input.timeRange?.from); + expect(config.timeRange).toHaveProperty('to', input.timeRange?.to); + }); + + it('includes empty panel title', () => { + const input: EmbeddableInput = { + ...baseEmbeddableInput, + title: '', + }; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + const config = decode(ast.chain[0].arguments.config[0] as string); + + expect(config).toHaveProperty('title', input.title); + }); + }); + + describe('by-value embeddable input', () => { + const baseEmbeddableInput = { + id: 'elementId', + disableTriggers: true, + filters: [], + }; + it('converts to an embeddable expression', () => { + const input: EmbeddableInput = baseEmbeddableInput; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + expect(ast.type).toBe('expression'); + expect(ast.chain[0].function).toBe('embeddable'); + expect(ast.chain[0].arguments.type[0]).toBe('visualization'); + + const config = decode(ast.chain[0].arguments.config[0] as string); + expect(config.filters).toStrictEqual(input.filters); + expect(config.disableTriggers).toStrictEqual(input.disableTriggers); + }); + + it('includes optional input values', () => { + const input: EmbeddableInput = { + ...baseEmbeddableInput, + title: 'title', + timeRange: { + from: 'now-1h', + to: 'now', + }, + }; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + const config = decode(ast.chain[0].arguments.config[0] as string); + + expect(config).toHaveProperty('title', input.title); + expect(config).toHaveProperty('timeRange'); + expect(config.timeRange).toHaveProperty('from', input.timeRange?.from); + expect(config.timeRange).toHaveProperty('to', input.timeRange?.to); + }); + + it('includes empty panel title', () => { + const input: EmbeddableInput = { + ...baseEmbeddableInput, + title: '', + }; + + const expression = toExpression(input, 'visualization'); + const ast = fromExpression(expression); + + const config = decode(ast.chain[0].arguments.config[0] as string); + + expect(config).toHaveProperty('title', input.title); + }); + }); +}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts new file mode 100644 index 0000000000000..94d86f6640be1 --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { encode } from '../../../../common/lib/embeddable_dataurl'; +import { EmbeddableInput } from '../../../expression_types'; + +export function toExpression(input: EmbeddableInput, embeddableType: string): string { + return `embeddable config="${encode(input)}" type="${embeddableType}"`; +} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts index 24da7238bcee9..224cdfba389d7 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts @@ -11,7 +11,8 @@ import { fromExpression, Ast } from '@kbn/interpreter/common'; import { chartPluginMock } from 'src/plugins/charts/public/mocks'; const baseEmbeddableInput = { - id: 'embeddableId', + id: 'elementId', + savedObjectId: 'embeddableId', filters: [], }; @@ -27,7 +28,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedLens'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); expect(ast.chain[0].arguments).not.toHaveProperty('title'); expect(ast.chain[0].arguments).not.toHaveProperty('timerange'); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts index 35e106f234fa4..5a13b73b3fe74 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts @@ -14,7 +14,7 @@ export function toExpression(input: SavedLensInput, palettes: PaletteRegistry): expressionParts.push('savedLens'); - expressionParts.push(`id="${input.id}"`); + expressionParts.push(`id="${input.savedObjectId}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts index 804d0d849cc7f..af7b40a9b283d 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts @@ -6,12 +6,12 @@ */ import { toExpression } from './map'; -import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable'; import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseSavedMapInput = { + id: 'elementId', attributes: { title: '' }, - id: 'embeddableId', + savedObjectId: 'embeddableId', filters: [], isLayerTOCOpen: false, refreshConfig: { @@ -23,7 +23,7 @@ const baseSavedMapInput = { describe('toExpression', () => { it('converts to a savedMap expression', () => { - const input: MapEmbeddableInput = { + const input = { ...baseSavedMapInput, }; @@ -33,7 +33,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedMap'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); expect(ast.chain[0].arguments).not.toHaveProperty('title'); expect(ast.chain[0].arguments).not.toHaveProperty('center'); @@ -41,7 +41,7 @@ describe('toExpression', () => { }); it('includes optional input values', () => { - const input: MapEmbeddableInput = { + const input = { ...baseSavedMapInput, mapCenter: { lat: 1, @@ -73,7 +73,7 @@ describe('toExpression', () => { }); it('includes empty panel title', () => { - const input: MapEmbeddableInput = { + const input = { ...baseSavedMapInput, title: '', }; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts index 3fd6a68a327c6..03746f38b4696 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable'; +import { MapEmbeddableInput } from '../../../../../../plugins/maps/public'; -export function toExpression(input: MapEmbeddableInput): string { +export function toExpression(input: MapEmbeddableInput & { savedObjectId: string }): string { const expressionParts = [] as string[]; expressionParts.push('savedMap'); - expressionParts.push(`id="${input.id}"`); + + expressionParts.push(`id="${input.savedObjectId}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts index c5106b9a102b4..4c61a130f3c95 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts @@ -9,7 +9,8 @@ import { toExpression } from './visualization'; import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseInput = { - id: 'embeddableId', + id: 'elementId', + savedObjectId: 'embeddableId', }; describe('toExpression', () => { @@ -24,7 +25,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedVisualization'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); }); it('includes timerange if given', () => { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts index bcb73b2081fee..364d7cd0755db 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts @@ -7,11 +7,11 @@ import { VisualizeInput } from 'src/plugins/visualizations/public'; -export function toExpression(input: VisualizeInput): string { +export function toExpression(input: VisualizeInput & { savedObjectId: string }): string { const expressionParts = [] as string[]; expressionParts.push('savedVisualization'); - expressionParts.push(`id="${input.id}"`); + expressionParts.push(`id="${input.savedObjectId}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); diff --git a/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts b/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts new file mode 100644 index 0000000000000..e76dedfe63b14 --- /dev/null +++ b/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EmbeddableInput } from '../../types'; + +export const encode = (input: Partial) => + Buffer.from(JSON.stringify(input)).toString('base64'); +export const decode = (serializedInput: string) => + JSON.parse(Buffer.from(serializedInput, 'base64').toString()); diff --git a/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts b/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts new file mode 100644 index 0000000000000..279f58799e8c0 --- /dev/null +++ b/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { embeddableFunctionFactory } from '../../../canvas_plugin_src/functions/external/embeddable'; +import { FunctionHelp } from '../function_help'; +import { FunctionFactory } from '../../../types'; + +export const help: FunctionHelp>> = { + help: i18n.translate('xpack.canvas.functions.embeddableHelpText', { + defaultMessage: `Returns an embeddable with the provided configuration`, + }), + args: { + config: i18n.translate('xpack.canvas.functions.embeddable.args.idHelpText', { + defaultMessage: `The base64 encoded embeddable input object`, + }), + type: i18n.translate('xpack.canvas.functions.embeddable.args.typeHelpText', { + defaultMessage: `The embeddable type`, + }), + }, +}; diff --git a/x-pack/plugins/canvas/i18n/functions/function_help.ts b/x-pack/plugins/canvas/i18n/functions/function_help.ts index 5eae785fefa2e..520d32af1c272 100644 --- a/x-pack/plugins/canvas/i18n/functions/function_help.ts +++ b/x-pack/plugins/canvas/i18n/functions/function_help.ts @@ -27,6 +27,7 @@ import { help as demodata } from './dict/demodata'; import { help as doFn } from './dict/do'; import { help as dropdownControl } from './dict/dropdown_control'; import { help as eq } from './dict/eq'; +import { help as embeddable } from './dict/embeddable'; import { help as escount } from './dict/escount'; import { help as esdocs } from './dict/esdocs'; import { help as essql } from './dict/essql'; @@ -182,6 +183,7 @@ export const getFunctionHelp = (): FunctionHelpDict => ({ do: doFn, dropdownControl, eq, + embeddable, escount, esdocs, essql, diff --git a/x-pack/plugins/canvas/kibana.json b/x-pack/plugins/canvas/kibana.json index 9c4d1b2179d82..2fd312502a3c7 100644 --- a/x-pack/plugins/canvas/kibana.json +++ b/x-pack/plugins/canvas/kibana.json @@ -25,6 +25,7 @@ "features", "inspector", "presentationUtil", + "visualizations", "uiActions", "share" ], diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index bf731876bf8c8..57f52fcf21f0f 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { FC, useCallback } from 'react'; import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -27,38 +27,44 @@ const strings = { }; export interface Props { onClose: () => void; - onSelect: (id: string, embeddableType: string) => void; + onSelect: (id: string, embeddableType: string, isByValueEnabled?: boolean) => void; availableEmbeddables: string[]; + isByValueEnabled?: boolean; } -export const AddEmbeddableFlyout: FC = ({ onSelect, availableEmbeddables, onClose }) => { +export const AddEmbeddableFlyout: FC = ({ + onSelect, + availableEmbeddables, + onClose, + isByValueEnabled, +}) => { const embeddablesService = useEmbeddablesService(); const platformService = usePlatformService(); const { getEmbeddableFactories } = embeddablesService; const { getSavedObjects, getUISettings } = platformService; - const onAddPanel = (id: string, savedObjectType: string, name: string) => { - const embeddableFactories = getEmbeddableFactories(); + const onAddPanel = useCallback( + (id: string, savedObjectType: string) => { + const embeddableFactories = getEmbeddableFactories(); + // Find the embeddable type from the saved object type + const found = Array.from(embeddableFactories).find((embeddableFactory) => { + return Boolean( + embeddableFactory.savedObjectMetaData && + embeddableFactory.savedObjectMetaData.type === savedObjectType + ); + }); - // Find the embeddable type from the saved object type - const found = Array.from(embeddableFactories).find((embeddableFactory) => { - return Boolean( - embeddableFactory.savedObjectMetaData && - embeddableFactory.savedObjectMetaData.type === savedObjectType - ); - }); - - const foundEmbeddableType = found ? found.type : 'unknown'; + const foundEmbeddableType = found ? found.type : 'unknown'; - onSelect(id, foundEmbeddableType); - }; + onSelect(id, foundEmbeddableType, isByValueEnabled); + }, + [isByValueEnabled, getEmbeddableFactories, onSelect] + ); const embeddableFactories = getEmbeddableFactories(); const availableSavedObjects = Array.from(embeddableFactories) - .filter((factory) => { - return availableEmbeddables.includes(factory.type); - }) + .filter((factory) => isByValueEnabled || availableEmbeddables.includes(factory.type)) .map((factory) => factory.savedObjectMetaData) .filter>(function ( maybeSavedObjectMetaData diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx index 770a4cac606b0..4dc8d963932d8 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx @@ -8,12 +8,14 @@ import React, { useMemo, useEffect, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { useSelector, useDispatch } from 'react-redux'; +import { encode } from '../../../common/lib/embeddable_dataurl'; import { AddEmbeddableFlyout as Component, Props as ComponentProps } from './flyout.component'; // @ts-expect-error untyped local import { addElement } from '../../state/actions/elements'; import { getSelectedPage } from '../../state/selectors/workpad'; import { EmbeddableTypes } from '../../../canvas_plugin_src/expression_types/embeddable'; import { State } from '../../../types'; +import { useLabsService } from '../../services'; const allowedEmbeddables = { [EmbeddableTypes.map]: (id: string) => { @@ -65,6 +67,9 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ availableEmbeddables, ...restProps }) => { + const labsService = useLabsService(); + const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); + const dispatch = useDispatch(); const pageId = useSelector((state) => getSelectedPage(state)); @@ -74,18 +79,27 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ ); const onSelect = useCallback( - (id: string, type: string) => { + (id: string, type: string): void => { const partialElement = { expression: `markdown "Could not find embeddable for type ${type}" | render`, }; - if (allowedEmbeddables[type]) { + + // If by-value is enabled, we'll handle both by-reference and by-value embeddables + // with the new generic `embeddable` function. + // Otherwise we fallback to the embeddable type specific expressions. + if (isByValueEnabled) { + const config = encode({ savedObjectId: id }); + partialElement.expression = `embeddable config="${config}" + type="${type}" +| render`; + } else if (allowedEmbeddables[type]) { partialElement.expression = allowedEmbeddables[type](id); } addEmbeddable(pageId, partialElement); restProps.onClose(); }, - [addEmbeddable, pageId, restProps] + [addEmbeddable, pageId, restProps, isByValueEnabled] ); return ( @@ -93,6 +107,7 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ {...restProps} availableEmbeddables={availableEmbeddables || []} onSelect={onSelect} + isByValueEnabled={isByValueEnabled} /> ); }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx index 50d527036560a..ffd5b095b12e5 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx @@ -6,3 +6,5 @@ */ export { useDownloadWorkpad, useDownloadRenderedWorkpad } from './use_download_workpad'; + +export { useIncomingEmbeddable } from './use_incoming_embeddable'; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts new file mode 100644 index 0000000000000..2f8e2503ea57e --- /dev/null +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect } from 'react'; +import { useDispatch } from 'react-redux'; +import { fromExpression } from '@kbn/interpreter/common'; +import { CANVAS_APP } from '../../../../common/lib'; +import { decode, encode } from '../../../../common/lib/embeddable_dataurl'; +import { CanvasElement, CanvasPage } from '../../../../types'; +import { useEmbeddablesService, useLabsService } from '../../../services'; +// @ts-expect-error unconverted file +import { addElement } from '../../../state/actions/elements'; +// @ts-expect-error unconverted file +import { selectToplevelNodes } from '../../../state/actions/transient'; + +import { + updateEmbeddableExpression, + fetchEmbeddableRenderable, +} from '../../../state/actions/embeddable'; +import { clearValue } from '../../../state/actions/resolved_args'; + +export const useIncomingEmbeddable = (selectedPage: CanvasPage) => { + const embeddablesService = useEmbeddablesService(); + const labsService = useLabsService(); + const dispatch = useDispatch(); + const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); + const stateTransferService = embeddablesService.getStateTransfer(); + + // fetch incoming embeddable from state transfer service. + const incomingEmbeddable = stateTransferService.getIncomingEmbeddablePackage(CANVAS_APP, true); + + useEffect(() => { + if (isByValueEnabled && incomingEmbeddable) { + const { embeddableId, input: incomingInput, type } = incomingEmbeddable; + + // retrieve existing element + const originalElement = selectedPage.elements.find( + ({ id }: CanvasElement) => id === embeddableId + ); + + if (originalElement) { + const originalAst = fromExpression(originalElement!.expression); + + const functionIndex = originalAst.chain.findIndex( + ({ function: fn }) => fn === 'embeddable' + ); + + const originalInput = decode( + originalAst.chain[functionIndex].arguments.config[0] as string + ); + + // clear out resolved arg for old embeddable + const argumentPath = [embeddableId, 'expressionRenderable']; + dispatch(clearValue({ path: argumentPath })); + + const updatedInput = { ...originalInput, ...incomingInput }; + + const expression = `embeddable config="${encode(updatedInput)}" + type="${type}" +| render`; + + dispatch( + updateEmbeddableExpression({ + elementId: originalElement.id, + embeddableExpression: expression, + }) + ); + + // update resolved args + dispatch(fetchEmbeddableRenderable(originalElement.id)); + + // select new embeddable element + dispatch(selectToplevelNodes([embeddableId])); + } else { + const expression = `embeddable config="${encode(incomingInput)}" + type="${type}" +| render`; + dispatch(addElement(selectedPage.id, { expression })); + } + } + }, [dispatch, selectedPage, incomingEmbeddable, isByValueEnabled]); +}; diff --git a/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot b/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot index 8ca3dc2a94d4e..47c536cd1e2ef 100644 --- a/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot @@ -13,6 +13,24 @@ exports[`Storyshots components/Variables/VarConfig default 1`] = `
+ +
+
+`; + +exports[`Storyshots components/WorkpadHeader/EditorMenu default 1`] = ` +
+
+ +
+
+`; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx new file mode 100644 index 0000000000000..01048bc0af301 --- /dev/null +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import React from 'react'; +import { EmbeddableFactoryDefinition, IEmbeddable } from 'src/plugins/embeddable/public'; +import { BaseVisType, VisTypeAlias } from 'src/plugins/visualizations/public'; +import { EditorMenu } from '../editor_menu.component'; + +const testFactories: EmbeddableFactoryDefinition[] = [ + { + type: 'ml_anomaly_swimlane', + getDisplayName: () => 'Anomaly swimlane', + getIconType: () => '', + getDescription: () => 'Description for anomaly swimlane', + isEditable: () => Promise.resolve(true), + create: () => Promise.resolve({ id: 'swimlane_embeddable' } as IEmbeddable), + grouping: [ + { + id: 'ml', + getDisplayName: () => 'machine learning', + getIconType: () => 'machineLearningApp', + }, + ], + }, + { + type: 'ml_anomaly_chart', + getDisplayName: () => 'Anomaly chart', + getIconType: () => '', + getDescription: () => 'Description for anomaly chart', + isEditable: () => Promise.resolve(true), + create: () => Promise.resolve({ id: 'anomaly_chart_embeddable' } as IEmbeddable), + grouping: [ + { + id: 'ml', + getDisplayName: () => 'machine learning', + getIconType: () => 'machineLearningApp', + }, + ], + }, + { + type: 'log_stream', + getDisplayName: () => 'Log stream', + getIconType: () => '', + getDescription: () => 'Description for log stream', + isEditable: () => Promise.resolve(true), + create: () => Promise.resolve({ id: 'anomaly_chart_embeddable' } as IEmbeddable), + }, +]; + +const testVisTypes: BaseVisType[] = [ + { title: 'TSVB', icon: '', description: 'Description of TSVB', name: 'tsvb' } as BaseVisType, + { + titleInWizard: 'Custom visualization', + title: 'Vega', + icon: '', + description: 'Description of Vega', + name: 'vega', + } as BaseVisType, +]; + +const testVisTypeAliases: VisTypeAlias[] = [ + { + title: 'Lens', + aliasApp: 'lens', + aliasPath: 'path/to/lens', + icon: 'lensApp', + name: 'lens', + description: 'Description of Lens app', + stage: 'production', + }, + { + title: 'Maps', + aliasApp: 'maps', + aliasPath: 'path/to/maps', + icon: 'gisApp', + name: 'maps', + description: 'Description of Maps app', + stage: 'production', + }, +]; + +storiesOf('components/WorkpadHeader/EditorMenu', module) + .add('default', () => ( + action('createNewVisType')} + createNewEmbeddable={() => action('createNewEmbeddable')} + /> + )) + .add('dark mode', () => ( + action('createNewVisType')} + createNewEmbeddable={() => action('createNewEmbeddable')} + /> + )); diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx new file mode 100644 index 0000000000000..e8f762f9731a1 --- /dev/null +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { + EuiContextMenu, + EuiContextMenuPanelItemDescriptor, + EuiContextMenuItemIcon, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { EmbeddableFactoryDefinition } from '../../../../../../../src/plugins/embeddable/public'; +import { BaseVisType, VisTypeAlias } from '../../../../../../../src/plugins/visualizations/public'; +import { SolutionToolbarPopover } from '../../../../../../../src/plugins/presentation_util/public'; + +const strings = { + getEditorMenuButtonLabel: () => + i18n.translate('xpack.canvas.solutionToolbar.editorMenuButtonLabel', { + defaultMessage: 'Select type', + }), +}; + +interface FactoryGroup { + id: string; + appName: string; + icon: EuiContextMenuItemIcon; + panelId: number; + factories: EmbeddableFactoryDefinition[]; +} + +interface Props { + factories: EmbeddableFactoryDefinition[]; + isDarkThemeEnabled?: boolean; + promotedVisTypes: BaseVisType[]; + visTypeAliases: VisTypeAlias[]; + createNewVisType: (visType?: BaseVisType | VisTypeAlias) => () => void; + createNewEmbeddable: (factory: EmbeddableFactoryDefinition) => () => void; +} + +export const EditorMenu: FC = ({ + factories, + isDarkThemeEnabled, + promotedVisTypes, + visTypeAliases, + createNewVisType, + createNewEmbeddable, +}: Props) => { + const factoryGroupMap: Record = {}; + const ungroupedFactories: EmbeddableFactoryDefinition[] = []; + + let panelCount = 1; + + // Maps factories with a group to create nested context menus for each group type + // and pushes ungrouped factories into a separate array + factories.forEach((factory: EmbeddableFactoryDefinition, index) => { + const { grouping } = factory; + + if (grouping) { + grouping.forEach((group) => { + if (factoryGroupMap[group.id]) { + factoryGroupMap[group.id].factories.push(factory); + } else { + factoryGroupMap[group.id] = { + id: group.id, + appName: group.getDisplayName ? group.getDisplayName({}) : group.id, + icon: (group.getIconType ? group.getIconType({}) : 'empty') as EuiContextMenuItemIcon, + factories: [factory], + panelId: panelCount, + }; + + panelCount++; + } + }); + } else { + ungroupedFactories.push(factory); + } + }); + + const getVisTypeMenuItem = (visType: BaseVisType): EuiContextMenuPanelItemDescriptor => { + const { name, title, titleInWizard, description, icon = 'empty' } = visType; + return { + name: titleInWizard || title, + icon: icon as string, + onClick: createNewVisType(visType), + 'data-test-subj': `visType-${name}`, + toolTipContent: description, + }; + }; + + const getVisTypeAliasMenuItem = ( + visTypeAlias: VisTypeAlias + ): EuiContextMenuPanelItemDescriptor => { + const { name, title, description, icon = 'empty' } = visTypeAlias; + + return { + name: title, + icon, + onClick: createNewVisType(visTypeAlias), + 'data-test-subj': `visType-${name}`, + toolTipContent: description, + }; + }; + + const getEmbeddableFactoryMenuItem = ( + factory: EmbeddableFactoryDefinition + ): EuiContextMenuPanelItemDescriptor => { + const icon = factory?.getIconType ? factory.getIconType() : 'empty'; + + const toolTipContent = factory?.getDescription ? factory.getDescription() : undefined; + + return { + name: factory.getDisplayName(), + icon, + toolTipContent, + onClick: createNewEmbeddable(factory), + 'data-test-subj': `createNew-${factory.type}`, + }; + }; + + const editorMenuPanels = [ + { + id: 0, + items: [ + ...visTypeAliases.map(getVisTypeAliasMenuItem), + ...Object.values(factoryGroupMap).map(({ id, appName, icon, panelId }) => ({ + name: appName, + icon, + panel: panelId, + 'data-test-subj': `canvasEditorMenu-${id}Group`, + })), + ...ungroupedFactories.map(getEmbeddableFactoryMenuItem), + ...promotedVisTypes.map(getVisTypeMenuItem), + ], + }, + ...Object.values(factoryGroupMap).map( + ({ appName, panelId, factories: groupFactories }: FactoryGroup) => ({ + id: panelId, + title: appName, + items: groupFactories.map(getEmbeddableFactoryMenuItem), + }) + ), + ]; + + return ( + + {() => ( + + )} + + ); +}; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx new file mode 100644 index 0000000000000..dad34e6983c5d --- /dev/null +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC, useCallback } from 'react'; +import { useLocation } from 'react-router-dom'; +import { trackCanvasUiMetric, METRIC_TYPE } from '../../../../public/lib/ui_metric'; +import { + useEmbeddablesService, + usePlatformService, + useVisualizationsService, +} from '../../../services'; +import { + BaseVisType, + VisGroups, + VisTypeAlias, +} from '../../../../../../../src/plugins/visualizations/public'; +import { + EmbeddableFactoryDefinition, + EmbeddableInput, +} from '../../../../../../../src/plugins/embeddable/public'; +import { CANVAS_APP } from '../../../../common/lib'; +import { encode } from '../../../../common/lib/embeddable_dataurl'; +import { ElementSpec } from '../../../../types'; +import { EditorMenu as Component } from './editor_menu.component'; + +interface Props { + /** + * Handler for adding a selected element to the workpad + */ + addElement: (element: Partial) => void; +} + +export const EditorMenu: FC = ({ addElement }) => { + const embeddablesService = useEmbeddablesService(); + const { pathname, search } = useLocation(); + const platformService = usePlatformService(); + const stateTransferService = embeddablesService.getStateTransfer(); + const visualizationsService = useVisualizationsService(); + const IS_DARK_THEME = platformService.getUISetting('theme:darkMode'); + + const createNewVisType = useCallback( + (visType?: BaseVisType | VisTypeAlias) => () => { + let path = ''; + let appId = ''; + + if (visType) { + if (trackCanvasUiMetric) { + trackCanvasUiMetric(METRIC_TYPE.CLICK, `${visType.name}:create`); + } + + if ('aliasPath' in visType) { + appId = visType.aliasApp; + path = visType.aliasPath; + } else { + appId = 'visualize'; + path = `#/create?type=${encodeURIComponent(visType.name)}`; + } + } else { + appId = 'visualize'; + path = '#/create?'; + } + + stateTransferService.navigateToEditor(appId, { + path, + state: { + originatingApp: CANVAS_APP, + originatingPath: `#/${pathname}${search}`, + }, + }); + }, + [stateTransferService, pathname, search] + ); + + const createNewEmbeddable = useCallback( + (factory: EmbeddableFactoryDefinition) => async () => { + if (trackCanvasUiMetric) { + trackCanvasUiMetric(METRIC_TYPE.CLICK, factory.type); + } + let embeddableInput; + if (factory.getExplicitInput) { + embeddableInput = await factory.getExplicitInput(); + } else { + const newEmbeddable = await factory.create({} as EmbeddableInput); + embeddableInput = newEmbeddable?.getInput(); + } + + if (embeddableInput) { + const config = encode(embeddableInput); + const expression = `embeddable config="${config}" + type="${factory.type}" +| render`; + + addElement({ expression }); + } + }, + [addElement] + ); + + const getVisTypesByGroup = (group: VisGroups): BaseVisType[] => + visualizationsService + .getByGroup(group) + .sort(({ name: a }: BaseVisType | VisTypeAlias, { name: b }: BaseVisType | VisTypeAlias) => { + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + }) + .filter(({ hidden }: BaseVisType) => !hidden); + + const visTypeAliases = visualizationsService + .getAliases() + .sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => + a === b ? 0 : a ? -1 : 1 + ); + + const factories = embeddablesService + ? Array.from(embeddablesService.getEmbeddableFactories()).filter( + ({ type, isEditable, canCreateNew, isContainerType }) => + isEditable() && + !isContainerType && + canCreateNew() && + !['visualization', 'ml'].some((factoryType) => { + return type.includes(factoryType); + }) + ) + : []; + + const promotedVisTypes = getVisTypesByGroup(VisGroups.PROMOTED); + + return ( + + ); +}; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts new file mode 100644 index 0000000000000..0f903b1bbbe2e --- /dev/null +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { EditorMenu } from './editor_menu'; +export { EditorMenu as EditorMenuComponent } from './editor_menu.component'; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx index 8ac581b0866a4..1cfab236d9a9c 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx @@ -12,11 +12,11 @@ import { EuiContextMenu, EuiIcon, EuiContextMenuPanelItemDescriptor } from '@ela import { i18n } from '@kbn/i18n'; import { PrimaryActionPopover } from '../../../../../../../src/plugins/presentation_util/public'; import { getId } from '../../../lib/get_id'; -import { ClosePopoverFn } from '../../popover'; import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib'; import { ElementSpec } from '../../../../types'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { AssetManager } from '../../asset_manager'; +import { ClosePopoverFn } from '../../popover'; import { SavedElementsModal } from '../../saved_elements_modal'; interface CategorizedElementLists { @@ -112,7 +112,7 @@ const categorizeElementsByType = (elements: ElementSpec[]): { [key: string]: Ele return categories; }; -interface Props { +export interface Props { /** * Dictionary of elements from elements registry */ @@ -120,7 +120,7 @@ interface Props { /** * Handler for adding a selected element to the workpad */ - addElement: (element: ElementSpec) => void; + addElement: (element: Partial) => void; } export const ElementMenu: FunctionComponent = ({ elements, addElement }) => { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts index 52c8daece7690..037bb84b0cdba 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export { ElementMenu } from './element_menu'; -export { ElementMenu as ElementMenuComponent } from './element_menu.component'; +export { ElementMenu } from './element_menu.component'; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx index f031d7c263199..b84e4faf2925e 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx @@ -27,6 +27,7 @@ import { ElementMenu } from './element_menu'; import { ShareMenu } from './share_menu'; import { ViewMenu } from './view_menu'; import { LabsControl } from './labs_control'; +import { EditorMenu } from './editor_menu'; const strings = { getFullScreenButtonAriaLabel: () => @@ -160,24 +161,22 @@ export const WorkpadHeader: FC = ({ + {isWriteable && ( + + + {{ + primaryActionButton: , + quickButtonGroup: , + addFromLibraryButton: , + extraButtons: [], + }} + + + )} - {isWriteable && ( - - - {{ - primaryActionButton: ( - - ), - quickButtonGroup: , - addFromLibraryButton: , - }} - - - )} @@ -192,6 +191,7 @@ export const WorkpadHeader: FC = ({ + diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 723d1afea2860..912055dd47a62 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -8,6 +8,7 @@ import { BehaviorSubject } from 'rxjs'; import type { SharePluginSetup } from 'src/plugins/share/public'; import { ChartsPluginSetup, ChartsPluginStart } from 'src/plugins/charts/public'; +import { VisualizationsStart } from 'src/plugins/visualizations/public'; import { ReportingStart } from '../../reporting/public'; import { CoreSetup, @@ -63,6 +64,7 @@ export interface CanvasStartDeps { charts: ChartsPluginStart; data: DataPublicPluginStart; presentationUtil: PresentationUtilPluginStart; + visualizations: VisualizationsStart; spaces?: SpacesPluginStart; } @@ -122,7 +124,12 @@ export class CanvasPlugin const { pluginServices } = await import('./services'); pluginServices.setRegistry( - pluginServiceRegistry.start({ coreStart, startPlugins, initContext: this.initContext }) + pluginServiceRegistry.start({ + coreStart, + startPlugins, + appUpdater: this.appUpdater, + initContext: this.initContext, + }) ); // Load application bundle diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts index 35e79b442a15d..bd9a4e7141c27 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts @@ -53,14 +53,24 @@ export const useWorkpad = ( workpad.aliasId = aliasId; } - dispatch(setAssets(assets)); - dispatch(setWorkpad(workpad, { loadPages })); - dispatch(setZoomScale(1)); + if (storedWorkpad.id !== workpadId || storedWorkpad.aliasId !== aliasId) { + dispatch(setAssets(assets)); + dispatch(setWorkpad(workpad, { loadPages })); + dispatch(setZoomScale(1)); + } } catch (e) { setError(e as Error | string); } })(); - }, [workpadId, dispatch, setError, loadPages, workpadResolve]); + }, [ + workpadId, + dispatch, + setError, + loadPages, + workpadResolve, + storedWorkpad.id, + storedWorkpad.aliasId, + ]); useEffect(() => { (() => { diff --git a/x-pack/plugins/canvas/public/services/embeddables.ts b/x-pack/plugins/canvas/public/services/embeddables.ts index 24d7a57e086f2..26b150b7a5349 100644 --- a/x-pack/plugins/canvas/public/services/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/embeddables.ts @@ -5,8 +5,12 @@ * 2.0. */ -import { EmbeddableFactory } from '../../../../../src/plugins/embeddable/public'; +import { + EmbeddableFactory, + EmbeddableStateTransfer, +} from '../../../../../src/plugins/embeddable/public'; export interface CanvasEmbeddablesService { getEmbeddableFactories: () => IterableIterator; + getStateTransfer: () => EmbeddableStateTransfer; } diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index f4292810b8089..ed55f919e4c76 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -17,6 +17,7 @@ import { CanvasNavLinkService } from './nav_link'; import { CanvasNotifyService } from './notify'; import { CanvasPlatformService } from './platform'; import { CanvasReportingService } from './reporting'; +import { CanvasVisualizationsService } from './visualizations'; import { CanvasWorkpadService } from './workpad'; export interface CanvasPluginServices { @@ -28,6 +29,7 @@ export interface CanvasPluginServices { notify: CanvasNotifyService; platform: CanvasPlatformService; reporting: CanvasReportingService; + visualizations: CanvasVisualizationsService; workpad: CanvasWorkpadService; } @@ -44,4 +46,6 @@ export const useNavLinkService = () => (() => pluginServices.getHooks().navLink. export const useNotifyService = () => (() => pluginServices.getHooks().notify.useService())(); export const usePlatformService = () => (() => pluginServices.getHooks().platform.useService())(); export const useReportingService = () => (() => pluginServices.getHooks().reporting.useService())(); +export const useVisualizationsService = () => + (() => pluginServices.getHooks().visualizations.useService())(); export const useWorkpadService = () => (() => pluginServices.getHooks().workpad.useService())(); diff --git a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts index 054b9da7409fb..8d1a86edab3d8 100644 --- a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts @@ -16,4 +16,5 @@ export type EmbeddablesServiceFactory = KibanaPluginServiceFactory< export const embeddablesServiceFactory: EmbeddablesServiceFactory = ({ startPlugins }) => ({ getEmbeddableFactories: startPlugins.embeddable.getEmbeddableFactories, + getStateTransfer: startPlugins.embeddable.getStateTransfer, }); diff --git a/x-pack/plugins/canvas/public/services/kibana/index.ts b/x-pack/plugins/canvas/public/services/kibana/index.ts index 1eb010e8d6f9d..91767947bc0a6 100644 --- a/x-pack/plugins/canvas/public/services/kibana/index.ts +++ b/x-pack/plugins/canvas/public/services/kibana/index.ts @@ -22,6 +22,7 @@ import { navLinkServiceFactory } from './nav_link'; import { notifyServiceFactory } from './notify'; import { platformServiceFactory } from './platform'; import { reportingServiceFactory } from './reporting'; +import { visualizationsServiceFactory } from './visualizations'; import { workpadServiceFactory } from './workpad'; export { customElementServiceFactory } from './custom_element'; @@ -31,6 +32,7 @@ export { labsServiceFactory } from './labs'; export { notifyServiceFactory } from './notify'; export { platformServiceFactory } from './platform'; export { reportingServiceFactory } from './reporting'; +export { visualizationsServiceFactory } from './visualizations'; export { workpadServiceFactory } from './workpad'; export const pluginServiceProviders: PluginServiceProviders< @@ -45,6 +47,7 @@ export const pluginServiceProviders: PluginServiceProviders< notify: new PluginServiceProvider(notifyServiceFactory), platform: new PluginServiceProvider(platformServiceFactory), reporting: new PluginServiceProvider(reportingServiceFactory), + visualizations: new PluginServiceProvider(visualizationsServiceFactory), workpad: new PluginServiceProvider(workpadServiceFactory), }; diff --git a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts b/x-pack/plugins/canvas/public/services/kibana/visualizations.ts new file mode 100644 index 0000000000000..e319ec1c1f427 --- /dev/null +++ b/x-pack/plugins/canvas/public/services/kibana/visualizations.ts @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaPluginServiceFactory } from '../../../../../../src/plugins/presentation_util/public'; +import { CanvasStartDeps } from '../../plugin'; +import { CanvasVisualizationsService } from '../visualizations'; + +export type VisualizationsServiceFactory = KibanaPluginServiceFactory< + CanvasVisualizationsService, + CanvasStartDeps +>; + +export const visualizationsServiceFactory: VisualizationsServiceFactory = ({ startPlugins }) => ({ + showNewVisModal: startPlugins.visualizations.showNewVisModal, + getByGroup: startPlugins.visualizations.getByGroup, + getAliases: startPlugins.visualizations.getAliases, +}); diff --git a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts index 173d27563e2b2..9c2cf4d0650ab 100644 --- a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts @@ -14,4 +14,5 @@ const noop = (..._args: any[]): any => {}; export const embeddablesServiceFactory: EmbeddablesServiceFactory = () => ({ getEmbeddableFactories: noop, + getStateTransfer: noop, }); diff --git a/x-pack/plugins/canvas/public/services/stubs/index.ts b/x-pack/plugins/canvas/public/services/stubs/index.ts index 06a5ff49e9c04..2216013a29c12 100644 --- a/x-pack/plugins/canvas/public/services/stubs/index.ts +++ b/x-pack/plugins/canvas/public/services/stubs/index.ts @@ -22,6 +22,7 @@ import { navLinkServiceFactory } from './nav_link'; import { notifyServiceFactory } from './notify'; import { platformServiceFactory } from './platform'; import { reportingServiceFactory } from './reporting'; +import { visualizationsServiceFactory } from './visualizations'; import { workpadServiceFactory } from './workpad'; export { customElementServiceFactory } from './custom_element'; @@ -31,6 +32,7 @@ export { navLinkServiceFactory } from './nav_link'; export { notifyServiceFactory } from './notify'; export { platformServiceFactory } from './platform'; export { reportingServiceFactory } from './reporting'; +export { visualizationsServiceFactory } from './visualizations'; export { workpadServiceFactory } from './workpad'; export const pluginServiceProviders: PluginServiceProviders = { @@ -42,6 +44,7 @@ export const pluginServiceProviders: PluginServiceProviders; + +const noop = (..._args: any[]): any => {}; + +export const visualizationsServiceFactory: VisualizationsServiceFactory = () => ({ + showNewVisModal: noop, + getByGroup: noop, + getAliases: noop, +}); diff --git a/x-pack/plugins/canvas/public/services/visualizations.ts b/x-pack/plugins/canvas/public/services/visualizations.ts new file mode 100644 index 0000000000000..c602b1dd39f3d --- /dev/null +++ b/x-pack/plugins/canvas/public/services/visualizations.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { VisualizationsStart } from '../../../../../src/plugins/visualizations/public'; + +export interface CanvasVisualizationsService { + showNewVisModal: VisualizationsStart['showNewVisModal']; + getByGroup: VisualizationsStart['getByGroup']; + getAliases: VisualizationsStart['getAliases']; +} diff --git a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts index 4cfdc7f21945f..092d4300d86b7 100644 --- a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts +++ b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts @@ -40,7 +40,7 @@ export const embeddableReducer = handleActions< const element = pageWithElement.elements.find((elem) => elem.id === elementId); - if (!element) { + if (!element || element.expression === embeddableExpression) { return workpadState; } diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 35b1d0025ea5f..ebe43ba76a46a 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -14,6 +14,7 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { HomeServerPluginSetup } from 'src/plugins/home/server'; +import { EmbeddableSetup } from 'src/plugins/embeddable/server'; import { ESSQL_SEARCH_STRATEGY } from '../common/lib/constants'; import { ReportingSetup } from '../../reporting/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; @@ -30,6 +31,7 @@ import { CanvasRouteHandlerContext, createWorkpadRouteContext } from './workpad_ interface PluginsSetup { expressions: ExpressionsServerSetup; + embeddable: EmbeddableSetup; features: FeaturesPluginSetup; home: HomeServerPluginSetup; bfetch: BfetchServerSetup; @@ -78,11 +80,16 @@ export class CanvasPlugin implements Plugin { plugins.home.sampleData.addAppLinksToSampleDataset ); - // we need the kibana index provided by global config for the Canvas usage collector - const globalConfig = this.initializerContext.config.legacy.get(); - registerCanvasUsageCollector(plugins.usageCollection, globalConfig.kibana.index); + // we need the kibana index for the Canvas usage collector + const kibanaIndex = coreSetup.savedObjects.getKibanaIndex(); + registerCanvasUsageCollector(plugins.usageCollection, kibanaIndex); - setupInterpreter(expressionsFork); + setupInterpreter(expressionsFork, { + embeddablePersistableStateService: { + extract: plugins.embeddable.extract, + inject: plugins.embeddable.inject, + }, + }); coreSetup.getStartServices().then(([_, depsStart]) => { const strategy = essqlSearchStrategyProvider(); diff --git a/x-pack/plugins/canvas/server/setup_interpreter.ts b/x-pack/plugins/canvas/server/setup_interpreter.ts index 2fe23eb86c086..849ad79717056 100644 --- a/x-pack/plugins/canvas/server/setup_interpreter.ts +++ b/x-pack/plugins/canvas/server/setup_interpreter.ts @@ -7,9 +7,15 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { functions } from '../canvas_plugin_src/functions/server'; -import { functions as externalFunctions } from '../canvas_plugin_src/functions/external'; +import { + initFunctions as initExternalFunctions, + InitializeArguments, +} from '../canvas_plugin_src/functions/external'; -export function setupInterpreter(expressions: ExpressionsServerSetup) { +export function setupInterpreter( + expressions: ExpressionsServerSetup, + dependencies: InitializeArguments +) { functions.forEach((f) => expressions.registerFunction(f)); - externalFunctions.forEach((f) => expressions.registerFunction(f)); + initExternalFunctions(dependencies).forEach((f) => expressions.registerFunction(f)); } diff --git a/x-pack/plugins/canvas/types/embeddables.ts b/x-pack/plugins/canvas/types/embeddables.ts new file mode 100644 index 0000000000000..b78efece59d8f --- /dev/null +++ b/x-pack/plugins/canvas/types/embeddables.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TimeRange } from 'src/plugins/data/public'; +import { Filter } from '@kbn/es-query'; +import { EmbeddableInput as Input } from '../../../../src/plugins/embeddable/common/'; + +export type EmbeddableInput = Input & { + timeRange?: TimeRange; + filters?: Filter[]; + savedObjectId?: string; +}; diff --git a/x-pack/plugins/canvas/types/functions.ts b/x-pack/plugins/canvas/types/functions.ts index 2569e0b10685b..c80102915ed95 100644 --- a/x-pack/plugins/canvas/types/functions.ts +++ b/x-pack/plugins/canvas/types/functions.ts @@ -10,8 +10,8 @@ import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; import { functions as commonFunctions } from '../canvas_plugin_src/functions/common'; import { functions as browserFunctions } from '../canvas_plugin_src/functions/browser'; import { functions as serverFunctions } from '../canvas_plugin_src/functions/server'; -import { functions as externalFunctions } from '../canvas_plugin_src/functions/external'; -import { initFunctions } from '../public/functions'; +import { initFunctions as initExternalFunctions } from '../canvas_plugin_src/functions/external'; +import { initFunctions as initClientFunctions } from '../public/functions'; /** * A `ExpressionFunctionFactory` is a powerful type used for any function that produces @@ -90,9 +90,11 @@ export type FunctionFactory = type CommonFunction = FunctionFactory; type BrowserFunction = FunctionFactory; type ServerFunction = FunctionFactory; -type ExternalFunction = FunctionFactory; +type ExternalFunction = FunctionFactory< + ReturnType extends Array ? U : never +>; type ClientFunctions = FunctionFactory< - ReturnType extends Array ? U : never + ReturnType extends Array ? U : never >; /** diff --git a/x-pack/plugins/canvas/types/index.ts b/x-pack/plugins/canvas/types/index.ts index 09ae1510be6da..930f337292088 100644 --- a/x-pack/plugins/canvas/types/index.ts +++ b/x-pack/plugins/canvas/types/index.ts @@ -9,6 +9,7 @@ export * from '../../../../src/plugins/expressions/common'; export * from './assets'; export * from './canvas'; export * from './elements'; +export * from './embeddables'; export * from './filters'; export * from './functions'; export * from './renderers'; diff --git a/x-pack/plugins/canvas/types/strategy.ts b/x-pack/plugins/canvas/types/strategy.ts index d7115a3e4372f..2cc4c72116cdb 100644 --- a/x-pack/plugins/canvas/types/strategy.ts +++ b/x-pack/plugins/canvas/types/strategy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; -import { estypes } from '@elastic/elasticsearch'; +import { TransportResult } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IKibanaSearchRequest } from 'src/plugins/data/common'; import { ExpressionValueFilter } from '.'; export interface EssqlSearchStrategyRequest extends IKibanaSearchRequest { @@ -27,5 +27,5 @@ export interface EssqlSearchStrategyResponse { }>; rows: any[]; - rawResponse: ApiResponse; + rawResponse: TransportResult; } diff --git a/x-pack/plugins/cases/common/api/connectors/index.ts b/x-pack/plugins/cases/common/api/connectors/index.ts index 2b3483b4f6184..fcd48511849d6 100644 --- a/x-pack/plugins/cases/common/api/connectors/index.ts +++ b/x-pack/plugins/cases/common/api/connectors/index.ts @@ -48,7 +48,7 @@ const ConnectorJiraTypeFieldsRt = rt.type({ fields: rt.union([JiraFieldsRT, rt.null]), }); -const ConnectorResillientTypeFieldsRt = rt.type({ +const ConnectorResilientTypeFieldsRt = rt.type({ type: rt.literal(ConnectorTypes.resilient), fields: rt.union([ResilientFieldsRT, rt.null]), }); @@ -78,7 +78,7 @@ export const noneConnectorId: string = 'none'; export const ConnectorTypeFieldsRt = rt.union([ ConnectorJiraTypeFieldsRt, ConnectorNoneTypeFieldsRt, - ConnectorResillientTypeFieldsRt, + ConnectorResilientTypeFieldsRt, ConnectorServiceNowITSMTypeFieldsRt, ConnectorServiceNowSIRTypeFieldsRt, ConnectorSwimlaneTypeFieldsRt, @@ -103,7 +103,7 @@ export type CaseUserActionConnector = rt.TypeOf; export type ConnectorTypeFields = rt.TypeOf; export type ConnectorJiraTypeFields = rt.TypeOf; -export type ConnectorResillientTypeFields = rt.TypeOf; +export type ConnectorResilientTypeFields = rt.TypeOf; export type ConnectorSwimlaneTypeFields = rt.TypeOf; export type ConnectorServiceNowITSMTypeFields = rt.TypeOf< typeof ConnectorServiceNowITSMTypeFieldsRt diff --git a/x-pack/plugins/cases/public/components/add_comment/index.test.tsx b/x-pack/plugins/cases/public/components/add_comment/index.test.tsx index 06a3897687921..c15722a3ec354 100644 --- a/x-pack/plugins/cases/public/components/add_comment/index.test.tsx +++ b/x-pack/plugins/cases/public/components/add_comment/index.test.tsx @@ -120,7 +120,7 @@ describe('AddComment ', () => { }); it('should insert a quote', async () => { - const sampleQuote = 'what a cool quote'; + const sampleQuote = 'what a cool quote \n with new lines'; const ref = React.createRef(); const wrapper = mount( @@ -138,10 +138,40 @@ describe('AddComment ', () => { }); expect(wrapper.find(`[data-test-subj="add-comment"] textarea`).text()).toBe( - `${sampleData.comment}\n\n${sampleQuote}` + `${sampleData.comment}\n\n> what a cool quote \n> with new lines \n\n` ); }); + it('should call onFocus when adding a quote', async () => { + const ref = React.createRef(); + + mount( + + + + ); + + ref.current!.editor!.textarea!.focus = jest.fn(); + await act(async () => { + ref.current!.addQuote('a comment'); + }); + + expect(ref.current!.editor!.textarea!.focus).toHaveBeenCalled(); + }); + + it('should NOT call onFocus on mount', async () => { + const ref = React.createRef(); + + mount( + + + + ); + + ref.current!.editor!.textarea!.focus = jest.fn(); + expect(ref.current!.editor!.textarea!.focus).not.toHaveBeenCalled(); + }); + it('it should insert a timeline', async () => { const useInsertTimelineMock = jest.fn(); let attachTimeline = noop; diff --git a/x-pack/plugins/cases/public/components/add_comment/index.tsx b/x-pack/plugins/cases/public/components/add_comment/index.tsx index f788456a30dff..3ee7c1604b24d 100644 --- a/x-pack/plugins/cases/public/components/add_comment/index.tsx +++ b/x-pack/plugins/cases/public/components/add_comment/index.tsx @@ -5,14 +5,22 @@ * 2.0. */ +import React, { + useCallback, + useRef, + forwardRef, + useImperativeHandle, + useEffect, + useState, +} from 'react'; import { EuiButton, EuiFlexItem, EuiFlexGroup, EuiLoadingSpinner } from '@elastic/eui'; -import React, { useCallback, useRef, forwardRef, useImperativeHandle } from 'react'; import styled from 'styled-components'; +import { isEmpty } from 'lodash'; import { CommentType } from '../../../common'; import { usePostComment } from '../../containers/use_post_comment'; import { Case } from '../../containers/types'; -import { MarkdownEditorForm } from '../markdown_editor'; +import { EuiMarkdownEditorRef, MarkdownEditorForm } from '../markdown_editor'; import { Form, useForm, UseField, useFormData } from '../../common/shared_imports'; import * as i18n from './translations'; @@ -33,6 +41,7 @@ const initialCommentValue: AddCommentFormSchema = { export interface AddCommentRefObject { addQuote: (quote: string) => void; setComment: (newComment: string) => void; + editor: EuiMarkdownEditorRef | null; } export interface AddCommentProps { @@ -61,7 +70,8 @@ export const AddComment = React.memo( }, ref ) => { - const editorRef = useRef(); + const editorRef = useRef(null); + const [focusOnContext, setFocusOnContext] = useState(false); const owner = useOwnerContext(); const { isLoading, postComment } = usePostComment(); @@ -77,7 +87,10 @@ export const AddComment = React.memo( const addQuote = useCallback( (quote) => { - setFieldValue(fieldName, `${comment}${comment.length > 0 ? '\n\n' : ''}${quote}`); + const addCarrots = quote.replace(new RegExp('\r?\n', 'g'), '\n> '); + const val = `> ${addCarrots} \n\n`; + setFieldValue(fieldName, `${comment}${comment.length > 0 ? '\n\n' : ''}${val}`); + setFocusOnContext(true); }, [comment, setFieldValue] ); @@ -111,6 +124,38 @@ export const AddComment = React.memo( } }, [submit, onCommentSaving, postComment, caseId, owner, onCommentPosted, subCaseId, reset]); + /** + * Focus on the text area when a quote has been added. + * + * The useEffect will run only when focusOnContext + * changes. + * + * The useEffect is also called once one mount + * where the comment is empty. We do not want to focus + * in this scenario. + * + * Ideally we would like to put the + * editorRef.current?.textarea?.focus(); inside the if (focusOnContext). + * The reason this is not feasible is because when it sets the + * focusOnContext to false a render will occur again and the + * focus will be lost. + * + * We do not put the comment in the dependency list + * because we do not want to focus when the user + * is typing. + */ + + useEffect(() => { + if (!isEmpty(comment)) { + editorRef.current?.textarea?.focus(); + } + + if (focusOnContext) { + setFocusOnContext(false); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [focusOnContext]); + return ( {isLoading && showLoading && } diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx index 4e0f1689bd4d1..9bbddfae2f9bd 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx @@ -123,11 +123,11 @@ describe('Connectors', () => { ).toBe('Update My Connector'); }); - test('it shows the deprecated callout when the connector is legacy', async () => { + test('it shows the deprecated callout when the connector is deprecated', async () => { render( , { // wrapper: TestProviders produces a TS error diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx index 1b575e3ba9334..b7bf7c322f76e 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx @@ -23,7 +23,7 @@ import { ActionConnector, CaseConnectorMapping } from '../../containers/configur import { Mapping } from './mapping'; import { ActionTypeConnector, ConnectorTypes } from '../../../common'; import { DeprecatedCallout } from '../connectors/deprecated_callout'; -import { isLegacyConnector } from '../utils'; +import { isDeprecatedConnector } from '../utils'; const EuiFormRowExtended = styled(EuiFormRow)` .euiFormRow__labelWrapper { @@ -111,7 +111,7 @@ const ConnectorsComponent: React.FC = ({ appendAddConnectorButton={true} /> - {selectedConnector.type !== ConnectorTypes.none && isLegacyConnector(connector) && ( + {selectedConnector.type !== ConnectorTypes.none && isDeprecatedConnector(connector) && ( diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx index 6f05f9f940d25..03ed3d6512638 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx @@ -171,7 +171,7 @@ describe('ConnectorsDropdown', () => { "value": "servicenow-sir", }, Object { - "data-test-subj": "dropdown-connector-servicenow-legacy", + "data-test-subj": "dropdown-connector-servicenow-uses-table-api", "inputDisplay": { /> , - "value": "servicenow-legacy", + "value": "servicenow-uses-table-api", }, ] `); @@ -288,8 +288,8 @@ describe('ConnectorsDropdown', () => { ).not.toThrowError(); }); - test('it shows the deprecated tooltip when the connector is legacy', () => { - render(, { + test('it shows the deprecated tooltip when the connector is deprecated', () => { + render(, { wrapper: ({ children }) => {children}, }); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx index c5fe9c7470745..c7ce3c5b3c4b6 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx @@ -13,7 +13,7 @@ import { ConnectorTypes } from '../../../common'; import { ActionConnector } from '../../containers/configure/types'; import * as i18n from './translations'; import { useKibana } from '../../common/lib/kibana'; -import { getConnectorIcon, isLegacyConnector } from '../utils'; +import { getConnectorIcon, isDeprecatedConnector } from '../utils'; import { euiStyled } from '../../../../../../src/plugins/kibana_react/common'; export interface Props { @@ -95,10 +95,10 @@ const ConnectorsDropdownComponent: React.FC = ({ {connector.name} - {isLegacyConnector(connector) && ` (${i18n.DEPRECATED_TOOLTIP_TEXT})`} + {isDeprecatedConnector(connector) && ` (${i18n.DEPRECATED_TOOLTIP_TEXT})`} - {isLegacyConnector(connector) && ( + {isDeprecatedConnector(connector) && ( { }); }); -describe('closure options', () => { +// Failing: See https://github.com/elastic/kibana/issues/115366 +describe.skip('closure options', () => { let wrapper: ReactWrapper; let persistCaseConfigure: jest.Mock; diff --git a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.test.tsx b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.test.tsx index 367609df3c887..690a9331c568f 100644 --- a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.test.tsx @@ -14,14 +14,14 @@ describe('DeprecatedCallout', () => { render(); expect(screen.getByText('This connector type is deprecated')).toBeInTheDocument(); expect(screen.getByText('Update this connector, or create a new one.')).toBeInTheDocument(); - expect(screen.getByTestId('legacy-connector-warning-callout')).toHaveClass( + expect(screen.getByTestId('deprecated-connector-warning-callout')).toHaveClass( 'euiCallOut euiCallOut--warning' ); }); test('it renders a danger flyout correctly', () => { render(); - expect(screen.getByTestId('legacy-connector-warning-callout')).toHaveClass( + expect(screen.getByTestId('deprecated-connector-warning-callout')).toHaveClass( 'euiCallOut euiCallOut--danger' ); }); diff --git a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx index 9337f2843506b..195b2deb84d6e 100644 --- a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx +++ b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx @@ -9,15 +9,15 @@ import React from 'react'; import { EuiCallOut, EuiCallOutProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -const LEGACY_CONNECTOR_WARNING_TITLE = i18n.translate( - 'xpack.cases.connectors.serviceNow.legacyConnectorWarningTitle', +const DEPRECATED_CONNECTOR_WARNING_TITLE = i18n.translate( + 'xpack.cases.connectors.serviceNow.deprecatedConnectorWarningTitle', { defaultMessage: 'This connector type is deprecated', } ); -const LEGACY_CONNECTOR_WARNING_DESC = i18n.translate( - 'xpack.cases.connectors.serviceNow.legacyConnectorWarningDesc', +const DEPRECATED_CONNECTOR_WARNING_DESC = i18n.translate( + 'xpack.cases.connectors.serviceNow.deprecatedConnectorWarningDesc', { defaultMessage: 'Update this connector, or create a new one.', } @@ -29,12 +29,12 @@ interface Props { const DeprecatedCalloutComponent: React.FC = ({ type = 'warning' }) => ( - {LEGACY_CONNECTOR_WARNING_DESC} + {DEPRECATED_CONNECTOR_WARNING_DESC} ); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx index 008340b6b7e97..324dcef8ba397 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx @@ -127,15 +127,15 @@ describe('ServiceNowITSM Fields', () => { ); }); - test('it shows the deprecated callout when the connector is legacy', async () => { - const legacyConnector = { ...connector, config: { isLegacy: true } }; - render(); - expect(screen.getByTestId('legacy-connector-warning-callout')).toBeInTheDocument(); + test('it shows the deprecated callout when the connector uses the table API', async () => { + const tableApiConnector = { ...connector, config: { usesTableApi: true } }; + render(); + expect(screen.getByTestId('deprecated-connector-warning-callout')).toBeInTheDocument(); }); - test('it does not show the deprecated callout when the connector is not legacy', async () => { + test('it does not show the deprecated callout when the connector does not uses the table API', async () => { render(); - expect(screen.queryByTestId('legacy-connector-warning-callout')).not.toBeInTheDocument(); + expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument(); }); describe('onChange calls', () => { diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx index aac78b8266fb5..cd8f5f4abf7b5 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx @@ -161,15 +161,15 @@ describe('ServiceNowSIR Fields', () => { ]); }); - test('it shows the deprecated callout when the connector is legacy', async () => { - const legacyConnector = { ...connector, config: { isLegacy: true } }; - render(); - expect(screen.getByTestId('legacy-connector-warning-callout')).toBeInTheDocument(); + test('it shows the deprecated callout when the connector uses the table API', async () => { + const tableApiConnector = { ...connector, config: { usesTableApi: true } }; + render(); + expect(screen.getByTestId('deprecated-connector-warning-callout')).toBeInTheDocument(); }); - test('it does not show the deprecated callout when the connector is not legacy', async () => { + test('it does not show the deprecated callout when the connector does not uses the table API', async () => { render(); - expect(screen.queryByTestId('legacy-connector-warning-callout')).not.toBeInTheDocument(); + expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument(); }); describe('onChange calls', () => { diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/validator.test.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/validator.test.ts index c098d803276bc..aa643191ac62e 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/validator.test.ts +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/validator.test.ts @@ -10,24 +10,24 @@ import { connectorValidator } from './validator'; describe('ServiceNow validator', () => { describe('connectorValidator', () => { - test('it returns an error message if the connector is legacy', () => { + test('it returns an error message if the connector uses the table API', () => { const invalidConnector = { ...connector, config: { ...connector.config, - isLegacy: true, + usesTableApi: true, }, }; expect(connectorValidator(invalidConnector)).toEqual({ message: 'Deprecated connector' }); }); - test('it does not returns an error message if the connector is not legacy', () => { + test('it does not returns an error message if the connector does not uses the table API', () => { const invalidConnector = { ...connector, config: { ...connector.config, - isLegacy: false, + usesTableApi: false, }, }; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/validator.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/validator.ts index 3f67f25549343..7d56163c48350 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/validator.ts +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/validator.ts @@ -9,16 +9,16 @@ import { ValidationConfig } from '../../../common/shared_imports'; import { CaseActionConnector } from '../../types'; /** - * The user can not use a legacy connector + * The user can not create cases with connectors that use the table API */ export const connectorValidator = ( connector: CaseActionConnector ): ReturnType => { const { - config: { isLegacy }, + config: { usesTableApi }, } = connector; - if (isLegacy) { + if (usesTableApi) { return { message: 'Deprecated connector', }; diff --git a/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx b/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx index f2351a2b2d793..4bf25b23403e1 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx @@ -37,7 +37,7 @@ interface MarkdownEditorProps { value: string; } -type EuiMarkdownEditorRef = ElementRef; +export type EuiMarkdownEditorRef = ElementRef; export interface MarkdownEditorRef { textarea: HTMLTextAreaElement | null; diff --git a/x-pack/plugins/cases/public/components/user_action_tree/index.test.tsx b/x-pack/plugins/cases/public/components/user_action_tree/index.test.tsx index dd5c993939b82..5241b0e66fb38 100644 --- a/x-pack/plugins/cases/public/components/user_action_tree/index.test.tsx +++ b/x-pack/plugins/cases/public/components/user_action_tree/index.test.tsx @@ -348,7 +348,7 @@ describe(`UserActionTree`, () => { .first() .simulate('click'); await waitFor(() => { - expect(setFieldValue).toBeCalledWith('comment', `> ${props.data.description} \n`); + expect(setFieldValue).toBeCalledWith('comment', `> ${props.data.description} \n\n`); }); }); diff --git a/x-pack/plugins/cases/public/components/user_action_tree/index.tsx b/x-pack/plugins/cases/public/components/user_action_tree/index.tsx index 7ea415324194c..92640a34548e8 100644 --- a/x-pack/plugins/cases/public/components/user_action_tree/index.tsx +++ b/x-pack/plugins/cases/public/components/user_action_tree/index.tsx @@ -226,10 +226,8 @@ export const UserActionTree = React.memo( const handleManageQuote = useCallback( (quote: string) => { - const addCarrots = quote.replace(new RegExp('\r?\n', 'g'), ' \n> '); - if (commentRefs.current[NEW_ID]) { - commentRefs.current[NEW_ID].addQuote(`> ${addCarrots} \n`); + commentRefs.current[NEW_ID].addQuote(quote); } handleOutlineComment('add-comment'); diff --git a/x-pack/plugins/cases/public/components/utils.ts b/x-pack/plugins/cases/public/components/utils.ts index ac5f4dbdd298e..74137789958a4 100644 --- a/x-pack/plugins/cases/public/components/utils.ts +++ b/x-pack/plugins/cases/public/components/utils.ts @@ -78,7 +78,7 @@ export const getConnectorIcon = ( }; // TODO: Remove when the applications are certified -export const isLegacyConnector = (connector?: CaseActionConnector) => { +export const isDeprecatedConnector = (connector?: CaseActionConnector): boolean => { if (connector == null) { return true; } @@ -91,5 +91,16 @@ export const isLegacyConnector = (connector?: CaseActionConnector) => { return true; } - return connector.config.isLegacy; + /** + * Connector's prior to the Elastic ServiceNow application + * use the Table API (https://developer.servicenow.com/dev.do#!/reference/api/rome/rest/c_TableAPI) + * Connectors after the Elastic ServiceNow application use the + * Import Set API (https://developer.servicenow.com/dev.do#!/reference/api/rome/rest/c_ImportSetAPI) + * A ServiceNow connector is considered deprecated if it uses the Table API. + * + * All other connectors do not have the usesTableApi config property + * so the function will always return false for them. + */ + + return !!connector.config.usesTableApi; }; diff --git a/x-pack/plugins/cases/public/containers/configure/mock.ts b/x-pack/plugins/cases/public/containers/configure/mock.ts index d1ae7f310a719..a5483e524e92d 100644 --- a/x-pack/plugins/cases/public/containers/configure/mock.ts +++ b/x-pack/plugins/cases/public/containers/configure/mock.ts @@ -72,12 +72,12 @@ export const connectorsMock: ActionConnector[] = [ isPreconfigured: false, }, { - id: 'servicenow-legacy', + id: 'servicenow-uses-table-api', actionTypeId: '.servicenow', name: 'My Connector', config: { apiUrl: 'https://instance1.service-now.com', - isLegacy: true, + usesTableApi: true, }, isPreconfigured: false, }, diff --git a/x-pack/plugins/cases/server/connectors/resilient/format.ts b/x-pack/plugins/cases/server/connectors/resilient/format.ts index 821c9b214a26e..ba82e2e8d1ea3 100644 --- a/x-pack/plugins/cases/server/connectors/resilient/format.ts +++ b/x-pack/plugins/cases/server/connectors/resilient/format.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { ConnectorResillientTypeFields } from '../../../common'; +import { ConnectorResilientTypeFields } from '../../../common'; import { Format } from './types'; export const format: Format = (theCase, alerts) => { const { incidentTypes = null, severityCode = null } = - (theCase.connector.fields as ConnectorResillientTypeFields['fields']) ?? {}; + (theCase.connector.fields as ConnectorResilientTypeFields['fields']) ?? {}; return { incidentTypes, severityCode }; }; diff --git a/x-pack/plugins/cases/server/services/alerts/index.test.ts b/x-pack/plugins/cases/server/services/alerts/index.test.ts index d7dd44b33628b..9113b73de187a 100644 --- a/x-pack/plugins/cases/server/services/alerts/index.test.ts +++ b/x-pack/plugins/cases/server/services/alerts/index.test.ts @@ -113,8 +113,8 @@ describe('updateAlertsStatus', () => { }, "script": Object { "lang": "painless", - "source": "if (ctx._source['kibana.alert.workflow_status'] != null) { - ctx._source['kibana.alert.workflow_status'] = 'acknowledged' + "source": "if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null) { + ctx._source['${ALERT_WORKFLOW_STATUS}'] = 'acknowledged' } if (ctx._source.signal != null && ctx._source.signal.status != null) { ctx._source.signal.status = 'acknowledged' @@ -156,8 +156,8 @@ describe('updateAlertsStatus', () => { }, "script": Object { "lang": "painless", - "source": "if (ctx._source['kibana.alert.workflow_status'] != null) { - ctx._source['kibana.alert.workflow_status'] = 'closed' + "source": "if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null) { + ctx._source['${ALERT_WORKFLOW_STATUS}'] = 'closed' } if (ctx._source.signal != null && ctx._source.signal.status != null) { ctx._source.signal.status = 'closed' @@ -185,8 +185,8 @@ describe('updateAlertsStatus', () => { }, "script": Object { "lang": "painless", - "source": "if (ctx._source['kibana.alert.workflow_status'] != null) { - ctx._source['kibana.alert.workflow_status'] = 'open' + "source": "if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null) { + ctx._source['${ALERT_WORKFLOW_STATUS}'] = 'open' } if (ctx._source.signal != null && ctx._source.signal.status != null) { ctx._source.signal.status = 'open' @@ -228,8 +228,8 @@ describe('updateAlertsStatus', () => { }, "script": Object { "lang": "painless", - "source": "if (ctx._source['kibana.alert.workflow_status'] != null) { - ctx._source['kibana.alert.workflow_status'] = 'closed' + "source": "if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null) { + ctx._source['${ALERT_WORKFLOW_STATUS}'] = 'closed' } if (ctx._source.signal != null && ctx._source.signal.status != null) { ctx._source.signal.status = 'closed' @@ -257,8 +257,8 @@ describe('updateAlertsStatus', () => { }, "script": Object { "lang": "painless", - "source": "if (ctx._source['kibana.alert.workflow_status'] != null) { - ctx._source['kibana.alert.workflow_status'] = 'open' + "source": "if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null) { + ctx._source['${ALERT_WORKFLOW_STATUS}'] = 'open' } if (ctx._source.signal != null && ctx._source.signal.status != null) { ctx._source.signal.status = 'open' diff --git a/x-pack/plugins/cases/server/services/cases/index.ts b/x-pack/plugins/cases/server/services/cases/index.ts index 3c76be6d6dd93..4a22793f78af5 100644 --- a/x-pack/plugins/cases/server/services/cases/index.ts +++ b/x-pack/plugins/cases/server/services/cases/index.ts @@ -19,7 +19,7 @@ import { SavedObjectsResolveResponse, } from 'kibana/server'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { nodeBuilder, KueryNode } from '../../../../../../src/plugins/data/common'; import { SecurityPluginSetup } from '../../../../security/server'; diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx index af0a1a583e447..d21b72b85f8d5 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx @@ -7,13 +7,7 @@ import React, { ReactNode } from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n/react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { UrlGeneratorsStart } from '../../../../../../../src/plugins/share/public/url_generators'; export function LocaleWrapper({ children }: { children?: ReactNode }) { return {children}; } - -export const mockUrls = { - getUrlGenerator: (id: string) => ({ createUrl: () => `hello-cool-${id}-url` }), -} as unknown as UrlGeneratorsStart; diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx index a2d51d7d21248..7f5117740f38c 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx @@ -49,7 +49,7 @@ export class SearchSessionsMgmtApp { const { sessionsClient } = data.search; const api = new SearchSessionsMgmtAPI(sessionsClient, this.config, { notifications, - urls: share.urlGenerators, + locators: share.url.locators, application, usageCollector: pluginsSetup.data.search.usageCollector, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx index 4c945e717464c..b79a4939b3fdd 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx @@ -16,13 +16,16 @@ import { SessionsClient } from 'src/plugins/data/public/search'; import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '..'; import { SearchSessionsMgmtAPI } from '../lib/api'; import { AsyncSearchIntroDocumentation } from '../lib/documentation'; -import { LocaleWrapper, mockUrls } from '../__mocks__'; +import { LocaleWrapper } from '../__mocks__'; import { SearchSessionsMgmtMain } from './main'; import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -32,6 +35,7 @@ describe('Background Search Session Management Main', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -49,7 +53,7 @@ describe('Background Search Session Management Main', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx index f3079155f7eb5..863e5e85d9ef3 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx @@ -16,13 +16,16 @@ import { SessionsClient } from 'src/plugins/data/public/search'; import { SearchSessionStatus } from '../../../../../../../../src/plugins/data/common'; import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../../'; import { SearchSessionsMgmtAPI } from '../../lib/api'; -import { LocaleWrapper, mockUrls } from '../../__mocks__'; +import { LocaleWrapper } from '../../__mocks__'; import { SearchSessionsMgmtTable } from './table'; import { dataPluginMock } from '../../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: CoreStart; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -32,6 +35,7 @@ describe('Background Search Session Management Table', () => { beforeEach(async () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -48,7 +52,7 @@ describe('Background Search Session Management Table', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts index a3bc3b51f61bd..a0b6aa80f2500 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts @@ -14,11 +14,13 @@ import type { SavedObjectsFindResponse } from 'src/core/server'; import { SessionsClient } from 'src/plugins/data/public/search'; import type { SessionsConfigSchema } from '../'; import { SearchSessionStatus } from '../../../../../../../src/plugins/data/common'; -import { mockUrls } from '../__mocks__'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { SearchSessionsMgmtAPI } from './api'; let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; +let mockShareStart: jest.Mocked; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -26,6 +28,7 @@ describe('Search Sessions Management API', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockConfig = { defaultExpiration: moment.duration('7d'), management: { @@ -60,7 +63,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -80,9 +83,9 @@ describe('Search Sessions Management API', () => { "initialState": Object {}, "name": "Veggie", "numSearches": 0, - "reloadUrl": "hello-cool-undefined-url", + "reloadUrl": undefined, "restoreState": Object {}, - "restoreUrl": "hello-cool-undefined-url", + "restoreUrl": undefined, "status": "complete", "version": undefined, }, @@ -111,7 +114,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -124,7 +127,7 @@ describe('Search Sessions Management API', () => { sessionsClient.find = jest.fn().mockRejectedValue(new Error('implementation is so bad')); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -153,7 +156,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -181,7 +184,7 @@ describe('Search Sessions Management API', () => { test('send cancel calls the cancel endpoint with a session ID', async () => { const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -196,7 +199,7 @@ describe('Search Sessions Management API', () => { sessionsClient.delete = jest.fn().mockRejectedValue(new Error('implementation is so bad')); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -225,7 +228,7 @@ describe('Search Sessions Management API', () => { test('send extend throws an error for now', async () => { const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -238,7 +241,7 @@ describe('Search Sessions Management API', () => { test('displays error on reject', async () => { sessionsClient.extend = jest.fn().mockRejectedValue({}); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts index 01b64dcaf8a85..fbd7f472177cb 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts @@ -11,6 +11,7 @@ import moment from 'moment'; import { from, race, timer } from 'rxjs'; import { mapTo, tap } from 'rxjs/operators'; import type { SharePluginStart } from 'src/plugins/share/public'; +import { SerializableRecord } from '@kbn/utility-types'; import { ISessionsClient, SearchUsageCollector, @@ -24,7 +25,7 @@ import { } from '../types'; import { SessionsConfigSchema } from '..'; -type UrlGeneratorsStart = SharePluginStart['urlGenerators']; +type LocatorsStart = SharePluginStart['url']['locators']; function getActions(status: UISearchSessionState) { const actions: ACTION[] = []; @@ -61,26 +62,21 @@ function getUIStatus(session: PersistedSearchSessionSavedObjectAttributes): UISe return session.status; } -async function getUrlFromState( - urls: UrlGeneratorsStart, - urlGeneratorId: string, - state: Record -) { - let url = '/'; +function getUrlFromState(locators: LocatorsStart, locatorId: string, state: SerializableRecord) { try { - url = await urls.getUrlGenerator(urlGeneratorId).createUrl(state); + const locator = locators.get(locatorId); + return locator?.getRedirectUrl(state); } catch (err) { // eslint-disable-next-line no-console console.error('Could not create URL from restoreState'); // eslint-disable-next-line no-console console.error(err); } - return url; } // Helper: factory for a function to map server objects to UI objects const mapToUISession = - (urls: UrlGeneratorsStart, config: SessionsConfigSchema) => + (locators: LocatorsStart, config: SessionsConfigSchema) => async ( savedObject: SavedObject ): Promise => { @@ -89,7 +85,7 @@ const mapToUISession = appId, created, expires, - urlGeneratorId, + locatorId, initialState, restoreState, idMapping, @@ -102,8 +98,8 @@ const mapToUISession = // TODO: initialState should be saved without the searchSessionID if (initialState) delete initialState.searchSessionId; // derive the URL and add it in - const reloadUrl = await getUrlFromState(urls, urlGeneratorId, initialState); - const restoreUrl = await getUrlFromState(urls, urlGeneratorId, restoreState); + const reloadUrl = await getUrlFromState(locators, locatorId, initialState); + const restoreUrl = await getUrlFromState(locators, locatorId, restoreState); return { id: savedObject.id, @@ -113,8 +109,8 @@ const mapToUISession = expires, status, actions, - restoreUrl, - reloadUrl, + restoreUrl: restoreUrl!, + reloadUrl: reloadUrl!, initialState, restoreState, numSearches: Object.keys(idMapping).length, @@ -123,7 +119,7 @@ const mapToUISession = }; interface SearchSessionManagementDeps { - urls: UrlGeneratorsStart; + locators: LocatorsStart; notifications: NotificationsStart; application: ApplicationStart; usageCollector?: SearchUsageCollector; @@ -174,7 +170,7 @@ export class SearchSessionsMgmtAPI { const savedObjects = result.saved_objects as Array< SavedObject >; - return await Promise.all(savedObjects.map(mapToUISession(this.deps.urls, this.config))); + return await Promise.all(savedObjects.map(mapToUISession(this.deps.locators, this.config))); } } catch (err) { // eslint-disable-next-line no-console diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx index 4764e273e5a68..9578d56e44b1c 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx @@ -17,14 +17,16 @@ import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../'; import { SearchSessionStatus } from '../../../../../../../src/plugins/data/common'; import { OnActionComplete } from '../components'; import { UISession } from '../types'; -import { mockUrls } from '../__mocks__'; import { SearchSessionsMgmtAPI } from './api'; import { getColumns } from './get_columns'; import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: CoreStart; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let api: SearchSessionsMgmtAPI; @@ -38,6 +40,7 @@ describe('Search Sessions Management table column factory', () => { beforeEach(async () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -54,7 +57,7 @@ describe('Search Sessions Management table column factory', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts index f4f928e67e19c..7489a1ce26aa5 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts @@ -21,7 +21,7 @@ export type PersistedSearchSessionSavedObjectAttributes = SearchSessionSavedObje Required< Pick< SearchSessionSavedObjectAttributes, - 'name' | 'appId' | 'urlGeneratorId' | 'initialState' | 'restoreState' + 'name' | 'appId' | 'locatorId' | 'initialState' | 'restoreState' > >; diff --git a/x-pack/plugins/data_enhanced/server/collectors/fetch.test.ts b/x-pack/plugins/data_enhanced/server/collectors/fetch.test.ts index 380cc0e354502..47e6fb05c2329 100644 --- a/x-pack/plugins/data_enhanced/server/collectors/fetch.test.ts +++ b/x-pack/plugins/data_enhanced/server/collectors/fetch.test.ts @@ -6,12 +6,10 @@ */ import { - SharedGlobalConfig, ElasticsearchClient, SavedObjectsErrorHelpers, Logger, } from '../../../../../src/core/server'; -import { BehaviorSubject } from 'rxjs'; import { fetchProvider } from './fetch'; import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks'; @@ -21,17 +19,13 @@ describe('fetchProvider', () => { let mockLogger: Logger; beforeEach(async () => { - const config$ = new BehaviorSubject({ - kibana: { - index: '123', - }, - } as any); + const kibanaIndex = '123'; mockLogger = { warn: jest.fn(), debug: jest.fn(), } as any; esClient = elasticsearchServiceMock.createElasticsearchClient(); - fetchFn = fetchProvider(config$, mockLogger); + fetchFn = fetchProvider(kibanaIndex, mockLogger); }); test('returns when ES returns no results', async () => { diff --git a/x-pack/plugins/data_enhanced/server/collectors/fetch.ts b/x-pack/plugins/data_enhanced/server/collectors/fetch.ts index 27f72986dd537..f60d6f32871d3 100644 --- a/x-pack/plugins/data_enhanced/server/collectors/fetch.ts +++ b/x-pack/plugins/data_enhanced/server/collectors/fetch.ts @@ -4,10 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; -import { SharedGlobalConfig, Logger } from 'kibana/server'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { Logger } from 'kibana/server'; import { CollectorFetchContext } from '../../../../../src/plugins/usage_collection/server'; import { SEARCH_SESSION_TYPE } from '../../../../../src/plugins/data/common'; import { ReportedUsage } from './register'; @@ -17,12 +15,11 @@ interface SessionPersistedTermsBucket { doc_count: number; } -export function fetchProvider(config$: Observable, logger: Logger) { +export function fetchProvider(kibanaIndex: string, logger: Logger) { return async ({ esClient }: CollectorFetchContext): Promise => { try { - const config = await config$.pipe(first()).toPromise(); const { body: esResponse } = await esClient.search({ - index: config.kibana.index, + index: kibanaIndex, body: { size: 0, aggs: { diff --git a/x-pack/plugins/data_enhanced/server/collectors/register.ts b/x-pack/plugins/data_enhanced/server/collectors/register.ts index fe96b7f7ced1b..6e482a618a292 100644 --- a/x-pack/plugins/data_enhanced/server/collectors/register.ts +++ b/x-pack/plugins/data_enhanced/server/collectors/register.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginInitializerContext, Logger } from 'kibana/server'; +import { Logger } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { fetchProvider } from './fetch'; @@ -15,16 +15,16 @@ export interface ReportedUsage { totalCount: number; } -export async function registerUsageCollector( +export function registerUsageCollector( usageCollection: UsageCollectionSetup, - context: PluginInitializerContext, + kibanaIndex: string, logger: Logger ) { try { const collector = usageCollection.makeUsageCollector({ type: 'search-session', isReady: () => true, - fetch: fetchProvider(context.config.legacy.globalConfig$, logger), + fetch: fetchProvider(kibanaIndex, logger), schema: { transientCount: { type: 'long' }, persistedCount: { type: 'long' }, diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index 60a5de6323f50..28df0a5aa70cf 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -53,7 +53,7 @@ export class EnhancedDataServerPlugin }); if (deps.usageCollection) { - registerUsageCollector(deps.usageCollection, this.initializerContext, this.logger); + registerUsageCollector(deps.usageCollection, core.savedObjects.getKibanaIndex(), this.logger); } } diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index 3e293aa82dc83..3f36bd0a75746 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -22,7 +22,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: name: schema.string(), appId: schema.string(), expires: schema.maybe(schema.string()), - urlGeneratorId: schema.string(), + locatorId: schema.string(), initialState: schema.maybe(schema.object({}, { unknowns: 'allow' })), restoreState: schema.maybe(schema.object({}, { unknowns: 'allow' })), }), @@ -32,7 +32,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: }, }, async (context, request, res) => { - const { sessionId, name, expires, initialState, restoreState, appId, urlGeneratorId } = + const { sessionId, name, expires, initialState, restoreState, appId, locatorId } = request.body; try { @@ -40,7 +40,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: name, appId, expires, - urlGeneratorId, + locatorId, initialState, restoreState, }); diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts index 9a359679c0e7a..f921ed78eb247 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts @@ -42,7 +42,7 @@ export const searchSessionSavedObjectType: SavedObjectsType = { appId: { type: 'keyword', }, - urlGeneratorId: { + locatorId: { type: 'keyword', }, initialState: { diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts index cdb86772482fe..aa344da68f931 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts @@ -9,6 +9,7 @@ import { searchSessionSavedObjectMigrations, SearchSessionSavedObjectAttributesPre$7$13$0, SearchSessionSavedObjectAttributesPre$7$14$0, + SearchSessionSavedObjectAttributesPre$8$0$0, } from './search_session_migration'; import { SavedObject } from '../../../../../src/core/types'; import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../../../src/plugins/data/common'; @@ -164,3 +165,193 @@ describe('7.13.0 -> 7.14.0', () => { `); }); }); + +describe('7.14.0 -> 8.0.0', () => { + const migration = searchSessionSavedObjectMigrations['8.0.0']; + + test('Discover app URL generator migrates to locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'DISCOVER_APP_URL_GENERATOR', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": "DISCOVER_APP_LOCATOR", + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Dashboard app URL generator migrates to locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'DASHBOARD_APP_URL_GENERATOR', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": "DASHBOARD_APP_LOCATOR", + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Undefined URL generator returns undefined locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: undefined, + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": undefined, + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Other URL generator throws error', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'my_url_generator_id', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + expect(() => + migration(mockSessionSavedObject, {} as SavedObjectMigrationContext) + ).toThrowErrorMatchingInlineSnapshot( + `"No migration found for search session URL generator my_url_generator_id"` + ); + }); +}); diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts index fa1428b3a3aad..4fa5964929f7c 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts @@ -29,10 +29,28 @@ export type SearchSessionSavedObjectAttributesPre$7$13$0 = Omit< * but what is important for 7.14.0 is that the version is less then "7.14.0" */ export type SearchSessionSavedObjectAttributesPre$7$14$0 = Omit< - SearchSessionSavedObjectAttributesLatest, + SearchSessionSavedObjectAttributesPre$8$0$0, 'version' >; +/** + * In 8.0.0, we migrated from using URL generators to the locators service. As a result, we move + * from using `urlGeneratorId` to `locatorId`. + */ +export type SearchSessionSavedObjectAttributesPre$8$0$0 = Omit< + SearchSessionSavedObjectAttributesLatest, + 'locatorId' +> & { + urlGeneratorId?: string; +}; + +function getLocatorId(urlGeneratorId?: string) { + if (!urlGeneratorId) return; + if (urlGeneratorId === 'DISCOVER_APP_URL_GENERATOR') return 'DISCOVER_APP_LOCATOR'; + if (urlGeneratorId === 'DASHBOARD_APP_URL_GENERATOR') return 'DASHBOARD_APP_LOCATOR'; + throw new Error(`No migration found for search session URL generator ${urlGeneratorId}`); +} + export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { '7.13.0': ( doc: SavedObjectUnsanitizedDoc @@ -60,4 +78,14 @@ export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { }, }; }, + '8.0.0': ( + doc: SavedObjectUnsanitizedDoc + ): SavedObjectUnsanitizedDoc => { + const { + attributes: { urlGeneratorId, ...otherAttrs }, + } = doc; + const locatorId = getLocatorId(urlGeneratorId); + const attributes = { ...otherAttrs, locatorId }; + return { ...doc, attributes }; + }, }; diff --git a/x-pack/plugins/data_enhanced/server/search/session/get_search_status.ts b/x-pack/plugins/data_enhanced/server/search/session/get_search_status.ts index 461c41b46491c..a49dc30b84fb5 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/get_search_status.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/get_search_status.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { ElasticsearchClient } from 'src/core/server'; import { SearchStatus } from './types'; import { SearchSessionRequestInfo } from '../../../../../../src/plugins/data/common'; @@ -19,9 +19,11 @@ export async function getSearchStatus( // TODO: Handle strategies other than the default one try { // @ts-expect-error start_time_in_millis: EpochMillis is string | number - const apiResponse: ApiResponse = await client.asyncSearch.status({ - id: asyncId, - }); + const apiResponse: TransportResult = await client.asyncSearch.status( + { + id: asyncId, + } + ); const response = apiResponse.body; if ((response.is_partial && !response.is_running) || response.completion_status >= 400) { return { diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 4b5e1a1f86a11..437e146f0d0f7 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -57,7 +57,7 @@ describe('SearchSessionService', () => { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', idMapping: {}, realmType: mockUser1.authentication_realm.type, realmName: mockUser1.authentication_realm.name, @@ -202,13 +202,13 @@ describe('SearchSessionService', () => { ).rejects.toMatchInlineSnapshot(`[Error: AppId is required]`); }); - it('throws if `generator id` is not provided', () => { + it('throws if `locatorId` is not provided', () => { expect( service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', }) - ).rejects.toMatchInlineSnapshot(`[Error: UrlGeneratorId is required]`); + ).rejects.toMatchInlineSnapshot(`[Error: locatorId is required]`); }); it('saving updates an existing saved object and persists it', async () => { @@ -222,7 +222,7 @@ describe('SearchSessionService', () => { await service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', - urlGeneratorId: 'panama', + locatorId: 'panama', }); expect(savedObjectsClient.update).toHaveBeenCalled(); @@ -236,7 +236,7 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); - expect(callAttributes).toHaveProperty('urlGeneratorId', 'panama'); + expect(callAttributes).toHaveProperty('locatorId', 'panama'); expect(callAttributes).toHaveProperty('initialState', {}); expect(callAttributes).toHaveProperty('restoreState', {}); }); @@ -255,7 +255,7 @@ describe('SearchSessionService', () => { await service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', - urlGeneratorId: 'panama', + locatorId: 'panama', }); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); @@ -271,7 +271,7 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); - expect(callAttributes).toHaveProperty('urlGeneratorId', 'panama'); + expect(callAttributes).toHaveProperty('locatorId', 'panama'); expect(callAttributes).toHaveProperty('initialState', {}); expect(callAttributes).toHaveProperty('restoreState', {}); expect(callAttributes).toHaveProperty('realmType', mockUser1.authentication_realm.type); @@ -300,7 +300,7 @@ describe('SearchSessionService', () => { { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', } ); diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 75f404d0f8790..84266e2545810 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -287,7 +287,7 @@ export class SearchSessionService { name, appId, - urlGeneratorId, + locatorId, initialState = {}, restoreState = {}, }: Partial @@ -295,12 +295,12 @@ export class SearchSessionService if (!this.sessionConfig.enabled) throw new Error('Search sessions are disabled'); if (!name) throw new Error('Name is required'); if (!appId) throw new Error('AppId is required'); - if (!urlGeneratorId) throw new Error('UrlGeneratorId is required'); + if (!locatorId) throw new Error('locatorId is required'); return this.updateOrCreate(deps, user, sessionId, { name, appId, - urlGeneratorId, + locatorId, initialState, restoreState, persisted: true, diff --git a/x-pack/plugins/data_visualizer/common/types/indices.ts b/x-pack/plugins/data_visualizer/common/types/indices.ts index c80b89b4e84c7..dd4bea8602720 100644 --- a/x-pack/plugins/data_visualizer/common/types/indices.ts +++ b/x-pack/plugins/data_visualizer/common/types/indices.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export interface IndicesOptions { allow_no_indices?: boolean; diff --git a/x-pack/plugins/data_visualizer/common/utils/datafeed_utils.ts b/x-pack/plugins/data_visualizer/common/utils/datafeed_utils.ts index bccd40ed43b0c..5a87d7b01db46 100644 --- a/x-pack/plugins/data_visualizer/common/utils/datafeed_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/datafeed_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type Datafeed = estypes.MlDatafeed; export type Aggregation = Record; diff --git a/x-pack/plugins/data_visualizer/common/utils/query_utils.ts b/x-pack/plugins/data_visualizer/common/utils/query_utils.ts index d2785072f419d..2aa4cd063d1b1 100644 --- a/x-pack/plugins/data_visualizer/common/utils/query_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/query_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /* * Contains utility functions for building and processing queries. */ diff --git a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts index fbe4ae5c6faf1..a088685f03f54 100644 --- a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from './object_utils'; import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts index 198079c6ec9de..f2d14de9812ca 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts @@ -6,7 +6,7 @@ */ import moment from 'moment'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Query, TimefilterContract } from 'src/plugins/data/public'; import dateMath from '@elastic/datemath'; import { IndexPattern } from '../../../../../../../../src/plugins/data/public'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/data_loader/data_loader.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/data_loader/data_loader.ts index c4db51dcd81bc..e0a2852a57b29 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/data_loader/data_loader.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/data_loader/data_loader.ts @@ -7,7 +7,7 @@ // Maximum number of examples to obtain for text type fields. import { CoreSetup } from 'kibana/public'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import { IndexPattern } from '../../../../../../../src/plugins/data/common'; import { NON_AGGREGATABLE_FIELD_TYPES, OMIT_FIELDS } from '../../../../common/constants'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/time_field_range.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/time_field_range.ts index 87d4a3b7fb711..58a4bd4520829 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/time_field_range.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/time_field_range.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { lazyLoadModules } from '../../../lazy_load_bundle'; import { GetTimeFieldRangeResponse } from '../../../../common/types/time_field_request'; import { Query } from '../../../../../../../src/plugins/data/common/query'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/visualizer_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/visualizer_stats.ts index 8db267a1dc837..3653936f3d12e 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/visualizer_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/services/visualizer_stats.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { lazyLoadModules } from '../../../lazy_load_bundle'; import type { DocumentCounts, FieldRequestConfig, FieldVisStats } from '../../../../common/types'; import { OverallStats } from '../types/overall_stats'; diff --git a/x-pack/plugins/data_visualizer/server/models/data_visualizer/check_fields_exist.ts b/x-pack/plugins/data_visualizer/server/models/data_visualizer/check_fields_exist.ts index f0cbffbfa70c3..24b4deeecdddd 100644 --- a/x-pack/plugins/data_visualizer/server/models/data_visualizer/check_fields_exist.ts +++ b/x-pack/plugins/data_visualizer/server/models/data_visualizer/check_fields_exist.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { get } from 'lodash'; import { IScopedClusterClient } from 'kibana/server'; import { AggCardinality, Aggs, FieldData } from '../../types'; diff --git a/x-pack/plugins/data_visualizer/server/models/data_visualizer/data_visualizer.ts b/x-pack/plugins/data_visualizer/server/models/data_visualizer/data_visualizer.ts index 003d5a7d86015..42e7f93cc8789 100644 --- a/x-pack/plugins/data_visualizer/server/models/data_visualizer/data_visualizer.ts +++ b/x-pack/plugins/data_visualizer/server/models/data_visualizer/data_visualizer.ts @@ -7,7 +7,7 @@ import { IScopedClusterClient } from 'kibana/server'; import { each, last } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { JOB_FIELD_TYPES } from '../../../common'; import type { BatchStats, diff --git a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_field_examples.ts b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_field_examples.ts index 69476e254068f..78adfb9e81b95 100644 --- a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_field_examples.ts +++ b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_field_examples.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { get } from 'lodash'; import { IScopedClusterClient } from 'kibana/server'; import { buildBaseFilterCriteria } from '../../../common/utils/query_utils'; diff --git a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_fields_stats.ts b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_fields_stats.ts index 6968aa97ab938..da93719e9ed93 100644 --- a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_fields_stats.ts +++ b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_fields_stats.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { each, find, get } from 'lodash'; import { IScopedClusterClient } from 'kibana/server'; import { diff --git a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_histogram_for_fields.ts b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_histogram_for_fields.ts index 6621c793c0017..1cbf40a22b056 100644 --- a/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_histogram_for_fields.ts +++ b/x-pack/plugins/data_visualizer/server/models/data_visualizer/get_histogram_for_fields.ts @@ -6,7 +6,7 @@ */ import { IScopedClusterClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { get } from 'lodash'; import { ChartData, ChartRequestAgg, HistogramField, NumericColumnStatsMap } from '../../types'; import { KBN_FIELD_TYPES } from '../../../../../../src/plugins/data/common'; diff --git a/x-pack/plugins/data_visualizer/server/routes/routes.ts b/x-pack/plugins/data_visualizer/server/routes/routes.ts index 74afae2634636..1ec2eaa242c1c 100644 --- a/x-pack/plugins/data_visualizer/server/routes/routes.ts +++ b/x-pack/plugins/data_visualizer/server/routes/routes.ts @@ -6,7 +6,7 @@ */ import type { CoreSetup, IScopedClusterClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { dataVisualizerFieldHistogramsSchema, dataVisualizerFieldStatsSchema, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.test.tsx index 78049d5832e9a..76622f9c12822 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.test.tsx @@ -87,6 +87,18 @@ describe('DomainsTable', () => { expect(tableContent).toContain('elastic.co'); }); + it('renders a clickable domain url', () => { + const basicTable = wrapper.find(EuiInMemoryTable).dive().find(EuiBasicTable).dive(); + const link = basicTable.find('[data-test-subj="CrawlerDomainURL"]').at(0); + + expect(link.dive().text()).toContain('elastic.co'); + expect(link.props()).toEqual( + expect.objectContaining({ + to: '/engines/some-engine/crawler/domains/1234', + }) + ); + }); + it('renders a last crawled column', () => { expect(tableContent).toContain('Last activity'); expect(tableContent).toContain('Jan 1, 2020'); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.tsx index 7214eace25e2d..1f0f6be22102f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/domains_table.tsx @@ -17,6 +17,7 @@ import { FormattedNumber } from '@kbn/i18n/react'; import { DELETE_BUTTON_LABEL, MANAGE_BUTTON_LABEL } from '../../../../shared/constants'; import { KibanaLogic } from '../../../../shared/kibana'; +import { EuiLinkTo } from '../../../../shared/react_router_helpers'; import { AppLogic } from '../../../app_logic'; import { ENGINE_CRAWLER_DOMAIN_PATH } from '../../../routes'; import { generateEnginePath } from '../../engine'; @@ -46,6 +47,14 @@ export const DomainsTable: React.FC = () => { defaultMessage: 'Domain URL', } ), + render: (_, domain: CrawlerDomain) => ( + + {domain.url} + + ), }, { field: 'lastCrawl', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx index 183d2b9cb7107..e851a594bc5a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx @@ -73,11 +73,8 @@ export const CurationsTable: React.FC = () => { truncateText: true, mobileOptions: { header: true, - // Note: the below props are valid props per https://elastic.github.io/eui/#/tabular-content/tables (Responsive tables), but EUI's types have a bug reporting it as an error - // @ts-ignore enlarge: true, width: '100%', - truncateText: false, }, }, { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx index 29418d09218f4..b1f02b960aa8a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx @@ -26,6 +26,10 @@ const MOCK_VALUES = { }, queries: ['some query'], }, + // EngineLogic + engine: { + search_relevance_suggestions_active: true, + }, }; describe('SuggestedDocumentsCallout', () => { @@ -40,7 +44,7 @@ describe('SuggestedDocumentsCallout', () => { expect(wrapper.is(SuggestionsCallout)); }); - it('is empty when the suggested is undefined', () => { + it('is empty when the suggestion is undefined', () => { setMockValues({ ...MOCK_VALUES, curation: {} }); const wrapper = shallow(); @@ -48,6 +52,15 @@ describe('SuggestedDocumentsCallout', () => { expect(wrapper.isEmptyRender()).toBe(true); }); + it('is empty when suggestions are not active', () => { + const values = set('engine.search_relevance_suggestions_active', false, MOCK_VALUES); + setMockValues(values); + + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); + it('is empty when curation status is not pending', () => { const values = set('curation.suggestion.status', 'applied', MOCK_VALUES); setMockValues(values); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx index e443e77d76190..af76ebee16bad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx @@ -11,7 +11,7 @@ import { useValues } from 'kea'; import { i18n } from '@kbn/i18n'; import { ENGINE_CURATION_SUGGESTION_PATH } from '../../../routes'; -import { generateEnginePath } from '../../engine'; +import { EngineLogic, generateEnginePath } from '../../engine'; import { SuggestionsCallout } from '../components/suggestions_callout'; @@ -21,8 +21,15 @@ export const SuggestedDocumentsCallout: React.FC = () => { const { curation: { suggestion, queries }, } = useValues(CurationLogic); - - if (typeof suggestion === 'undefined' || suggestion.status !== 'pending') { + const { + engine: { search_relevance_suggestions_active: searchRelevanceSuggestionsActive }, + } = useValues(EngineLogic); + + if ( + typeof suggestion === 'undefined' || + suggestion.status !== 'pending' || + searchRelevanceSuggestionsActive === false + ) { return null; } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx index 4e09dadc6c836..49d48c8c05ba6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx @@ -14,6 +14,8 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { set } from 'lodash/fp'; + import { EuiTab } from '@elastic/eui'; import { getPageHeaderTabs, getPageTitle } from '../../../../test_helpers'; @@ -51,8 +53,10 @@ describe('Curations', () => { curationsSettings: { enabled: true, }, - // LicensingLogic - hasPlatinumLicense: true, + // EngineLogic + engine: { + search_relevance_suggestions_active: true, + }, }; const actions = { @@ -84,8 +88,8 @@ describe('Curations', () => { expect(actions.onSelectPageTab).toHaveBeenNthCalledWith(3, 'settings'); }); - it('renders less tabs when less than platinum license', () => { - setMockValues({ ...values, hasPlatinumLicense: false }); + it('renders less tabs when suggestions are not active', () => { + setMockValues(set('engine.search_relevance_suggestions_active', false, values)); const wrapper = shallow(); expect(getPageTitle(wrapper)).toEqual('Curated results'); @@ -94,8 +98,8 @@ describe('Curations', () => { expect(tabs.length).toBe(2); }); - it('renders a New! badge when less than platinum license', () => { - setMockValues({ ...values, hasPlatinumLicense: false }); + it('renders a New! badge when suggestions are not active', () => { + setMockValues(set('engine.search_relevance_suggestions_active', false, values)); const wrapper = shallow(); expect(getPageTitle(wrapper)).toEqual('Curated results'); @@ -104,29 +108,8 @@ describe('Curations', () => { expect(tabs.at(1).prop('append')).not.toBeUndefined(); }); - it('renders a New! badge when suggestions are disabled', () => { - setMockValues({ - ...values, - curationsSettings: { - enabled: false, - }, - }); - const wrapper = shallow(); - - expect(getPageTitle(wrapper)).toEqual('Curated results'); - - const tabs = getPageHeaderTabs(wrapper).find(EuiTab); - expect(tabs.at(2).prop('append')).not.toBeUndefined(); - }); - - it('hides the badge when suggestions are enabled and the user has a platinum license', () => { - setMockValues({ - ...values, - hasPlatinumLicense: true, - curationsSettings: { - enabled: true, - }, - }); + it('hides the badge when suggestions are active', () => { + setMockValues(set('engine.search_relevance_suggestions_active', true, values)); const wrapper = shallow(); expect(getPageTitle(wrapper)).toEqual('Curated results'); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx index 1cd8313743536..2207555772b5b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx @@ -12,11 +12,10 @@ import { useValues, useActions } from 'kea'; import { EuiBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { LicensingLogic } from '../../../../shared/licensing'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; import { ENGINE_CURATIONS_NEW_PATH } from '../../../routes'; -import { generateEnginePath } from '../../engine'; +import { EngineLogic, generateEnginePath } from '../../engine'; import { AppSearchPageTemplate } from '../../layout'; import { CURATIONS_OVERVIEW_TITLE, CREATE_NEW_CURATION_TITLE } from '../constants'; @@ -30,13 +29,13 @@ import { CurationsSettings, CurationsSettingsLogic } from './curations_settings' export const Curations: React.FC = () => { const { dataLoading: curationsDataLoading, meta, selectedPageTab } = useValues(CurationsLogic); const { loadCurations, onSelectPageTab } = useActions(CurationsLogic); - const { hasPlatinumLicense } = useValues(LicensingLogic); const { - dataLoading: curationsSettingsDataLoading, - curationsSettings: { enabled: curationsSettingsEnabled }, - } = useValues(CurationsSettingsLogic); + engine: { search_relevance_suggestions_active: searchRelevanceSuggestionsActive }, + } = useValues(EngineLogic); - const suggestionsEnabled = hasPlatinumLicense && curationsSettingsEnabled; + const { dataLoading: curationsSettingsDataLoading } = useValues(CurationsSettingsLogic); + + const suggestionsEnabled = searchRelevanceSuggestionsActive; const OVERVIEW_TAB = { label: i18n.translate( @@ -75,7 +74,7 @@ export const Curations: React.FC = () => { ), }; - const pageTabs = hasPlatinumLicense + const pageTabs = searchRelevanceSuggestionsActive ? [OVERVIEW_TAB, HISTORY_TAB, SETTINGS_TAB] : [OVERVIEW_TAB, SETTINGS_TAB]; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx index 809157704a14e..43ef9dfd7ad2b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx @@ -12,6 +12,7 @@ import '../../../__mocks__/engine_logic.mock'; import React from 'react'; import { shallow } from 'enzyme'; +import { set } from 'lodash/fp'; import { CurationsTable, EmptyState } from '../components'; @@ -33,8 +34,10 @@ const MOCK_VALUES = { id: 'cur-id-2', }, ], - // LicensingLogics - hasPlatinumLicense: true, + // EngineLogic + engine: { + search_relevance_suggestions_active: true, + }, }; describe('CurationsOverview', () => { @@ -67,36 +70,15 @@ describe('CurationsOverview', () => { expect(wrapper.find(CurationsTable)).toHaveLength(1); }); - it('renders a suggestions table when the user has a platinum license and curations suggestions enabled', () => { - setMockValues({ - ...MOCK_VALUES, - hasPlatinumLicense: true, - curationsSettings: { - enabled: true, - }, - }); + it('renders a suggestions table when suggestions are active', () => { + setMockValues(set('engine.search_relevance_suggestions_active', true, MOCK_VALUES)); const wrapper = shallow(); expect(wrapper.find(SuggestionsTable).exists()).toBe(true); }); - it('doesn\t render a suggestions table when the user has no platinum license', () => { - setMockValues({ - ...MOCK_VALUES, - hasPlatinumLicense: false, - }); - const wrapper = shallow(); - - expect(wrapper.find(SuggestionsTable).exists()).toBe(false); - }); - - it('doesn\t render a suggestions table when the user has disabled suggestions', () => { - setMockValues({ - ...MOCK_VALUES, - curationsSettings: { - enabled: false, - }, - }); + it('doesn\t render a suggestions table when suggestions are not active', () => { + setMockValues(set('engine.search_relevance_suggestions_active', false, MOCK_VALUES)); const wrapper = shallow(); expect(wrapper.find(SuggestionsTable).exists()).toBe(false); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx index 00593403b08cf..a611ca88cefd4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx @@ -11,22 +11,18 @@ import { useValues } from 'kea'; import { EuiSpacer } from '@elastic/eui'; -import { LicensingLogic } from '../../../../shared/licensing'; +import { EngineLogic } from '../../engine'; import { CurationsTable, EmptyState } from '../components'; import { SuggestionsTable } from '../components/suggestions_table'; import { CurationsLogic } from '../curations_logic'; -import { CurationsSettingsLogic } from './curations_settings'; - export const CurationsOverview: React.FC = () => { const { curations } = useValues(CurationsLogic); - const { hasPlatinumLicense } = useValues(LicensingLogic); - const { - curationsSettings: { enabled }, - } = useValues(CurationsSettingsLogic); + engine: { search_relevance_suggestions_active: searchRelevanceSuggestionsActive }, + } = useValues(EngineLogic); - const shouldShowSuggestions = enabled && hasPlatinumLicense; + const shouldShowSuggestions = searchRelevanceSuggestionsActive; return ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts index 818fac3d0706e..b8aae9c39174d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts @@ -12,8 +12,20 @@ import { } from '../../../../../__mocks__/kea_logic'; import '../../../../__mocks__/engine_logic.mock'; +jest.mock('../../curations_logic', () => ({ + CurationsLogic: { + values: {}, + actions: { + loadCurations: jest.fn(), + }, + }, +})); + import { nextTick } from '@kbn/test/jest'; +import { CurationsLogic } from '../..'; +import { EngineLogic } from '../../../engine'; + import { CurationsSettingsLogic } from './curations_settings_logic'; const DEFAULT_VALUES = { @@ -205,6 +217,10 @@ describe('CurationsSettingsLogic', () => { enabled: true, mode: 'automatic', }); + + // data should have been reloaded + expect(EngineLogic.actions.initializeEngine).toHaveBeenCalled(); + expect(CurationsLogic.actions.loadCurations).toHaveBeenCalled(); }); it('presents any API errors to the user', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.ts index d79ad64a69788..3984cbd024da4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.ts @@ -10,6 +10,7 @@ import { kea, MakeLogicType } from 'kea'; import { flashAPIErrors } from '../../../../../shared/flash_messages'; import { HttpLogic } from '../../../../../shared/http'; import { EngineLogic } from '../../../engine'; +import { CurationsLogic } from '../../curations_logic'; export interface CurationsSettings { enabled: boolean; @@ -101,6 +102,10 @@ export const CurationsSettingsLogic = kea< } ); actions.onCurationsSettingsLoad(response.curation); + + // Re-fetch data so that UI updates to new settings + CurationsLogic.actions.loadCurations(); + EngineLogic.actions.initializeEngine(); } catch (e) { flashAPIErrors(e); } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts index 28739a2799332..bb30190833dd3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts @@ -43,6 +43,7 @@ describe('EngineLogic', () => { schema: { test: SchemaType.Text }, apiTokens: [], apiKey: 'some-key', + search_relevance_suggestions_active: true, }; const DEFAULT_VALUES = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts index d4c652ab9c7a7..0bfbc185b85f3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts @@ -54,6 +54,7 @@ export interface EngineDetails extends Engine { engine_count?: number; includedEngines?: EngineDetails[]; search_relevance_suggestions?: SearchRelevanceSuggestionDetails; + search_relevance_suggestions_active: boolean; } interface ResultField { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx index 58e2cd8cf4c9b..c65d95a5254ee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx @@ -18,16 +18,14 @@ import { SuggestionsCallout } from '../../curations/components/suggestions_callo import { SuggestedCurationsCallout } from './suggested_curations_callout'; const MOCK_VALUES = { - // EngineLogic engine: { search_relevance_suggestions: { curation: { pending: 1, }, }, + search_relevance_suggestions_active: true, }, - // LicensingLogic - hasPlatinumLicense: true, }; describe('SuggestedCurationsCallout', () => { @@ -43,15 +41,20 @@ describe('SuggestedCurationsCallout', () => { }); it('is empty when the suggestions are undefined', () => { - setMockValues({ ...MOCK_VALUES, engine: {} }); + setMockValues({ + ...MOCK_VALUES, + engine: { + search_relevance_suggestions_active: true, + }, + }); const wrapper = shallow(); expect(wrapper.isEmptyRender()).toBe(true); }); - it('is empty when no pending curations', () => { - const values = set('engine.search_relevance_suggestions.curation.pending', 0, MOCK_VALUES); + it('is empty when suggestions are not active', () => { + const values = set('engine.search_relevance_suggestions_active', false, MOCK_VALUES); setMockValues(values); const wrapper = shallow(); @@ -59,9 +62,8 @@ describe('SuggestedCurationsCallout', () => { expect(wrapper.isEmptyRender()).toBe(true); }); - it('is empty when the user has no platinum license', () => { - // This would happen if the user *had* suggestions and then downgraded from platinum to gold or something - const values = set('hasPlatinumLicense', false, MOCK_VALUES); + it('is empty when no pending curations', () => { + const values = set('engine.search_relevance_suggestions.curation.pending', 0, MOCK_VALUES); setMockValues(values); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx index 046cc2d744b00..04b2d2b207e94 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx @@ -10,23 +10,24 @@ import { useValues } from 'kea'; import { i18n } from '@kbn/i18n'; -import { LicensingLogic } from '../../../../shared/licensing'; import { ENGINE_CURATIONS_PATH } from '../../../routes'; import { SuggestionsCallout } from '../../curations/components/suggestions_callout'; import { EngineLogic, generateEnginePath } from '../../engine'; export const SuggestedCurationsCallout: React.FC = () => { const { - engine: { search_relevance_suggestions: searchRelevanceSuggestions }, + engine: { + search_relevance_suggestions: searchRelevanceSuggestions, + search_relevance_suggestions_active: searchRelevanceSuggestionsActive, + }, } = useValues(EngineLogic); - const { hasPlatinumLicense } = useValues(LicensingLogic); const pendingCount = searchRelevanceSuggestions?.curation.pending; if ( typeof searchRelevanceSuggestions === 'undefined' || pendingCount === 0 || - hasPlatinumLicense === false + searchRelevanceSuggestionsActive === false ) { return null; } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/tables/shared_columns.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/tables/shared_columns.tsx index 3375b25cdcd6c..2c8fcfdbc54cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/tables/shared_columns.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/tables/shared_columns.tsx @@ -36,11 +36,8 @@ export const NAME_COLUMN: EuiTableFieldDataColumnType = { truncateText: true, mobileOptions: { header: true, - // Note: the below props are valid props per https://elastic.github.io/eui/#/tabular-content/tables (Responsive tables), but EUI's types have a bug reporting it as an error - // @ts-ignore enlarge: true, width: '100%', - truncateText: false, }, }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts index 48cbf4ba00d87..7222edad56822 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts @@ -376,7 +376,7 @@ export const exampleResult = { source: 'custom', }, ], - schemaFields: {}, + schemaFields: { cats: 'text', dogs: 'text' }, }; export const mostRecentIndexJob = { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/constants.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/constants.ts index a0df5337b2e2e..43da4ccef223a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/constants.ts @@ -267,6 +267,9 @@ export const SOURCE_OBJ_TYPES = { defaultMessage: 'Repository List', } ), + FILES: i18n.translate('xpack.enterpriseSearch.workplaceSearch.sources.objTypes.files', { + defaultMessage: 'Files (markdown only)', + }), EMAILS: i18n.translate('xpack.enterpriseSearch.workplaceSearch.sources.objTypes.emails', { defaultMessage: 'Emails', }), diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx index 5a15ef641be99..eeb7f6b54f2c0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx @@ -45,6 +45,7 @@ describe('ExampleResultDetailCard', () => { ...exampleResult, searchResultConfig: { detailFields: [{ fieldName: 'date', label: 'Date' }] }, exampleDocuments: [{ date }], + schemaFields: { date: 'date' }, }); const wrapper = shallow(); @@ -52,4 +53,17 @@ describe('ExampleResultDetailCard', () => { new Date(Date.parse(date)).toLocaleString() ); }); + + it('shows non-formatted value when not a date field', () => { + const value = '9999'; + setMockValues({ + ...exampleResult, + searchResultConfig: { detailFields: [{ fieldName: 'value', label: 'Value' }] }, + exampleDocuments: [{ value }], + schemaFields: { value: 'text' }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiText).children().text()).toContain(value); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx index 8b0a72ac23e39..734e370e4c53d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx @@ -12,6 +12,7 @@ import { useValues } from 'kea'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { SchemaType } from '../../../../../shared/schema/types'; import { URL_LABEL } from '../../../../constants'; import { getAsLocalDateTimeString } from '../../../../utils'; @@ -26,6 +27,7 @@ export const ExampleResultDetailCard: React.FC = () => { titleFieldHover, urlFieldHover, exampleDocuments, + schemaFields, } = useValues(DisplaySettingsLogic); const result = exampleDocuments[0]; @@ -63,7 +65,8 @@ export const ExampleResultDetailCard: React.FC = () => { {detailFields.length > 0 ? ( detailFields.map(({ fieldName, label }, index) => { const value = result[fieldName]; - const dateValue = getAsLocalDateTimeString(value); + const fieldType = (schemaFields as { [key: string]: SchemaType })[fieldName]; + const dateValue = fieldType === SchemaType.Date && getAsLocalDateTimeString(value); return (
{ - const { searchResultConfig, exampleDocuments } = exampleResult; + const { searchResultConfig, exampleDocuments, schemaFields } = exampleResult; const availableFieldOptions = [ { value: 'foo', @@ -70,6 +70,7 @@ describe('ResultDetail', () => { searchResultConfig, availableFieldOptions, exampleDocuments, + schemaFields, }); }); @@ -94,6 +95,7 @@ describe('ResultDetail', () => { }, availableFieldOptions, exampleDocuments, + schemaFields, }); const wrapper = shallow(); @@ -122,6 +124,7 @@ describe('ResultDetail', () => { }, availableFieldOptions, exampleDocuments, + schemaFields, }); const wrapper = mount(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx index 55694f1e797a2..3ff21566cf916 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx @@ -207,6 +207,7 @@ export const staticSourceData = [ SOURCE_OBJ_TYPES.ISSUES, SOURCE_OBJ_TYPES.PULL_REQUESTS, SOURCE_OBJ_TYPES.REPOSITORY_LIST, + SOURCE_OBJ_TYPES.FILES, ], features: { basicOrgContext: [ @@ -247,6 +248,7 @@ export const staticSourceData = [ SOURCE_OBJ_TYPES.ISSUES, SOURCE_OBJ_TYPES.PULL_REQUESTS, SOURCE_OBJ_TYPES.REPOSITORY_LIST, + SOURCE_OBJ_TYPES.FILES, ], features: { basicOrgContext: [ diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index f4140298928b6..314a6b9a31ef8 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -16,7 +16,8 @@ import { findOptionsSchema } from '../event_log_client'; import { delay } from '../lib/delay'; import { times } from 'lodash'; import { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { estypes, RequestEvent } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/types'; +import type { TransportResult } from '@elastic/elasticsearch'; type MockedLogger = ReturnType; @@ -399,9 +400,7 @@ describe('setIndexToHidden', () => { expect(clusterClient.indices.putSettings).toHaveBeenCalledWith({ index: 'foo-bar-000001', body: { - settings: { - 'index.hidden': true, - }, + 'index.hidden': true, }, }); }); @@ -1270,10 +1269,10 @@ type RetryableFunction = () => boolean; const RETRY_UNTIL_DEFAULT_COUNT = 20; const RETRY_UNTIL_DEFAULT_WAIT = 1000; // milliseconds -function asApiResponse(body: T): RequestEvent { +function asApiResponse(body: T): TransportResult { return { body, - } as RequestEvent; + } as TransportResult; } async function retryUntil( diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 7eb3328dddb6b..7246e1ed972ec 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -11,7 +11,7 @@ import { reject, isUndefined, isNumber, pick } from 'lodash'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, ElasticsearchClient } from 'src/core/server'; import util from 'util'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { IEvent, IValidatedEvent, SAVED_OBJECT_REL_PRIMARY } from '../types'; import { FindOptionsType } from '../event_log_client'; @@ -255,9 +255,7 @@ export class ClusterClientAdapter ({ version: '1.2.3' })); jest.mock('./init'); @@ -63,6 +63,7 @@ describe('createEsContext', () => { kibanaVersion: '1.2.3', elasticsearchClientPromise: Promise.resolve(elasticsearchClient), }); + elasticsearchClient.indices.existsTemplate.mockResolvedValue(asApiResponse(false)); elasticsearchClient.indices.existsIndexTemplate.mockResolvedValue(asApiResponse(false)); elasticsearchClient.indices.existsAlias.mockResolvedValue(asApiResponse(false)); @@ -113,8 +114,8 @@ describe('createEsContext', () => { }); }); -function asApiResponse(body: T): RequestEvent { +function asApiResponse(body: T): TransportResult { return { body, - } as RequestEvent; + } as TransportResult; } diff --git a/x-pack/plugins/event_log/server/es/init.ts b/x-pack/plugins/event_log/server/es/init.ts index f15b9f89887c5..7641404c484ce 100644 --- a/x-pack/plugins/event_log/server/es/init.ts +++ b/x-pack/plugins/event_log/server/es/init.ts @@ -5,8 +5,11 @@ * 2.0. */ -import { IndicesAlias, IndicesIndexStatePrefixedSettings } from '@elastic/elasticsearch/api/types'; -import { estypes } from '@elastic/elasticsearch'; +import { + IndicesAlias, + IndicesIndexStatePrefixedSettings, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { asyncForEach } from '@kbn/std'; import { getIlmPolicy, getIndexTemplate } from './documents'; import { EsContext } from './context'; diff --git a/x-pack/plugins/event_log/server/plugin.ts b/x-pack/plugins/event_log/server/plugin.ts index 77cad86cefdc6..83bd8582636dd 100644 --- a/x-pack/plugins/event_log/server/plugin.ts +++ b/x-pack/plugins/event_log/server/plugin.ts @@ -12,7 +12,6 @@ import { Plugin as CorePlugin, PluginInitializerContext, IClusterClient, - SharedGlobalConfig, IContextProvider, } from 'src/core/server'; import { SpacesPluginStart } from '../../spaces/server'; @@ -50,7 +49,6 @@ export class Plugin implements CorePlugin(); - this.globalConfig = this.context.config.legacy.get(); this.savedObjectProviderRegistry = new SavedObjectProviderRegistry(); this.kibanaVersion = this.context.env.packageInfo.version; } setup(core: CoreSetup): IEventLogService { - const kibanaIndex = this.globalConfig.kibana.index; + const kibanaIndex = core.savedObjects.getKibanaIndex(); this.systemLogger.debug('setting up plugin'); diff --git a/x-pack/plugins/file_upload/common/types.ts b/x-pack/plugins/file_upload/common/types.ts index 8462f8983a67d..6e72b749bdb61 100644 --- a/x-pack/plugins/file_upload/common/types.ts +++ b/x-pack/plugins/file_upload/common/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ES_FIELD_TYPES } from 'src/plugins/data/common'; export interface InputOverrides { diff --git a/x-pack/plugins/file_upload/server/get_time_field_range.ts b/x-pack/plugins/file_upload/server/get_time_field_range.ts index 0e8358f1671d0..1c8e94d5fc301 100644 --- a/x-pack/plugins/file_upload/server/get_time_field_range.ts +++ b/x-pack/plugins/file_upload/server/get_time_field_range.ts @@ -5,7 +5,7 @@ * 2.0. */ import { IScopedClusterClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from './utils/runtime_field_utils'; export async function getTimeFieldRange( diff --git a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts index aba6effe175c0..09a473b611ac9 100644 --- a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts +++ b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common'; type RuntimeType = typeof RUNTIME_FIELD_TYPES[number]; diff --git a/x-pack/plugins/fleet/common/openapi/README.md b/x-pack/plugins/fleet/common/openapi/README.md index 7ccccf052f37d..f0377deea15c8 100644 --- a/x-pack/plugins/fleet/common/openapi/README.md +++ b/x-pack/plugins/fleet/common/openapi/README.md @@ -1,6 +1,6 @@ -# OpenAPI +# OpenAPI (Experimental) -The current self-contained spec file is [as JSON](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.json) or [as YAML](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.yaml) and can be used for online tools like those found at https://openapi.tools/ +The current self-contained spec file is [as JSON](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.json) or [as YAML](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.yaml) and can be used for online tools like those found at https://openapi.tools/. This spec is experiemental and may be incomplete or change later. For example, online viewers for the specification like these: diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 6f107ae44bfa7..078281fec9806 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // Follow pattern from https://github.com/elastic/kibana/pull/52447 // TODO: Update when https://github.com/elastic/kibana/issues/53021 is closed import type { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx index b30d51bb46aaa..875180e5795c2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx @@ -553,7 +553,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { > diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx index 29c226ca64f57..e11aaabb4fd95 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx @@ -312,6 +312,34 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ /> + + + } + helpText={ + + {i18n.translate( + 'xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyDataRetentionLearnMoreLink', + { defaultMessage: 'Learn more' } + )} + + ), + }} + /> + } + > +
+ + {/* Advanced vars */} {advancedVars.map((varDef) => { const { name: varName, type: varType } = varDef; diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx index 48c8fa56fb91b..79175d241c29f 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx @@ -32,7 +32,8 @@ export const DeploymentDetails = () => { !( cname.endsWith('elastic-cloud.com') || cname.endsWith('found.io') || - cname.endsWith('found.no') + cname.endsWith('found.no') || + cname.endsWith('foundit.no') ) ) { return null; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx index 4f13a874532f1..f1d0717584e2e 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx @@ -231,6 +231,7 @@ export const AvailablePackages: React.FC = memo(() => { } href={addBasePath('/app/integrations/detail/endpoint/')} title={i18n.translate('xpack.fleet.featuredSecurityTitle', { @@ -246,6 +247,7 @@ export const AvailablePackages: React.FC = memo(() => { { } href={addBasePath('/app/enterprise_search/app_search')} title={i18n.translate('xpack.fleet.featuredSearchTitle', { diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 22f4b8cd6daab..6075b7e441fdf 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -6,6 +6,8 @@ */ /* eslint-disable max-classes-per-file */ +import type { ElasticsearchErrorDetails } from 'src/core/server'; + import { isESClientError } from './utils'; export { defaultIngestErrorHandler, ingestErrorToResponseOptions } from './handlers'; @@ -65,8 +67,8 @@ export class ArtifactsElasticsearchError extends IngestManagerError { constructor(public readonly meta: Error) { super( `${ - isESClientError(meta) && meta.meta.body?.error?.reason - ? meta.meta.body?.error?.reason + isESClientError(meta) && (meta.meta.body as ElasticsearchErrorDetails)?.error?.reason + ? (meta.meta.body as ElasticsearchErrorDetails)?.error?.reason : `Elasticsearch error while working with artifacts: ${meta.message}` }` ); diff --git a/x-pack/plugins/fleet/server/errors/utils.ts b/x-pack/plugins/fleet/server/errors/utils.ts index d58f82b94fcd7..23e92cdcd9f51 100644 --- a/x-pack/plugins/fleet/server/errors/utils.ts +++ b/x-pack/plugins/fleet/server/errors/utils.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; -export function isESClientError(error: unknown): error is ResponseError { - return error instanceof ResponseError; +export function isESClientError(error: unknown): error is errors.ResponseError { + return error instanceof errors.ResponseError; } export function isElasticsearchVersionConflictError(error: Error): boolean { diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index e6577426974a3..9300e0bb6c3e1 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -114,7 +114,6 @@ export const createMockAgentService = (): jest.Mocked => { return { getAgentStatusById: jest.fn(), getAgentStatusForAgentPolicy: jest.fn(), - authenticateAgentWithAccessToken: jest.fn(), getAgent: jest.fn(), listAgents: jest.fn(), }; diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index 8a95065380b69..410682a13733c 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -74,7 +74,6 @@ import { import { getAgentStatusById, getAgentStatusForAgentPolicy, - authenticateAgentWithAccessToken, getAgentsByKuery, getAgentById, } from './services/agents'; @@ -342,7 +341,6 @@ export class FleetPlugin listAgents: getAgentsByKuery, getAgentStatusById, getAgentStatusForAgentPolicy, - authenticateAgentWithAccessToken, }, agentPolicyService: { get: agentPolicyService.get, diff --git a/x-pack/plugins/fleet/server/routes/app/index.ts b/x-pack/plugins/fleet/server/routes/app/index.ts index 43614f3a286b0..e46e57d3838b4 100644 --- a/x-pack/plugins/fleet/server/routes/app/index.ts +++ b/x-pack/plugins/fleet/server/routes/app/index.ts @@ -48,7 +48,10 @@ export const getCheckPermissionsHandler: RequestHandler = async (context, reques export const generateServiceTokenHandler: RequestHandler = async (context, request, response) => { const esClient = context.core.elasticsearch.client.asCurrentUser; try { - const { body: tokenResponse } = await esClient.transport.request({ + const { body: tokenResponse } = await esClient.transport.request<{ + created?: boolean; + token?: GenerateServiceTokenResponse; + }>({ method: 'POST', path: `_security/service/elastic/fleet-server/credential/token/token-${Date.now()}`, }); diff --git a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts index 073ff7806d9fe..232df94d7610b 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { keyBy, keys, merge } from 'lodash'; -import type { RequestHandler, SavedObjectsBulkGetObject } from 'src/core/server'; +import type { RequestHandler } from 'src/core/server'; import type { DataStream } from '../../types'; import { KibanaSavedObjectType } from '../../../common'; @@ -15,7 +15,6 @@ import { getPackageSavedObjects } from '../../services/epm/packages/get'; import { defaultIngestErrorHandler } from '../../errors'; const DATA_STREAM_INDEX_PATTERN = 'logs-*-*,metrics-*-*,traces-*-*,synthetics-*-*'; - interface ESDataStreamInfo { name: string; timestamp_field: { @@ -94,17 +93,12 @@ export const getListHandler: RequestHandler = async (context, request, response) const allDashboardSavedObjectsResponse = await context.core.savedObjects.client.bulkGet<{ title?: string; }>( - Object.values(dashboardIdsByPackageName).reduce( - (allDashboards, dashboardIds) => { - return allDashboards.concat( - dashboardIds.map((id) => ({ - id, - type: KibanaSavedObjectType.dashboard, - fields: ['title'], - })) - ); - }, - [] + Object.values(dashboardIdsByPackageName).flatMap((dashboardIds) => + dashboardIds.map((id) => ({ + id, + type: KibanaSavedObjectType.dashboard, + fields: ['title'], + })) ) ); // Ignore dashboards not found @@ -142,12 +136,12 @@ export const getListHandler: RequestHandler = async (context, request, response) const { body: { aggregations: dataStreamAggs }, } = await esClient.search({ - index: dataStream.indices.map((index) => index.index_name), + index: dataStream.name, body: { size: 0, query: { bool: { - must: [ + filter: [ { exists: { field: 'data_stream.namespace', @@ -234,7 +228,7 @@ export const getListHandler: RequestHandler = async (context, request, response) return dataStreamResponse; }); - // Return final data streams objects sorted by last activity, decending + // Return final data streams objects sorted by last activity, descending // After filtering out data streams that are missing dataset/namespace/type fields body.data_streams = (await Promise.all(dataStreamPromises)) .filter(({ dataset, namespace, type }) => dataset && namespace && type) diff --git a/x-pack/plugins/fleet/server/services/agents/authenticate.test.ts b/x-pack/plugins/fleet/server/services/agents/authenticate.test.ts deleted file mode 100644 index eaa240165e853..0000000000000 --- a/x-pack/plugins/fleet/server/services/agents/authenticate.test.ts +++ /dev/null @@ -1,156 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { KibanaRequest } from 'kibana/server'; -import { elasticsearchServiceMock } from 'src/core/server/mocks'; - -import { authenticateAgentWithAccessToken } from './authenticate'; - -describe('test agent autenticate services', () => { - it('should succeed with a valid API key and an active agent', async () => { - const mockEsClient = elasticsearchServiceMock.createInternalClient(); - - mockEsClient.search.mockResolvedValue({ - body: { - hits: { - hits: [ - { - // @ts-expect-error - _id: 'agent1', - _source: { - // @ts-expect-error - active: true, - // @ts-expect-error - access_api_key_id: 'pedTuHIBTEDt93wW0Fhr', - }, - }, - ], - }, - }, - }); - await authenticateAgentWithAccessToken(mockEsClient, { - auth: { isAuthenticated: true }, - headers: { - authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==', - }, - } as KibanaRequest); - }); - - it('should throw if the request is not authenticated', async () => { - const mockEsClient = elasticsearchServiceMock.createInternalClient(); - - mockEsClient.search.mockResolvedValue({ - body: { - hits: { - hits: [ - { - // @ts-expect-error - _id: 'agent1', - _source: { - // @ts-expect-error - active: true, - // @ts-expect-error - access_api_key_id: 'pedTuHIBTEDt93wW0Fhr', - }, - }, - ], - }, - }, - }); - expect( - authenticateAgentWithAccessToken(mockEsClient, { - auth: { isAuthenticated: false }, - headers: { - authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==', - }, - } as KibanaRequest) - ).rejects.toThrow(/Request not authenticated/); - }); - - it('should throw if the ApiKey headers is malformed', async () => { - const mockEsClient = elasticsearchServiceMock.createInternalClient(); - - const hits = [ - { - _id: 'agent1', - _source: { - active: true, - - access_api_key_id: 'pedTuHIBTEDt93wW0Fhr', - }, - }, - ]; - - mockEsClient.search.mockResolvedValue({ - body: { - hits: { - // @ts-expect-error - hits, - }, - }, - }); - expect( - authenticateAgentWithAccessToken(mockEsClient, { - auth: { isAuthenticated: true }, - headers: { - authorization: 'aaaa', - }, - } as KibanaRequest) - ).rejects.toThrow(/Authorization header is malformed/); - }); - - it('should throw if the agent is not active', async () => { - const mockEsClient = elasticsearchServiceMock.createInternalClient(); - - const hits = [ - { - _id: 'agent1', - _source: { - active: false, - access_api_key_id: 'pedTuHIBTEDt93wW0Fhr', - }, - }, - ]; - mockEsClient.search.mockResolvedValue({ - body: { - hits: { - // @ts-expect-error - hits, - }, - }, - }); - expect( - authenticateAgentWithAccessToken(mockEsClient, { - auth: { isAuthenticated: true }, - headers: { - authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==', - }, - } as KibanaRequest) - ).rejects.toThrow(/Agent inactive/); - }); - - it('should throw if there is no agent matching the API key', async () => { - const mockEsClient = elasticsearchServiceMock.createInternalClient(); - - mockEsClient.search.mockResolvedValue({ - body: { - hits: { - // @ts-expect-error - hits: [], - }, - }, - }); - expect( - authenticateAgentWithAccessToken(mockEsClient, { - auth: { isAuthenticated: true }, - headers: { - authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==', - }, - } as KibanaRequest) - ).rejects.toThrow(/Agent not found/); - }); -}); diff --git a/x-pack/plugins/fleet/server/services/agents/authenticate.ts b/x-pack/plugins/fleet/server/services/agents/authenticate.ts deleted file mode 100644 index 0d0d520528dad..0000000000000 --- a/x-pack/plugins/fleet/server/services/agents/authenticate.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import Boom from '@hapi/boom'; -import type { KibanaRequest } from 'src/core/server'; -import type { ElasticsearchClient } from 'src/core/server'; - -import type { Agent } from '../../types'; -import * as APIKeyService from '../api_keys'; - -import { getAgentByAccessAPIKeyId } from './crud'; - -export async function authenticateAgentWithAccessToken( - esClient: ElasticsearchClient, - request: KibanaRequest -): Promise { - if (!request.auth.isAuthenticated) { - throw Boom.unauthorized('Request not authenticated'); - } - let res: { apiKey: string; apiKeyId: string }; - try { - res = APIKeyService.parseApiKeyFromHeaders(request.headers); - } catch (err) { - throw Boom.unauthorized(err.message); - } - - const agent = await getAgentByAccessAPIKeyId(esClient, res.apiKeyId); - - return agent; -} diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index 03647c52e05f0..b8d7c284309df 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; import type { KueryNode } from '@kbn/es-query'; @@ -126,10 +126,12 @@ export async function getAgentsByKuery( index: AGENTS_INDEX, from: (page - 1) * perPage, size: perPage, - sort: `${sortField}:${sortOrder}`, track_total_hits: true, ignore_unavailable: true, - body, + body: { + ...body, + sort: [{ [sortField]: { order: sortOrder } }], + }, }); let agents = res.body.hits.hits.map(searchHitToAgent); @@ -219,6 +221,7 @@ export function isAgentDocument( } export type ESAgentDocumentResult = estypes.MgetHit; + export async function getAgentDocuments( esClient: ElasticsearchClient, agentIds: string[] @@ -315,10 +318,9 @@ export async function bulkUpdateAgents( }); return { - items: res.body.items.map((item: estypes.BulkResponseItemContainer) => ({ + items: res.body.items.map((item) => ({ id: item.update!._id as string, success: !item.update!.error, - // @ts-expect-error ErrorCause is not assignable to Error error: item.update!.error as Error, })), }; diff --git a/x-pack/plugins/fleet/server/services/agents/helpers.ts b/x-pack/plugins/fleet/server/services/agents/helpers.ts index 195b2567c24ae..609d5ba6c83a0 100644 --- a/x-pack/plugins/fleet/server/services/agents/helpers.ts +++ b/x-pack/plugins/fleet/server/services/agents/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SearchHit } from '../../../../../../src/core/types/elasticsearch'; import type { Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; diff --git a/x-pack/plugins/fleet/server/services/agents/index.ts b/x-pack/plugins/fleet/server/services/agents/index.ts index ede548c6fd60d..9b2846b68364e 100644 --- a/x-pack/plugins/fleet/server/services/agents/index.ts +++ b/x-pack/plugins/fleet/server/services/agents/index.ts @@ -12,5 +12,4 @@ export * from './crud'; export * from './update'; export * from './actions'; export * from './reassign'; -export * from './authenticate'; export * from './setup'; diff --git a/x-pack/plugins/fleet/server/services/agents/reassign.test.ts b/x-pack/plugins/fleet/server/services/agents/reassign.test.ts index a87432c639249..71935ffa5f90c 100644 --- a/x-pack/plugins/fleet/server/services/agents/reassign.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/reassign.test.ts @@ -6,6 +6,7 @@ */ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SavedObject } from 'kibana/server'; import type { AgentPolicy } from '../../types'; @@ -47,7 +48,10 @@ describe('reassignAgent (singular)', () => { expect(esClient.update).toBeCalledTimes(1); const calledWith = esClient.update.mock.calls[0]; expect(calledWith[0]?.id).toBe(agentInRegularDoc._id); - expect(calledWith[0]?.body?.doc).toHaveProperty('policy_id', regularAgentPolicySO.id); + expect((calledWith[0] as estypes.UpdateRequest)?.body?.doc).toHaveProperty( + 'policy_id', + regularAgentPolicySO.id + ); }); it('cannot reassign from regular agent policy to hosted', async () => { @@ -85,7 +89,7 @@ describe('reassignAgents (plural)', () => { // calls ES update with correct values const calledWith = esClient.bulk.mock.calls[0][0]; // only 1 are regular and bulk write two line per update - expect(calledWith.body?.length).toBe(2); + expect((calledWith as estypes.BulkRequest).body?.length).toBe(2); // @ts-expect-error expect(calledWith.body[0].update._id).toEqual(agentInRegularDoc._id); }); diff --git a/x-pack/plugins/fleet/server/services/agents/unenroll.test.ts b/x-pack/plugins/fleet/server/services/agents/unenroll.test.ts index 3621bc5025ab3..7f744ba6a59f4 100644 --- a/x-pack/plugins/fleet/server/services/agents/unenroll.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/unenroll.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; import type { SavedObject } from 'kibana/server'; @@ -43,7 +43,9 @@ describe('unenrollAgent (singular)', () => { expect(esClient.update).toBeCalledTimes(1); const calledWith = esClient.update.mock.calls[0]; expect(calledWith[0]?.id).toBe(agentInRegularDoc._id); - expect(calledWith[0]?.body).toHaveProperty('doc.unenrollment_started_at'); + expect((calledWith[0] as estypes.UpdateRequest)?.body).toHaveProperty( + 'doc.unenrollment_started_at' + ); }); it('cannot unenroll from hosted agent policy by default', async () => { @@ -71,7 +73,9 @@ describe('unenrollAgent (singular)', () => { expect(esClient.update).toBeCalledTimes(1); const calledWith = esClient.update.mock.calls[0]; expect(calledWith[0]?.id).toBe(agentInHostedDoc._id); - expect(calledWith[0]?.body).toHaveProperty('doc.unenrollment_started_at'); + expect((calledWith[0] as estypes.UpdateRequest)?.body).toHaveProperty( + 'doc.unenrollment_started_at' + ); }); it('can unenroll from hosted agent policy with force=true and revoke=true', async () => { @@ -81,7 +85,7 @@ describe('unenrollAgent (singular)', () => { expect(esClient.update).toBeCalledTimes(1); const calledWith = esClient.update.mock.calls[0]; expect(calledWith[0]?.id).toBe(agentInHostedDoc._id); - expect(calledWith[0]?.body).toHaveProperty('doc.unenrolled_at'); + expect((calledWith[0] as estypes.UpdateRequest)?.body).toHaveProperty('doc.unenrolled_at'); }); }); @@ -93,10 +97,12 @@ describe('unenrollAgents (plural)', () => { // calls ES update with correct values const calledWith = esClient.bulk.mock.calls[1][0]; - const ids = calledWith?.body + const ids = (calledWith as estypes.BulkRequest)?.body ?.filter((i: any) => i.update !== undefined) .map((i: any) => i.update._id); - const docs = calledWith?.body?.filter((i: any) => i.doc).map((i: any) => i.doc); + const docs = (calledWith as estypes.BulkRequest)?.body + ?.filter((i: any) => i.doc) + .map((i: any) => i.doc); expect(ids).toEqual(idsToUnenroll); for (const doc of docs!) { expect(doc).toHaveProperty('unenrollment_started_at'); @@ -111,10 +117,12 @@ describe('unenrollAgents (plural)', () => { // calls ES update with correct values const onlyRegular = [agentInRegularDoc._id, agentInRegularDoc2._id]; const calledWith = esClient.bulk.mock.calls[1][0]; - const ids = calledWith?.body + const ids = (calledWith as estypes.BulkRequest)?.body ?.filter((i: any) => i.update !== undefined) .map((i: any) => i.update._id); - const docs = calledWith?.body?.filter((i: any) => i.doc).map((i: any) => i.doc); + const docs = (calledWith as estypes.BulkRequest)?.body + ?.filter((i: any) => i.doc) + .map((i: any) => i.doc); expect(ids).toEqual(onlyRegular); for (const doc of docs!) { expect(doc).toHaveProperty('unenrollment_started_at'); @@ -149,10 +157,12 @@ describe('unenrollAgents (plural)', () => { // calls ES update with correct values const onlyRegular = [agentInRegularDoc._id, agentInRegularDoc2._id]; const calledWith = esClient.bulk.mock.calls[0][0]; - const ids = calledWith?.body + const ids = (calledWith as estypes.BulkRequest)?.body ?.filter((i: any) => i.update !== undefined) .map((i: any) => i.update._id); - const docs = calledWith?.body?.filter((i: any) => i.doc).map((i: any) => i.doc); + const docs = (calledWith as estypes.BulkRequest)?.body + ?.filter((i: any) => i.doc) + .map((i: any) => i.doc); expect(ids).toEqual(onlyRegular); for (const doc of docs!) { expect(doc).toHaveProperty('unenrolled_at'); @@ -166,10 +176,12 @@ describe('unenrollAgents (plural)', () => { // calls ES update with correct values const calledWith = esClient.bulk.mock.calls[1][0]; - const ids = calledWith?.body + const ids = (calledWith as estypes.BulkRequest)?.body ?.filter((i: any) => i.update !== undefined) .map((i: any) => i.update._id); - const docs = calledWith?.body?.filter((i: any) => i.doc).map((i: any) => i.doc); + const docs = (calledWith as estypes.BulkRequest)?.body + ?.filter((i: any) => i.doc) + .map((i: any) => i.doc); expect(ids).toEqual(idsToUnenroll); for (const doc of docs!) { expect(doc).toHaveProperty('unenrollment_started_at'); @@ -204,10 +216,12 @@ describe('unenrollAgents (plural)', () => { // calls ES update with correct values const calledWith = esClient.bulk.mock.calls[0][0]; - const ids = calledWith?.body + const ids = (calledWith as estypes.BulkRequest)?.body ?.filter((i: any) => i.update !== undefined) .map((i: any) => i.update._id); - const docs = calledWith?.body?.filter((i: any) => i.doc).map((i: any) => i.doc); + const docs = (calledWith as estypes.BulkRequest)?.body + ?.filter((i: any) => i.doc) + .map((i: any) => i.doc); expect(ids).toEqual(idsToUnenroll); for (const doc of docs!) { expect(doc).toHaveProperty('unenrolled_at'); diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts index cc2357351f6df..166bd26e0d706 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts @@ -8,7 +8,7 @@ import uuid from 'uuid'; import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; import { toElasticsearchQuery, fromKueryExpression } from '@kbn/es-query'; @@ -42,10 +42,12 @@ export async function listEnrollmentApiKeys( index: ENROLLMENT_API_KEYS_INDEX, from: (page - 1) * perPage, size: perPage, - sort: 'created_at:desc', track_total_hits: true, ignore_unavailable: true, - body: query ? { query } : undefined, + body: { + sort: [{ created_at: { order: 'desc' } }], + ...(query ? { query } : {}), + }, }); // @ts-expect-error @elastic/elasticsearch _source is optional @@ -84,7 +86,7 @@ export async function getEnrollmentAPIKey( // @ts-expect-error esDocToEnrollmentApiKey doesn't accept optional _source return esDocToEnrollmentApiKey(res.body); } catch (e) { - if (e instanceof ResponseError && e.statusCode === 404) { + if (e instanceof errors.ResponseError && e.statusCode === 404) { throw Boom.notFound(`Enrollment api key ${id} not found`); } diff --git a/x-pack/plugins/fleet/server/services/artifacts/artifacts.test.ts b/x-pack/plugins/fleet/server/services/artifacts/artifacts.test.ts index b046b41d73722..a0e186aafb79a 100644 --- a/x-pack/plugins/fleet/server/services/artifacts/artifacts.test.ts +++ b/x-pack/plugins/fleet/server/services/artifacts/artifacts.test.ts @@ -7,9 +7,9 @@ import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; -import type { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; +import type { TransportResult } from '@elastic/elasticsearch'; import { FLEET_SERVER_ARTIFACTS_INDEX } from '../../../common'; @@ -43,6 +43,7 @@ describe('When using the artifacts services', () => { describe('and calling `getArtifact()`', () => { it('should get artifact using id', async () => { + // @ts-expect-error not full interface esClientMock.get.mockImplementation(() => { return elasticsearchServiceMock.createSuccessTransportRequestPromise( generateArtifactEsGetSingleHitMock() @@ -64,7 +65,7 @@ describe('When using the artifacts services', () => { it('should throw an ArtifactElasticsearchError if one is encountered', async () => { esClientMock.get.mockImplementation(() => { return elasticsearchServiceMock.createErrorTransportRequestPromise( - new ResponseError(generateEsRequestErrorApiResponseMock()) + new errors.ResponseError(generateEsRequestErrorApiResponseMock()) ); }); @@ -103,9 +104,8 @@ describe('When using the artifacts services', () => { }); it('should ignore 409 errors from elasticsearch', async () => { - const error = new ResponseError({ statusCode: 409 } as ApiResponse); + const error = new errors.ResponseError({ statusCode: 409 } as TransportResult); // Unclear why `mockRejectedValue()` has the params value type set to `never` - // @ts-expect-error esClientMock.create.mockRejectedValue(error); await expect(() => createArtifact(esClientMock, newArtifact)).not.toThrow(); }); @@ -140,6 +140,7 @@ describe('When using the artifacts services', () => { describe('and calling `listArtifacts()`', () => { beforeEach(() => { + // @ts-expect-error not full interface esClientMock.search.mockImplementation(() => { return elasticsearchServiceMock.createSuccessTransportRequestPromise( generateArtifactEsSearchResultHitsMock() @@ -152,11 +153,13 @@ describe('When using the artifacts services', () => { expect(esClientMock.search).toHaveBeenCalledWith({ index: FLEET_SERVER_ARTIFACTS_INDEX, - sort: 'created:asc', ignore_unavailable: true, q: '', from: 0, size: 20, + body: { + sort: [{ created: { order: 'asc' } }], + }, }); expect(results).toEqual({ @@ -184,11 +187,13 @@ describe('When using the artifacts services', () => { expect(esClientMock.search).toHaveBeenCalledWith({ index: FLEET_SERVER_ARTIFACTS_INDEX, - sort: 'identifier:desc', q: 'packageName:endpoint', ignore_unavailable: true, from: 450, size: 50, + body: { + sort: [{ identifier: { order: 'desc' } }], + }, }); expect(listMeta).toEqual({ diff --git a/x-pack/plugins/fleet/server/services/artifacts/artifacts.ts b/x-pack/plugins/fleet/server/services/artifacts/artifacts.ts index 6ac23cb1f9ef8..3a6db6fd0d04f 100644 --- a/x-pack/plugins/fleet/server/services/artifacts/artifacts.ts +++ b/x-pack/plugins/fleet/server/services/artifacts/artifacts.ts @@ -103,11 +103,13 @@ export const listArtifacts = async ( try { const searchResult = await esClient.search({ index: FLEET_SERVER_ARTIFACTS_INDEX, - sort: `${sortField}:${sortOrder}`, q: kuery, from: (page - 1) * perPage, ignore_unavailable: true, size: perPage, + body: { + sort: [{ [sortField]: { order: sortOrder } }], + }, }); return { diff --git a/x-pack/plugins/fleet/server/services/artifacts/client.test.ts b/x-pack/plugins/fleet/server/services/artifacts/client.test.ts index 470f1d4ce0a84..ae875df26371c 100644 --- a/x-pack/plugins/fleet/server/services/artifacts/client.test.ts +++ b/x-pack/plugins/fleet/server/services/artifacts/client.test.ts @@ -28,6 +28,7 @@ describe('When using the Fleet Artifacts Client', () => { singleHit._source.package_name = 'not endpoint'; } + // @ts-expect-error not full interface esClientMock.get.mockImplementation(() => { return elasticsearchServiceMock.createSuccessTransportRequestPromise(singleHit); }); @@ -104,6 +105,7 @@ describe('When using the Fleet Artifacts Client', () => { describe('and calling `listArtifacts()`', () => { beforeEach(() => { + // @ts-expect-error not full interface esClientMock.search.mockImplementation(() => { return elasticsearchServiceMock.createSuccessTransportRequestPromise( generateArtifactEsSearchResultHitsMock() diff --git a/x-pack/plugins/fleet/server/services/artifacts/mocks.ts b/x-pack/plugins/fleet/server/services/artifacts/mocks.ts index 2799e1807123d..bc22bff0b29d0 100644 --- a/x-pack/plugins/fleet/server/services/artifacts/mocks.ts +++ b/x-pack/plugins/fleet/server/services/artifacts/mocks.ts @@ -6,8 +6,8 @@ */ import { URL } from 'url'; -import type { ApiResponse } from '@elastic/elasticsearch'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import type { TransportResult } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; import { elasticsearchServiceMock } from '../../../../../../src/core/server/mocks'; import type { SearchHit, ESSearchResponse } from '../../../../../../src/core/types/elasticsearch'; @@ -69,7 +69,7 @@ export interface GenerateEsRequestErrorApiResponseMockProps { export const generateEsRequestErrorApiResponseMock = ( { statusCode = 500 }: GenerateEsRequestErrorApiResponseMockProps = { statusCode: 500 } -): ApiResponse => { +): TransportResult => { return generateEsApiResponseMock( { _index: '.fleet-artifacts_1', @@ -127,8 +127,8 @@ export const generateArtifactEsSearchResultHitsMock = (): ESSearchResponse< export const generateEsApiResponseMock = >( body: TBody, - otherProps: Partial> = {} -): ApiResponse => { + otherProps: Partial> = {} +): TransportResult => { return elasticsearchServiceMock.createApiResponse({ body, headers: { @@ -148,8 +148,6 @@ export const generateEsApiResponseMock = >( id: 7160, }, name: 'elasticsearch-js', - // There are some properties missing below which is not important for this mock - // @ts-ignore connection: { url: new URL('http://localhost:9200/'), id: 'http://localhost:9200/', @@ -158,6 +156,8 @@ export const generateEsApiResponseMock = >( resurrectTimeout: 0, _openRequests: 0, status: 'alive', + // There are some properties missing below which is not important for this mock + // @ts-expect-error roles: { master: true, data: true, @@ -182,7 +182,7 @@ export const setEsClientMethodResponseToError = ( ) => { esClientMock[method].mockImplementation(() => { return elasticsearchServiceMock.createErrorTransportRequestPromise( - new ResponseError(generateEsRequestErrorApiResponseMock(options)) + new errors.ResponseError(generateEsRequestErrorApiResponseMock(options)) ); }); }; diff --git a/x-pack/plugins/fleet/server/services/artifacts/utils.ts b/x-pack/plugins/fleet/server/services/artifacts/utils.ts index bce6b1a1e815b..e3b1be26165e8 100644 --- a/x-pack/plugins/fleet/server/services/artifacts/utils.ts +++ b/x-pack/plugins/fleet/server/services/artifacts/utils.ts @@ -8,5 +8,9 @@ import { isESClientError } from '../../errors'; export const isElasticsearchItemNotFoundError = (error: Error): boolean => { - return isESClientError(error) && error.meta.statusCode === 404 && error.meta.body.found === false; + return ( + isESClientError(error) && + error.meta.statusCode === 404 && + (error.meta.body as any).found === false + ); }; 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 5b85a25f14659..42e1bff6ab370 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 @@ -5,7 +5,7 @@ * 2.0. */ -import type { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; +import type { TransportRequestOptions } from '@elastic/elasticsearch'; import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { ElasticsearchAssetType } from '../../../../types'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/install.ts index d6de59507fbf7..d97081f15aca3 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/install.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { saveInstalledEsRefs } from '../../packages/install'; import { getPathParts } from '../../archive'; @@ -71,12 +71,13 @@ async function handleMlModelInstall({ model_id: mlModel.installationName, defer_definition_decompression: true, timeout: '45s', + // @ts-expect-error expects an object not a string body: mlModel.content, }); } catch (err) { // swallow the error if the ml model already exists. const isAlreadyExistError = - err instanceof ResponseError && + err instanceof errors.ResponseError && err?.body?.error?.type === 'resource_already_exists_exception'; if (!isAlreadyExistError) { throw err; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts index 552e486552a78..2e6365a9913e4 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts @@ -5,6 +5,7 @@ * 2.0. */ import { elasticsearchServiceMock } from 'src/core/server/mocks'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createAppContextStartContractMock } from '../../../../mocks'; import { appContextService } from '../../../../services'; @@ -49,14 +50,13 @@ describe('EPM install', () => { packageName: pkg.name, }); - const sentTemplate = esClient.indices.putIndexTemplate.mock.calls[0][0]!.body as Record< - string, - any - >; + const sentTemplate = ( + esClient.indices.putIndexTemplate.mock.calls[0][0] as estypes.IndicesPutIndexTemplateRequest + ).body; expect(sentTemplate).toBeDefined(); - expect(sentTemplate.priority).toBe(templatePriorityDatasetIsPrefixUnset); - expect(sentTemplate.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixUnset]); + expect(sentTemplate?.priority).toBe(templatePriorityDatasetIsPrefixUnset); + expect(sentTemplate?.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixUnset]); }); it('tests installPackage to use correct priority and index_patterns for data stream with dataset_is_prefix set to false', async () => { @@ -90,14 +90,13 @@ describe('EPM install', () => { packageName: pkg.name, }); - const sentTemplate = esClient.indices.putIndexTemplate.mock.calls[0][0]!.body as Record< - string, - any - >; + const sentTemplate = ( + esClient.indices.putIndexTemplate.mock.calls[0][0] as estypes.IndicesPutIndexTemplateRequest + ).body; expect(sentTemplate).toBeDefined(); - expect(sentTemplate.priority).toBe(templatePriorityDatasetIsPrefixFalse); - expect(sentTemplate.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixFalse]); + expect(sentTemplate?.priority).toBe(templatePriorityDatasetIsPrefixFalse); + expect(sentTemplate?.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixFalse]); }); it('tests installPackage to use correct priority and index_patterns for data stream with dataset_is_prefix set to true', async () => { @@ -130,14 +129,14 @@ describe('EPM install', () => { packageVersion: pkg.version, packageName: pkg.name, }); - const sentTemplate = esClient.indices.putIndexTemplate.mock.calls[0][0]!.body as Record< - string, - any - >; + + const sentTemplate = ( + esClient.indices.putIndexTemplate.mock.calls[0][0] as estypes.IndicesPutIndexTemplateRequest + ).body; expect(sentTemplate).toBeDefined(); - expect(sentTemplate.priority).toBe(templatePriorityDatasetIsPrefixTrue); - expect(sentTemplate.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixTrue]); + expect(sentTemplate?.priority).toBe(templatePriorityDatasetIsPrefixTrue); + expect(sentTemplate?.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixTrue]); }); it('tests installPackage remove the aliases property if the property existed', async () => { @@ -181,18 +180,16 @@ describe('EPM install', () => { packageName: pkg.name, }); - const removeAliases = esClient.indices.putIndexTemplate.mock.calls[0][0]!.body as Record< - string, - any - >; - expect(removeAliases.template.aliases).not.toBeDefined(); + const removeAliases = ( + esClient.indices.putIndexTemplate.mock.calls[0][0] as estypes.IndicesPutIndexTemplateRequest + ).body; + expect(removeAliases?.template?.aliases).not.toBeDefined(); - const sentTemplate = esClient.indices.putIndexTemplate.mock.calls[1][0]!.body as Record< - string, - any - >; + const sentTemplate = ( + esClient.indices.putIndexTemplate.mock.calls[1][0] as estypes.IndicesPutIndexTemplateRequest + ).body; expect(sentTemplate).toBeDefined(); - expect(sentTemplate.priority).toBe(templatePriorityDatasetIsPrefixUnset); - expect(sentTemplate.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixUnset]); + expect(sentTemplate?.priority).toBe(templatePriorityDatasetIsPrefixUnset); + expect(sentTemplate?.index_patterns).toEqual([templateIndexPatternDatasetIsPrefixUnset]); }); }); 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 9dae415838890..67b57dea6e310 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 @@ -192,7 +192,6 @@ function putComponentTemplate( const { name, body, create = false } = params; return { clusterPromise: esClient.cluster.putComponentTemplate( - // @ts-expect-error body is missing required key `settings`. TemplateMapEntry has settings *or* mappings { name, body, create }, { ignore: [404] } ), diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index 44d633d5f6e53..16cb4a29bcc7e 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -505,7 +505,7 @@ const updateExistingDataStream = async ({ try { await esClient.indices.putSettings({ index: dataStreamName, - body: { settings: { default_pipeline: settings.index.default_pipeline } }, + body: { default_pipeline: settings.index.default_pipeline }, }); } catch (err) { throw new Error(`could not update index template settings for ${dataStreamName}`); 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 7d62c0ef41c8d..93181d4f26d02 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 @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { saveInstalledEsRefs } from '../../packages/install'; import { getPathParts } from '../../archive'; @@ -129,7 +129,7 @@ async function handleTransformInstall({ } catch (err) { // swallow the error if the transform already exists. const isAlreadyExistError = - err instanceof ResponseError && + err instanceof errors.ResponseError && err?.body?.error?.type === 'resource_already_exists_exception'; if (!isAlreadyExistError) { throw err; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts index 34dcd5427d655..5f6f64576ad64 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts @@ -18,7 +18,7 @@ jest.mock('./common', () => { }; }); -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import type { ElasticsearchClient, SavedObject, SavedObjectsClientContract } from 'kibana/server'; @@ -518,7 +518,7 @@ describe('test transform install', () => { esClient.transport.request.mockImplementationOnce(() => elasticsearchClientMock.createErrorTransportRequestPromise( - new ResponseError( + new errors.ResponseError( elasticsearchClientMock.createApiResponse({ statusCode: 400, body: { error: { type: 'resource_already_exists_exception' } }, diff --git a/x-pack/plugins/fleet/server/services/index.ts b/x-pack/plugins/fleet/server/services/index.ts index 0ec8a1452beb1..ab88e5af18efa 100644 --- a/x-pack/plugins/fleet/server/services/index.ts +++ b/x-pack/plugins/fleet/server/services/index.ts @@ -5,10 +5,9 @@ * 2.0. */ -import type { KibanaRequest } from 'kibana/server'; import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import type { AgentStatus, Agent } from '../types'; +import type { AgentStatus } from '../types'; import type { GetAgentStatusResponse } from '../../common'; @@ -48,13 +47,6 @@ export interface AgentService { * Get an Agent by id */ getAgent: typeof getAgentById; - /** - * Authenticate an agent with access toekn - */ - authenticateAgentWithAccessToken( - esClient: ElasticsearchClient, - request: KibanaRequest - ): Promise; /** * Return the status by the Agent's id */ diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index c25a1db753c73..46747762213f1 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -578,6 +578,12 @@ describe('Package policy service', () => { }); describe('update', () => { + beforeEach(() => { + appContextService.start(createAppContextStartContractMock()); + }); + afterEach(() => { + appContextService.stop(); + }); it('should fail to update on version conflict', async () => { const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.get.mockResolvedValue({ diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index fa9df22eb5e8c..c03ccfc43ebd8 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -9,7 +9,7 @@ import { omit, partition } from 'lodash'; import { i18n } from '@kbn/i18n'; import semverLte from 'semver/functions/lte'; import { getFlattenedObject } from '@kbn/std'; -import type { KibanaRequest } from 'src/core/server'; +import type { KibanaRequest, LogMeta } from 'src/core/server'; import type { ElasticsearchClient, RequestHandlerContext, @@ -84,6 +84,17 @@ export const DATA_STREAM_ALLOWED_INDEX_PRIVILEGES = new Set([ 'read_cross_cluster', ]); +interface PackagePolicyUpgradeLogMeta extends LogMeta { + package_policy_upgrade: { + package_name: string; + current_version: string; + new_version: string; + status: 'success' | 'failure'; + error?: any[]; + dryRun?: boolean; + }; +} + class PackagePolicyService { public async create( soClient: SavedObjectsClientContract, @@ -432,6 +443,23 @@ class PackagePolicyService { pkgName: packagePolicy.package.name, currentVersion: packagePolicy.package.version, }); + + const upgradeMeta: PackagePolicyUpgradeLogMeta = { + package_policy_upgrade: { + package_name: packagePolicy.package.name, + new_version: packagePolicy.package.version, + current_version: 'unknown', + status: 'success', + dryRun: false, + }, + }; + + appContextService + .getLogger() + .info( + `Package policy successfully upgraded ${JSON.stringify(upgradeMeta)}`, + upgradeMeta + ); } return newPolicy; @@ -661,6 +689,27 @@ class PackagePolicyService { const hasErrors = 'errors' in updatedPackagePolicy; + if (packagePolicy.package.version !== packageInfo.version) { + const upgradeMeta: PackagePolicyUpgradeLogMeta = { + package_policy_upgrade: { + package_name: packageInfo.name, + current_version: packagePolicy.package.version, + new_version: packageInfo.version, + status: hasErrors ? 'failure' : 'success', + error: hasErrors ? updatedPackagePolicy.errors : undefined, + dryRun: true, + }, + }; + appContextService + .getLogger() + .info( + `Package policy upgrade dry run ${ + hasErrors ? 'resulted in errors' : 'ran successfully' + } ${JSON.stringify(upgradeMeta)}`, + upgradeMeta + ); + } + return { name: updatedPackagePolicy.name, diff: [packagePolicy, updatedPackagePolicy], diff --git a/x-pack/plugins/index_lifecycle_management/README.md b/x-pack/plugins/index_lifecycle_management/README.md index 28b2a4637da89..35c2aa063ec23 100644 --- a/x-pack/plugins/index_lifecycle_management/README.md +++ b/x-pack/plugins/index_lifecycle_management/README.md @@ -34,7 +34,6 @@ PUT /_ilm/policy/full "cold" : { "min_age" : "30s", "actions" : { - "freeze": {} } }, "delete" : { diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.helpers.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.helpers.ts index cdb5dc16d1964..23b64c3dade19 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.helpers.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.helpers.ts @@ -7,7 +7,6 @@ import { createForceMergeActions, - createFreezeActions, createMinAgeActions, createReadonlyActions, createRolloverActions, @@ -47,7 +46,6 @@ export const setupSearchableSnapshotsTestBed = async (args?: { cold: { ...createMinAgeActions(testBed, 'cold'), ...createSearchableSnapshotActions(testBed, 'cold'), - ...createFreezeActions(testBed, 'cold'), ...createReadonlyActions(testBed, 'cold'), }, frozen: { diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts index f6b8276938daf..a620f6e1268be 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts @@ -33,7 +33,7 @@ describe(' searchable snapshots', () => { component.update(); }); - test('enabling searchable snapshot should hide force merge, freeze, readonly and shrink in subsequent phases', async () => { + test('enabling searchable snapshot should hide force merge, readonly and shrink in subsequent phases', async () => { const { actions } = testBed; await actions.togglePhase('warm'); @@ -43,7 +43,6 @@ describe(' searchable snapshots', () => { expect(actions.warm.shrinkExists()).toBeTruthy(); expect(actions.warm.readonlyExists()).toBeTruthy(); expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); - expect(actions.cold.freezeExists()).toBeTruthy(); expect(actions.cold.readonlyExists()).toBeTruthy(); await actions.hot.setSearchableSnapshot('my-repo'); @@ -53,7 +52,6 @@ describe(' searchable snapshots', () => { expect(actions.warm.readonlyExists()).toBeFalsy(); // searchable snapshot in cold is still visible expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); - expect(actions.cold.freezeExists()).toBeFalsy(); expect(actions.cold.readonlyExists()).toBeFalsy(); }); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts index 7a4d1f7efca63..be196a377edb4 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts @@ -408,7 +408,6 @@ describe(' serialization', () => { await actions.cold.setDataAllocation('node_attrs'); await actions.cold.setSelectedNodeAttribute('test:123'); await actions.cold.setReplicas('123'); - await actions.cold.setFreeze(); await actions.cold.toggleReadonly(); await actions.cold.setIndexPriority('123'); @@ -428,7 +427,6 @@ describe(' serialization', () => { "test": "123", }, }, - "freeze": Object {}, "readonly": Object {}, "set_priority": Object { "priority": 123, diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/freeze_actions.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/freeze_actions.ts deleted file mode 100644 index ad3d9d3bfbcb8..0000000000000 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/freeze_actions.ts +++ /dev/null @@ -1,18 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { TestBed } from '@kbn/test/jest'; -import { Phase } from '../../../../common/types'; -import { createFormToggleAction } from './form_toggle_action'; - -export const createFreezeActions = (testBed: TestBed, phase: Phase) => { - const { exists } = testBed; - return { - setFreeze: createFormToggleAction(testBed, `${phase}-freezeSwitch`), - freezeExists: (): boolean => exists(`${phase}-freezeSwitch`), - }; -}; diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/index.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/index.ts index 528e818e8a7da..f2579031dbad9 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/index.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/index.ts @@ -21,7 +21,6 @@ export { createForceMergeActions } from './forcemerge_actions'; export { createReadonlyActions } from './readonly_actions'; export { createIndexPriorityActions } from './index_priority_actions'; export { createShrinkActions } from './shrink_actions'; -export { createFreezeActions } from './freeze_actions'; export { createHotPhaseActions, createWarmPhaseActions, diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/phases.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/phases.ts index 18cc0f01ca06c..7f07480cc248d 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/phases.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/phases.ts @@ -15,7 +15,6 @@ import { createMinAgeActions, createNodeAllocationActions, createReplicasAction, - createFreezeActions, createSnapshotPolicyActions, } from './'; @@ -49,7 +48,6 @@ export const createColdPhaseActions = (testBed: TestBed) => { ...createMinAgeActions(testBed, 'cold'), ...createReplicasAction(testBed, 'cold'), ...createReadonlyActions(testBed, 'cold'), - ...createFreezeActions(testBed, 'cold'), ...createIndexPriorityActions(testBed, 'cold'), ...createNodeAllocationActions(testBed, 'cold'), ...createSearchableSnapshotActions(testBed, 'cold'), diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts index b9922a0d59459..085179f14913d 100644 --- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts +++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts @@ -134,7 +134,6 @@ export interface SerializedColdPhase extends SerializedPhase { export interface SerializedFrozenPhase extends SerializedPhase { actions: { - freeze?: {}; allocate?: AllocateAction; set_priority?: { priority: number | null; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts index aed3aa455b651..e1a316eda594f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/constants/ui_metric.ts @@ -17,6 +17,5 @@ export const UIM_POLICY_DETACH_INDEX: string = 'policy_detach_index'; export const UIM_CONFIG_COLD_PHASE: string = 'config_cold_phase'; export const UIM_CONFIG_WARM_PHASE: string = 'config_warm_phase'; export const UIM_CONFIG_SET_PRIORITY: string = 'config_set_priority'; -export const UIM_CONFIG_FREEZE_INDEX: string = 'config_freeze_index'; export const UIM_INDEX_RETRY_STEP: string = 'index_retry_step'; export const UIM_EDIT_CLICK: string = 'edit_click'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase/cold_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase/cold_phase.tsx index 648aebf8118de..58f8544174044 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase/cold_phase.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase/cold_phase.tsx @@ -14,7 +14,6 @@ import { SearchableSnapshotField, IndexPriorityField, ReplicasField, - FreezeField, ReadonlyField, } from '../shared_fields'; @@ -36,9 +35,6 @@ export const ColdPhase: FunctionComponent = () => { }> - {/* Freeze section */} - {!isUsingSearchableSnapshotInHotPhase && } - {/* Readonly section */} {!isUsingSearchableSnapshotInHotPhase && } diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/freeze_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/freeze_field.tsx deleted file mode 100644 index 8db1829f03764..0000000000000 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/freeze_field.tsx +++ /dev/null @@ -1,47 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { FunctionComponent } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiTextColor } from '@elastic/eui'; - -import { LearnMoreLink, ToggleFieldWithDescribedFormRow } from '../../'; - -interface Props { - phase: 'cold' | 'frozen'; -} - -export const FreezeField: FunctionComponent = ({ phase }) => { - return ( - - - - } - description={ - - {' '} - - - } - fullWidth - titleSize="xs" - switchProps={{ - 'data-test-subj': `${phase}-freezeSwitch`, - path: `_meta.${phase}.freezeEnabled`, - }} - > -
- - ); -}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/index.ts index 91faf5c66df81..220f0bd8e941a 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/index.ts @@ -22,5 +22,3 @@ export { ReadonlyField } from './readonly_field'; export { ReplicasField } from './replicas_field'; export { IndexPriorityField } from './index_priority_field'; - -export { FreezeField } from './freeze_field'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx index 44459debc8f4d..0ce98351c9672 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx @@ -257,7 +257,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ 'xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody', { defaultMessage: - 'Force merge, shrink, read only, and freeze actions are not allowed when converting data to a fully-mounted index in this phase.', + 'Force merge, shrink and read only actions are not allowed when converting data to a fully-mounted index in this phase.', } )} data-test-subj="searchableSnapshotFieldsDisabledCallout" diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/configuration_context.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/configuration_context.tsx index 97952a3a212c7..5d506d6235f3f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/configuration_context.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/configuration_context.tsx @@ -19,7 +19,7 @@ export interface Configuration { */ isUsingRollover: boolean; /** - * If this value is true, phases after hot cannot set shrink, forcemerge, freeze, or + * If this value is true, phases after hot cannot set shrink, forcemerge or * searchable_snapshot actions. * * See https://github.com/elastic/elasticsearch/blob/master/docs/reference/ilm/actions/ilm-searchable-snapshot.asciidoc. diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts index 1ce5b8aa7a717..73c15c864b2af 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts @@ -53,14 +53,12 @@ export const createDeserializer = cold: { enabled: Boolean(cold), dataTierAllocationType: determineDataTierAllocationType(cold?.actions), - freezeEnabled: Boolean(cold?.actions?.freeze), readonlyEnabled: Boolean(cold?.actions?.readonly), minAgeToMilliSeconds: -1, }, frozen: { enabled: Boolean(frozen), dataTierAllocationType: determineDataTierAllocationType(frozen?.actions), - freezeEnabled: Boolean(frozen?.actions?.freeze), minAgeToMilliSeconds: -1, }, delete: { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts index 4391f398a6c5a..bd3cd3e08a5a9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts @@ -85,7 +85,6 @@ const originalPolicy: SerializedPolicy = { include: { test: 'my_value' }, exclude: { test: 'my_value' }, }, - freeze: {}, readonly: {}, set_priority: { priority: 12, @@ -139,20 +138,34 @@ describe('deserializer and serializer', () => { serializer = createSerializer(cloneDeep(policy)); }); - it('preserves any unknown policy settings', () => { - const thisTestPolicy = cloneDeep(originalPolicy); - // We populate all levels of the policy with entries our UI does not know about - populateWithUnknownEntries(thisTestPolicy); - serializer = createSerializer(thisTestPolicy); + describe('unknown policy settings', function () { + it('preserves any unknown properties', () => { + const thisTestPolicy = cloneDeep(originalPolicy); + // We populate all levels of the policy with entries our UI does not know about + populateWithUnknownEntries(thisTestPolicy); + serializer = createSerializer(thisTestPolicy); - const copyOfThisTestPolicy = cloneDeep(thisTestPolicy); + const copyOfThisTestPolicy = cloneDeep(thisTestPolicy); - const _formInternal = deserializer(thisTestPolicy); - expect(serializer(_formInternal)).toEqual(thisTestPolicy); + const _formInternal = deserializer(thisTestPolicy); + expect(serializer(_formInternal)).toEqual(thisTestPolicy); - // Assert that the policy we passed in is unaltered after deserialization and serialization - expect(thisTestPolicy).not.toBe(copyOfThisTestPolicy); - expect(thisTestPolicy).toEqual(copyOfThisTestPolicy); + // Assert that the policy we passed in is unaltered after deserialization and serialization + expect(thisTestPolicy).not.toBe(copyOfThisTestPolicy); + expect(thisTestPolicy).toEqual(copyOfThisTestPolicy); + }); + + it('except freeze action in the cold phase', () => { + const policyWithoutFreeze = cloneDeep(originalPolicy); + + const policyWithFreeze = cloneDeep(policyWithoutFreeze); + // add a freeze action to the cold phase + policyWithFreeze.phases.cold!.actions!.freeze = {}; + serializer = createSerializer(policyWithFreeze); + + const _formInternal = deserializer(policyWithFreeze); + expect(serializer(_formInternal)).toEqual(policyWithoutFreeze); + }); }); it('removes all phases if they were disabled in the form', () => { @@ -240,14 +253,6 @@ describe('deserializer and serializer', () => { expect(result.phases.cold!.actions.set_priority).toBeUndefined(); }); - it('removes freeze setting in the cold phase if it is disabled in the form', () => { - formInternal._meta.cold.freezeEnabled = false; - - const result = serializer(formInternal); - - expect(result.phases.cold!.actions.freeze).toBeUndefined(); - }); - it('removes node attribute allocation when it is not selected in the form', () => { // Change from 'node_attrs' to 'node_roles' formInternal._meta.cold.dataTierAllocationType = 'node_roles'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts index 24112cf4725d2..2870b41d71783 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts @@ -248,12 +248,6 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ { defaultMessage: 'Activate cold phase' } ), }, - freezeEnabled: { - defaultValue: false, - label: i18n.translate('xpack.indexLifecycleMgmt.coldPhase.freezeIndexLabel', { - defaultMessage: 'Freeze index', - }), - }, readonlyEnabled: { defaultValue: false, label: i18nTexts.editPolicy.readonlyEnabledFieldLabel, @@ -284,12 +278,6 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ { defaultMessage: 'Activate frozen phase' } ), }, - freezeEnabled: { - defaultValue: false, - label: i18n.translate('xpack.indexLifecycleMgmt.frozePhase.freezeIndexLabel', { - defaultMessage: 'Freeze index', - }), - }, minAgeUnit: { defaultValue: 'd', }, diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts index 652f045922d4d..1bc97107b07a9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts @@ -237,10 +237,10 @@ export const createSerializer = /** * COLD PHASE FREEZE + * The freeze action has been removed in 8.0. + * Clean up any policies that still have this action configured */ - if (_meta.cold.freezeEnabled) { - coldPhase.actions.freeze = coldPhase.actions.freeze ?? {}; - } else { + if (coldPhase.actions.freeze) { delete coldPhase.actions.freeze; } diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts index 6c4d311d6177c..8e83f123a8fa2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts @@ -66,13 +66,11 @@ interface WarmPhaseMetaFields interface ColdPhaseMetaFields extends DataAllocationMetaFields, MinAgeField { enabled: boolean; - freezeEnabled: boolean; readonlyEnabled: boolean; } interface FrozenPhaseMetaFields extends DataAllocationMetaFields, MinAgeField { enabled: boolean; - freezeEnabled: boolean; } interface DeletePhaseMetaFields extends MinAgeField { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts index 513fd122a0848..891109fd22027 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts @@ -9,7 +9,6 @@ import { UIM_CONFIG_COLD_PHASE, UIM_CONFIG_WARM_PHASE, UIM_CONFIG_SET_PRIORITY, - UIM_CONFIG_FREEZE_INDEX, defaultIndexPriority, } from '../constants/'; @@ -60,20 +59,4 @@ describe('getUiMetricsForPhases', () => { }) ).toEqual([UIM_CONFIG_WARM_PHASE, UIM_CONFIG_SET_PRIORITY]); }); - - test('gets freeze index', () => { - expect( - getUiMetricsForPhases({ - cold: { - min_age: '0ms', - actions: { - freeze: {}, - set_priority: { - priority: parseInt(defaultIndexPriority.cold, 10), - }, - }, - }, - }) - ).toEqual([UIM_CONFIG_COLD_PHASE, UIM_CONFIG_FREEZE_INDEX]); - }); }); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts index 0e68b389ef3da..fa9a8d44e9774 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts @@ -17,7 +17,6 @@ import { UiCounterMetricType } from '@kbn/analytics'; import { UIM_APP_NAME, UIM_CONFIG_COLD_PHASE, - UIM_CONFIG_FREEZE_INDEX, UIM_CONFIG_SET_PRIORITY, UIM_CONFIG_WARM_PHASE, defaultIndexPriority, @@ -68,10 +67,6 @@ export function getUiMetricsForPhases(phases: Phases): string[] { ); }, }, - { - metric: UIM_CONFIG_FREEZE_INDEX, - isTracked: () => phases.cold && phases.cold.actions.freeze, - }, ]; return phaseUiMetrics.reduce((tracked: string[], { metric, isTracked }) => { diff --git a/x-pack/plugins/index_lifecycle_management/server/plugin.ts b/x-pack/plugins/index_lifecycle_management/server/plugin.ts index f511f837b8074..08b1033371ad5 100644 --- a/x-pack/plugins/index_lifecycle_management/server/plugin.ts +++ b/x-pack/plugins/index_lifecycle_management/server/plugin.ts @@ -31,11 +31,10 @@ const indexLifecycleDataEnricher = async ( } = await client.asCurrentUser.ilm.explainLifecycle({ index: '*', }); - + // @ts-expect-error IndexLifecyclePolicy is not compatible with IlmExplainLifecycleResponse return indicesList.map((index: IndexWithoutIlm) => { return { ...index, - // @ts-expect-error @elastic/elasticsearch https://github.com/elastic/elasticsearch-specification/issues/531 ilm: { ...(ilmIndicesData[index.name] || {}) }, }; }); diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts index bc27a3b909c85..5ac37f4eeb215 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts @@ -21,7 +21,7 @@ async function createPolicy( ignore: [404], }; - return client.ilm.putLifecycle({ policy: name, body }, options); + return client.ilm.putLifecycle({ name, body }, options); } /** diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts index 069adc139a86d..eed36962a78e5 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts @@ -17,8 +17,7 @@ async function deletePolicies(client: ElasticsearchClient, policyName: string): ignore: [404], }; - // @ts-expect-error @elastic/elasticsearch DeleteSnapshotLifecycleRequest.policy_id is required - return client.ilm.deleteLifecycle({ policy: policyName }, options); + return client.ilm.deleteLifecycle({ name: policyName }, options); } const paramsSchema = schema.object({ diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts index 5c65ff9f6a14b..8cb96e4af0bf3 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_fetch_route.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { ApiResponse } from '@elastic/elasticsearch'; +import type { TransportResult } from '@elastic/elasticsearch'; import { PolicyFromES, SerializedPolicy } from '../../../../common/types'; import { RouteDependencies } from '../../../types'; @@ -46,7 +46,7 @@ function formatPolicies(policiesMap: PoliciesMap): PolicyFromES[] { }, []); } -async function fetchPolicies(client: ElasticsearchClient): Promise> { +async function fetchPolicies(client: ElasticsearchClient): Promise> { const options = { // we allow 404 since they may have no policies ignore: [404], diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/snapshot_repositories/register_fetch_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/snapshot_repositories/register_fetch_route.ts index f1fb987c41911..8787be8e936ba 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/snapshot_repositories/register_fetch_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/snapshot_repositories/register_fetch_route.ts @@ -29,7 +29,7 @@ export const registerFetchRoute = ({ router, license }: RouteDependencies) => { try { const esResult = await ctx.core.elasticsearch.client.asCurrentUser.snapshot.getRepository({ - repository: '*', + name: '*', }); const repos: ListSnapshotReposResponse = { repositories: Object.keys(esResult.body), diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts index 8ee05bfa5d322..96775484e0733 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts @@ -59,4 +59,5 @@ export type TestSubjects = | 'templatesTab' | 'templateTable' | 'title' + | 'unfreezeIndexMenuButton' | 'viewButton'; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts index f95ea373d58b4..79fe885820fae 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts @@ -22,7 +22,6 @@ import { stubWebWorker } from '@kbn/test/jest'; import { createMemoryHistory } from 'history'; stubWebWorker(); -// unhandled promise rejection https://github.com/elastic/kibana/issues/112699 describe('', () => { let testBed: IndicesTestBed; let server: ReturnType['server']; @@ -160,9 +159,15 @@ describe('', () => { describe('index actions', () => { const indexName = 'testIndex'; + const indexMock = createNonDataStreamIndex(indexName); beforeEach(async () => { - httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]); + httpRequestsMockHelpers.setLoadIndicesResponse([ + { + ...indexMock, + isFrozen: true, + }, + ]); httpRequestsMockHelpers.setReloadIndicesResponse({ indexNames: [indexName] }); testBed = await setup(); @@ -184,5 +189,27 @@ describe('', () => { // a reload server call also. expect(server.requests[requestsCount - 1].url).toBe(`${API_BASE_PATH}/indices/reload`); }); + + test('should be able to unfreeze a frozen index', async () => { + const { actions, exists } = testBed; + + httpRequestsMockHelpers.setReloadIndicesResponse([{ ...indexMock, isFrozen: false }]); + + // Open context menu + await actions.clickManageContextMenuButton(); + // Check that the unfreeze action exists for the current index and unfreeze it + expect(exists('unfreezeIndexMenuButton')).toBe(true); + await actions.clickContextMenuOption('unfreezeIndexMenuButton'); + + const requestsCount = server.requests.length; + expect(server.requests[requestsCount - 2].url).toBe(`${API_BASE_PATH}/indices/unfreeze`); + // After the index is unfrozen, we imediately do a reload. So we need to expect to see + // a reload server call also. + expect(server.requests[requestsCount - 1].url).toBe(`${API_BASE_PATH}/indices/reload`); + // Open context menu once again, since clicking an action will close it. + await actions.clickManageContextMenuButton(); + // The unfreeze action should not be present anymore + expect(exists('unfreezeIndexMenuButton')).toBe(false); + }); }); }); diff --git a/x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap b/x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap index f4f886dd7211c..68fb65ed352d1 100644 --- a/x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap +++ b/x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap @@ -108,7 +108,6 @@ Array [ "Refresh indices", "Clear indices cache", "Flush indices", - "Freeze indices", "Delete indices", ] `; @@ -134,7 +133,6 @@ Array [ "Refresh index", "Clear index cache", "Flush index", - "Freeze index", "Delete index", ] `; diff --git a/x-pack/plugins/index_management/common/constants/index.ts b/x-pack/plugins/index_management/common/constants/index.ts index 373044aef9d45..6641e6ef67c7d 100644 --- a/x-pack/plugins/index_management/common/constants/index.ts +++ b/x-pack/plugins/index_management/common/constants/index.ts @@ -24,8 +24,6 @@ export { UIM_INDEX_FLUSH_MANY, UIM_INDEX_FORCE_MERGE, UIM_INDEX_FORCE_MERGE_MANY, - UIM_INDEX_FREEZE, - UIM_INDEX_FREEZE_MANY, UIM_INDEX_OPEN, UIM_INDEX_OPEN_MANY, UIM_INDEX_REFRESH, diff --git a/x-pack/plugins/index_management/common/constants/ui_metric.ts b/x-pack/plugins/index_management/common/constants/ui_metric.ts index b6e29cd7e3024..18cd983834bd5 100644 --- a/x-pack/plugins/index_management/common/constants/ui_metric.ts +++ b/x-pack/plugins/index_management/common/constants/ui_metric.ts @@ -19,8 +19,6 @@ export const UIM_INDEX_FLUSH = 'index_flush'; export const UIM_INDEX_FLUSH_MANY = 'index_flush_many'; export const UIM_INDEX_FORCE_MERGE = 'index_force_merge'; export const UIM_INDEX_FORCE_MERGE_MANY = 'index_force_merge_many'; -export const UIM_INDEX_FREEZE = 'index_freeze'; -export const UIM_INDEX_FREEZE_MANY = 'index_freeze_many'; export const UIM_INDEX_OPEN = 'index_open'; export const UIM_INDEX_OPEN_MANY = 'index_open_many'; export const UIM_INDEX_REFRESH = 'index_refresh'; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js index 4470d7ba152cc..9e650f7fe2da5 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js @@ -20,7 +20,6 @@ import { openDetailPanel, performExtensionAction, reloadIndices, - freezeIndices, unfreezeIndices, } from '../../../../store/actions'; @@ -68,9 +67,6 @@ const mapDispatchToProps = (dispatch, { indexNames }) => { refreshIndices: () => { dispatch(refreshIndices({ indexNames })); }, - freezeIndices: () => { - dispatch(freezeIndices({ indexNames })); - }, unfreezeIndices: () => { dispatch(unfreezeIndices({ indexNames })); }, diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js index c5bd62feff826..cc78f8c99a4c6 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js @@ -70,7 +70,6 @@ export class IndexActionsContextMenu extends Component { return indexStatusByName[indexName] === INDEX_OPEN; }); const allFrozen = every(indices, (index) => index.isFrozen); - const allUnfrozen = every(indices, (index) => !index.isFrozen); const selectedIndexCount = indexNames.length; const items = []; if (!detailPanel && selectedIndexCount === 1) { @@ -178,6 +177,7 @@ export class IndexActionsContextMenu extends Component { }); if (allFrozen) { items.push({ + 'data-test-subj': 'unfreezeIndexMenuButton', name: i18n.translate('xpack.idxMgmt.indexActionsMenu.unfreezeIndexLabel', { defaultMessage: 'Unfreeze {selectedIndexCount, plural, one {index} other {indices} }', values: { selectedIndexCount }, @@ -186,17 +186,6 @@ export class IndexActionsContextMenu extends Component { this.closePopoverAndExecute(unfreezeIndices); }, }); - } else if (allUnfrozen) { - items.push({ - name: i18n.translate('xpack.idxMgmt.indexActionsMenu.freezeIndexLabel', { - defaultMessage: 'Freeze {selectedIndexCount, plural, one {index} other {indices} }', - values: { selectedIndexCount }, - }), - onClick: () => { - this.closePopover(); - this.setState({ renderConfirmModal: this.renderConfirmFreezeModal }); - }, - }); } } else { items.push({ @@ -619,76 +608,6 @@ export class IndexActionsContextMenu extends Component { ); }; - renderConfirmFreezeModal = () => { - const { freezeIndices, indexNames } = this.props; - - return ( - this.closePopoverAndExecute(freezeIndices)} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.cancelButtonText', - { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.confirmButtonText', - { - defaultMessage: 'Freeze {count, plural, one {index} other {indices}}', - values: { - count: indexNames.length, - }, - } - )} - > -

- -

- -
    - {indexNames.map((indexName) => ( -
  • {indexName}
  • - ))} -
- - -

- -

-
-
- ); - }; - render() { return ( diff --git a/x-pack/plugins/index_management/public/application/services/api.ts b/x-pack/plugins/index_management/public/application/services/api.ts index a7109854d676f..5929df2f2821d 100644 --- a/x-pack/plugins/index_management/public/application/services/api.ts +++ b/x-pack/plugins/index_management/public/application/services/api.ts @@ -19,8 +19,6 @@ import { UIM_INDEX_FLUSH_MANY, UIM_INDEX_FORCE_MERGE, UIM_INDEX_FORCE_MERGE_MANY, - UIM_INDEX_FREEZE, - UIM_INDEX_FREEZE_MANY, UIM_INDEX_OPEN, UIM_INDEX_OPEN_MANY, UIM_INDEX_REFRESH, @@ -177,16 +175,6 @@ export async function clearCacheIndices(indices: string[]) { uiMetricService.trackMetric(METRIC_TYPE.COUNT, eventName); return response; } -export async function freezeIndices(indices: string[]) { - const body = JSON.stringify({ - indices, - }); - const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/freeze`, { body }); - // Only track successful requests. - const eventName = indices.length > 1 ? UIM_INDEX_FREEZE_MANY : UIM_INDEX_FREEZE; - uiMetricService.trackMetric(METRIC_TYPE.COUNT, eventName); - return response; -} export async function unfreezeIndices(indices: string[]) { const body = JSON.stringify({ indices, diff --git a/x-pack/plugins/index_management/public/application/services/index.ts b/x-pack/plugins/index_management/public/application/services/index.ts index 53bb9fa9ebb5e..536024ed5c758 100644 --- a/x-pack/plugins/index_management/public/application/services/index.ts +++ b/x-pack/plugins/index_management/public/application/services/index.ts @@ -15,7 +15,6 @@ export { flushIndices, forcemergeIndices, clearCacheIndices, - freezeIndices, unfreezeIndices, loadIndexSettings, updateIndexSettings, diff --git a/x-pack/plugins/index_management/public/application/store/actions/freeze_indices.js b/x-pack/plugins/index_management/public/application/store/actions/freeze_indices.js deleted file mode 100644 index 002b0c5f00c9d..0000000000000 --- a/x-pack/plugins/index_management/public/application/store/actions/freeze_indices.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createAction } from 'redux-actions'; -import { i18n } from '@kbn/i18n'; -import { freezeIndices as request } from '../../services'; -import { clearRowStatus, reloadIndices } from '../actions'; -import { notificationService } from '../../services/notification'; - -export const freezeIndicesStart = createAction('INDEX_MANAGEMENT_FREEZE_INDICES_START'); - -export const freezeIndices = - ({ indexNames }) => - async (dispatch) => { - dispatch(freezeIndicesStart({ indexNames })); - try { - await request(indexNames); - } catch (error) { - notificationService.showDangerToast(error.message); - return dispatch(clearRowStatus({ indexNames })); - } - dispatch(reloadIndices(indexNames)); - notificationService.showSuccessToast( - i18n.translate('xpack.idxMgmt.freezeIndicesAction.successfullyFrozeIndicesMessage', { - defaultMessage: 'Successfully froze: [{indexNames}]', - values: { indexNames: indexNames.join(', ') }, - }) - ); - }; diff --git a/x-pack/plugins/index_management/public/application/store/actions/index.js b/x-pack/plugins/index_management/public/application/store/actions/index.js index bb970efe1b58f..853798ab94bff 100644 --- a/x-pack/plugins/index_management/public/application/store/actions/index.js +++ b/x-pack/plugins/index_management/public/application/store/actions/index.js @@ -15,7 +15,6 @@ export * from './load_indices'; export * from './load_index_data'; export * from './open_indices'; export * from './refresh_indices'; -export * from './freeze_indices'; export * from './unfreeze_indices'; export * from './reload_indices'; export * from './table_state'; diff --git a/x-pack/plugins/index_management/server/lib/fetch_indices.ts b/x-pack/plugins/index_management/server/lib/fetch_indices.ts index f78e666ddfc5f..1dd27dff98c16 100644 --- a/x-pack/plugins/index_management/server/lib/fetch_indices.ts +++ b/x-pack/plugins/index_management/server/lib/fetch_indices.ts @@ -54,7 +54,6 @@ async function fetchIndicesCall( aliases: aliases.length ? aliases : 'none', // @ts-expect-error @elastic/elasticsearch https://github.com/elastic/elasticsearch-specification/issues/532 hidden: index.settings.index.hidden === 'true', - // @ts-expect-error @elastic/elasticsearch https://github.com/elastic/elasticsearch-specification/issues/532 data_stream: index.data_stream!, }); } diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/register_update_route.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/register_update_route.ts index 464d73790af2a..c2235b9eb85ab 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/register_update_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/register_update_route.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '../index'; diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts deleted file mode 100644 index fcab1d6338b6f..0000000000000 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; - -import { RouteDependencies } from '../../../types'; -import { addBasePath } from '../index'; - -const bodySchema = schema.object({ - indices: schema.arrayOf(schema.string()), -}); - -export function registerFreezeRoute({ router, lib: { handleEsError } }: RouteDependencies) { - router.post( - { path: addBasePath('/indices/freeze'), validate: { body: bodySchema } }, - async (context, request, response) => { - const { client } = context.core.elasticsearch; - const { indices = [] } = request.body as typeof bodySchema.type; - - try { - await client.asCurrentUser.indices.freeze({ - index: indices.join(','), - }); - return response.ok(); - } catch (error) { - return handleEsError({ error, response }); - } - } - ); -} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_indices_routes.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_indices_routes.ts index ae1577f7722fe..c3e3eeb35118c 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_indices_routes.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_indices_routes.ts @@ -16,7 +16,6 @@ import { registerOpenRoute } from './register_open_route'; import { registerRefreshRoute } from './register_refresh_route'; import { registerReloadRoute } from './register_reload_route'; import { registerDeleteRoute } from './register_delete_route'; -import { registerFreezeRoute } from './register_freeze_route'; import { registerUnfreezeRoute } from './register_unfreeze_route'; export function registerIndicesRoutes(dependencies: RouteDependencies) { @@ -29,6 +28,5 @@ export function registerIndicesRoutes(dependencies: RouteDependencies) { registerRefreshRoute(dependencies); registerReloadRoute(dependencies); registerDeleteRoute(dependencies); - registerFreezeRoute(dependencies); registerUnfreezeRoute(dependencies); } diff --git a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts index 7458b98f5092f..3335913b81071 100644 --- a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '../index'; diff --git a/x-pack/plugins/index_management/server/routes/api/templates/lib.ts b/x-pack/plugins/index_management/server/routes/api/templates/lib.ts index ec8916b0b8d07..413e73ff93d5f 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/lib.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/lib.ts @@ -51,7 +51,6 @@ export const saveTemplate = async ({ return await client.asCurrentUser.indices.putTemplate({ name: template.name, - // @ts-expect-error @elastic/elasticsearch https://github.com/elastic/elasticsearch-specification/issues/533 order, body: { index_patterns, diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts index cd363cbd7d003..e45d86f3e2b27 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema, TypeOf } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; @@ -31,7 +31,7 @@ export function registerSimulateRoute({ router, lib: { handleEsError } }: RouteD // Issue: https://github.com/elastic/elasticsearch/issues/59152 index_patterns: ['a_fake_index_pattern_that_wont_match_any_indices'], }, - }); + } as estypes.IndicesSimulateTemplateRequest); return response.ok({ body: templatePreview }); } catch (error) { diff --git a/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_overview.ts b/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_overview.ts index 5746410f03388..0fe94c7f53dab 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_overview.ts +++ b/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_overview.ts @@ -25,9 +25,23 @@ export const podOverview: TSVBMetricModelCreator = ( metrics: [ { field: 'kubernetes.pod.cpu.usage.node.pct', - id: 'avg-cpu-usage', + id: 'avg-cpu-without', type: 'avg', }, + { + field: 'kubernetes.pod.cpu.usage.limit.pct', + id: 'avg-cpu-with', + type: 'avg', + }, + { + id: 'cpu-usage', + type: 'calculation', + variables: [ + { id: 'cpu_with', name: 'with_limit', field: 'avg-cpu-with' }, + { id: 'cpu_without', name: 'without_limit', field: 'avg-cpu-without' }, + ], + script: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + }, ], }, { @@ -36,9 +50,23 @@ export const podOverview: TSVBMetricModelCreator = ( metrics: [ { field: 'kubernetes.pod.memory.usage.node.pct', - id: 'avg-memory-usage', + id: 'avg-memory-without', type: 'avg', }, + { + field: 'kubernetes.pod.memory.usage.limit.pct', + id: 'avg-memory-with', + type: 'avg', + }, + { + id: 'memory-usage', + type: 'calculation', + variables: [ + { id: 'memory_with', name: 'with_limit', field: 'avg-memory-with' }, + { id: 'memory_without', name: 'without_limit', field: 'avg-memory-without' }, + ], + script: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + }, ], }, { diff --git a/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts b/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts index 567acf1fc4134..c6bc10901fcb8 100644 --- a/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts +++ b/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataView, DataViewsContract } from '../../../../../src/plugins/data_views/common'; import { ObjectEntries } from '../utility_types'; import { ResolveLogSourceConfigurationError } from './errors'; diff --git a/x-pack/plugins/infra/common/search_strategies/log_entries/log_entries.ts b/x-pack/plugins/infra/common/search_strategies/log_entries/log_entries.ts index cc6d3fbe585e0..4e115cda6a8e6 100644 --- a/x-pack/plugins/infra/common/search_strategies/log_entries/log_entries.ts +++ b/x-pack/plugins/infra/common/search_strategies/log_entries/log_entries.ts @@ -6,7 +6,7 @@ */ import * as rt from 'io-ts'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { logSourceColumnConfigurationRT } from '../../log_sources/log_source_configuration'; import { logEntryAfterCursorRT, diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx index 5aafd9b613d99..ec97d01a1cd6f 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx @@ -54,6 +54,7 @@ describe('ExpressionChart', () => { metricAlias: 'metricbeat-*', inventoryDefaultView: 'host', metricsExplorerDefaultView: 'host', + // @ts-ignore fields: { timestamp: '@timestamp', container: 'container.id', diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx index b176e3907228c..6a68c01e26017 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx @@ -7,10 +7,11 @@ import React, { useMemo, useCallback } from 'react'; import { Axis, Chart, niceTimeFormatter, Position, Settings } from '@elastic/charts'; -import { first, last } from 'lodash'; import { EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataViewBase } from '@kbn/es-query'; +import { first, last } from 'lodash'; + import { MetricsSourceConfiguration } from '../../../../common/metrics_sources'; import { Color } from '../../../../common/color_palette'; import { MetricsExplorerRow, MetricsExplorerAggregation } from '../../../../common/http_api'; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts index 9de6e574ecb5b..94bb3d8e66cbf 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { HttpHandler } from 'src/core/public'; import { LOG_ANALYSIS_VALIDATE_DATASETS_PATH, diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts index a211fecc807fa..8a9f960b54afa 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts @@ -6,7 +6,7 @@ */ import type { HttpHandler } from 'src/core/public'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { LOG_ANALYSIS_VALIDATE_INDICES_PATH, diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts index 4ae99b95cfff8..4ff8c0c3c08e0 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts @@ -6,7 +6,7 @@ */ import type { HttpHandler } from 'src/core/public'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ValidateLogEntryDatasetsResponsePayload, ValidationIndicesResponsePayload, diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts index 6823ed173a740..9ef41042302a1 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import type { HttpHandler } from 'src/core/public'; import { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx index 99d4ab4becee5..433a24cffd937 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx @@ -6,7 +6,7 @@ */ import createContainer from 'constate'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useMemo } from 'react'; import { useLogAnalysisModule } from '../../log_analysis_module'; import { useLogAnalysisModuleConfiguration } from '../../log_analysis_module_configuration'; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts index c4c939d0ebb9d..214faaf9a3012 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { HttpHandler } from 'src/core/public'; import { bucketSpan, diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx index f3e8f7e777597..46587969ca2ab 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import createContainer from 'constate'; import { useMemo } from 'react'; import { ModuleSourceConfiguration } from '../../log_analysis_module_types'; diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts index 4541eb6518788..97a3f8eabbe4e 100644 --- a/x-pack/plugins/infra/public/lib/lib.ts +++ b/x-pack/plugins/infra/public/lib/lib.ts @@ -124,7 +124,7 @@ export enum InfraWaffleMapRuleOperator { } export interface InfraWaffleMapOptions { - fields?: MetricsSourceConfigurationProperties['fields'] | null; + fields?: Omit | null; formatter: InfraFormatterType; formatTemplate: string; metric: SnapshotMetricInput; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index 6b7e98912fd49..c0d0b15217df3 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -6,9 +6,10 @@ */ import DateMath from '@elastic/datemath'; -import { isEqual } from 'lodash'; import { useEffect, useState } from 'react'; import { DataViewBase } from '@kbn/es-query'; +import { isEqual } from 'lodash'; + import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources'; import { MetricsExplorerResponse, diff --git a/x-pack/plugins/infra/public/utils/logs_overview_fetchers.ts b/x-pack/plugins/infra/public/utils/logs_overview_fetchers.ts index c813bd3dae781..44f65b9e8071a 100644 --- a/x-pack/plugins/infra/public/utils/logs_overview_fetchers.ts +++ b/x-pack/plugins/infra/public/utils/logs_overview_fetchers.ts @@ -6,7 +6,7 @@ */ import { encode } from 'rison-node'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FetchData, FetchDataParams, LogsFetchDataResponse } from '../../../observability/public'; import { DEFAULT_SOURCE_ID } from '../../common/constants'; import { callFetchLogSourceConfigurationAPI } from '../containers/logs/log_source/api/fetch_log_source_configuration'; diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 4d4a0ff6320bd..00c52dae7ed3c 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Lifecycle } from '@hapi/hapi'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { JsonArray, JsonValue } from '@kbn/utility-types'; diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 4576a2e8452ac..0c0284e328dd3 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -5,37 +5,36 @@ * 2.0. */ -import { - IndicesExistsAlias, - IndicesGet, - MlGetBuckets, -} from '@elastic/elasticsearch/api/requestParams'; -import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; -import { estypes } from '@elastic/elasticsearch'; -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { - InfraRouteConfig, - InfraServerPluginSetupDeps, - CallWithRequestParams, - InfraDatabaseSearchResponse, - InfraDatabaseMultiResponse, - InfraDatabaseFieldCapsResponse, - InfraDatabaseGetIndicesResponse, - InfraDatabaseGetIndicesAliasResponse, -} from './adapter_types'; -import { TSVBMetricModel } from '../../../../common/inventory_models/types'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { TransportRequestParams } from '@elastic/elasticsearch'; +import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { CoreSetup, IRouter, KibanaRequest, + RequestHandler, RouteMethod, } from '../../../../../../../src/core/server'; -import { RequestHandler } from '../../../../../../../src/core/server'; -import { InfraConfig } from '../../../plugin'; -import type { InfraPluginRequestHandlerContext } from '../../../types'; import { UI_SETTINGS } from '../../../../../../../src/plugins/data/server'; import { TimeseriesVisData } from '../../../../../../../src/plugins/vis_types/timeseries/server'; -import { InfraServerPluginStartDeps } from './adapter_types'; +import { TSVBMetricModel } from '../../../../common/inventory_models/types'; +import { InfraConfig } from '../../../plugin'; +import type { InfraPluginRequestHandlerContext } from '../../../types'; +import { + CallWithRequestParams, + InfraDatabaseFieldCapsResponse, + InfraDatabaseGetIndicesAliasResponse, + InfraDatabaseGetIndicesResponse, + InfraDatabaseMultiResponse, + InfraDatabaseSearchResponse, + InfraRouteConfig, + InfraServerPluginSetupDeps, + InfraServerPluginStartDeps, +} from './adapter_types'; + +interface FrozenIndexParams { + ignore_throttled?: boolean; +} export class KibanaFramework { public router: IRouter; @@ -133,7 +132,7 @@ export class KibanaFramework { ) { const { elasticsearch, uiSettings } = requestContext.core; - const includeFrozen = await uiSettings.client.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); + const includeFrozen = await uiSettings.client.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); if (endpoint === 'msearch') { const maxConcurrentShardRequests = await uiSettings.client.get( UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS @@ -143,11 +142,17 @@ export class KibanaFramework { } } - const frozenIndicesParams = ['search', 'msearch'].includes(endpoint) - ? { - ignore_throttled: !includeFrozen, - } - : {}; + // Only set the "ignore_throttled" value (to false) if the Kibana setting + // for "search:includeFrozen" is true (i.e. don't ignore throttled indices, a triple negative!) + // More information: + // - https://github.com/elastic/kibana/issues/113197 + // - https://github.com/elastic/elasticsearch/pull/77479 + // + // NOTE: these params only need to be spread onto the search and msearch calls below + const frozenIndicesParams: FrozenIndexParams = {}; + if (includeFrozen) { + frozenIndicesParams.ignore_throttled = false; + } let apiResult; switch (endpoint) { @@ -166,38 +171,32 @@ export class KibanaFramework { case 'fieldCaps': apiResult = elasticsearch.client.asCurrentUser.fieldCaps({ ...params, - ...frozenIndicesParams, }); break; case 'indices.existsAlias': apiResult = elasticsearch.client.asCurrentUser.indices.existsAlias({ ...params, - ...frozenIndicesParams, - } as IndicesExistsAlias); + } as estypes.IndicesExistsAliasRequest); break; case 'indices.getAlias': apiResult = elasticsearch.client.asCurrentUser.indices.getAlias({ ...params, - ...frozenIndicesParams, }); break; case 'indices.get': apiResult = elasticsearch.client.asCurrentUser.indices.get({ ...params, - ...frozenIndicesParams, - } as IndicesGet); + } as estypes.IndicesGetRequest); break; case 'transport.request': apiResult = elasticsearch.client.asCurrentUser.transport.request({ ...params, - ...frozenIndicesParams, } as TransportRequestParams); break; case 'ml.getBuckets': apiResult = elasticsearch.client.asCurrentUser.ml.getBuckets({ ...params, - ...frozenIndicesParams, - } as MlGetBuckets); + } as estypes.MlGetBucketsRequest); break; } return apiResult ? (await apiResult).body : undefined; diff --git a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts index 524658559eadf..75a86ae654d6c 100644 --- a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts @@ -10,8 +10,8 @@ import { fold, map } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import * as runtimeTypes from 'io-ts'; -import { compact } from 'lodash'; import { JsonArray } from '@kbn/utility-types'; +import { compact } from 'lodash'; import type { InfraPluginRequestHandlerContext } from '../../../types'; import { LogEntriesAdapter, @@ -46,7 +46,7 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { const highlightClause = highlightQuery ? { highlight: { - boundary_scanner: 'word', + boundary_scanner: 'word' as const, fields: fields.reduce( (highlightFieldConfigs, fieldName) => ({ ...highlightFieldConfigs, diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/lib/check_valid_node.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/lib/check_valid_node.ts index f2b7691646e48..a1bff361a8067 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/lib/check_valid_node.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/lib/check_valid_node.ts @@ -17,7 +17,7 @@ export const checkValidNode = async ( allow_no_indices: true, ignore_unavailable: true, index: indexPattern, - terminateAfter: 1, + terminate_after: 1, body: { size: 0, query: { diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts index 3dd702126735d..26f2ecbc10197 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { first, get, last } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ALERT_REASON, ALERT_RULE_PARAMS } from '@kbn/rule-data-utils'; import moment from 'moment'; +import { first, get, last } from 'lodash'; import { getCustomMetricLabel } from '../../../../common/formatters/get_custom_metric_label'; import { toMetricOpt } from '../../../../common/snapshot_metric_i18n'; import { AlertStates } from './types'; diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts index 1f0521070a1e5..e5d8bab948581 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts @@ -24,7 +24,7 @@ import { GroupedSearchQueryResponse, } from '../../../../common/alerting/logs/log_threshold/types'; import { alertsMock } from '../../../../../alerting/server/mocks'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // Mocks // const numericField = { diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index f99f7a96158c3..6d2b074c45bb0 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import { ALERT_EVALUATION_THRESHOLD, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts index 5bd7a4947b439..71c18d9f7cf04 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { mapValues, first, last, isNaN, isNumber, isObject, has } from 'lodash'; import moment from 'moment'; import { ElasticsearchClient } from 'kibana/server'; +import { mapValues, first, last, isNaN, isNumber, isObject, has } from 'lodash'; import { isTooManyBucketsPreviewException, TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, @@ -222,6 +222,7 @@ const getMetric: ( return groupedResults; } const { body: result } = await esClient.search({ + // @ts-expect-error buckets_path is not compatible body: searchBody, index, }); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index bd9c0afefa3fc..d204782957f34 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -232,6 +232,50 @@ describe('The metric threshold alert type', () => { ); expect(stateResult3.groups).toEqual(expect.arrayContaining(['a', 'b'])); }); + + const executeWithFilter = ( + comparator: Comparator, + threshold: number[], + filterQuery: string, + metric?: string, + state?: any + ) => + executor({ + ...mockOptions, + services, + params: { + groupBy: ['something'], + criteria: [ + { + ...baseNonCountCriterion, + comparator, + threshold, + metric: metric ?? baseNonCountCriterion.metric, + }, + ], + }, + state: state ?? mockOptions.state.wrapped, + }); + test('persists previous groups that go missing, until the filterQuery param changes', async () => { + const stateResult1 = await executeWithFilter(Comparator.GT, [0.75], 'query', 'test.metric.2'); + expect(stateResult1.groups).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + const stateResult2 = await executeWithFilter( + Comparator.GT, + [0.75], + 'query', + 'test.metric.1', + stateResult1 + ); + expect(stateResult2.groups).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + const stateResult3 = await executeWithFilter( + Comparator.GT, + [0.75], + 'different query', + 'test.metric.1', + stateResult2 + ); + expect(stateResult3.groups).toEqual(expect.arrayContaining(['a', 'b'])); + }); }); describe('querying with multiple criteria', () => { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index e4887e922bb66..0abf4c41e7cc9 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -33,6 +33,7 @@ export type MetricThresholdAlertTypeParams = Record; export type MetricThresholdAlertTypeState = AlertTypeState & { groups: string[]; groupBy?: string | string[]; + filterQuery?: string; }; export type MetricThresholdAlertInstanceState = AlertInstanceState; // no specific instace state used export type MetricThresholdAlertInstanceContext = AlertInstanceContext; // no specific instace state used @@ -94,8 +95,11 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => const config = source.configuration; const previousGroupBy = state.groupBy; + const previousFilterQuery = state.filterQuery; const prevGroups = - alertOnGroupDisappear && isEqual(previousGroupBy, params.groupBy) + alertOnGroupDisappear && + isEqual(previousGroupBy, params.groupBy) && + isEqual(previousFilterQuery, params.filterQuery) ? // Filter out the * key from the previous groups, only include it if it's one of // the current groups. In case of a groupBy alert that starts out with no data and no // groups, we don't want to persist the existence of the * alert instance @@ -220,7 +224,7 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => } } - return { groups, groupBy: params.groupBy }; + return { groups, groupBy: params.groupBy, filterQuery: params.filterQuery }; }); export const FIRED_ACTIONS = { diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index 16209e5e4b684..e7b1624206515 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { JsonObject } from '@kbn/utility-types'; import type { InfraPluginRequestHandlerContext } from '../../../types'; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/queries/log_entry_datasets.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/queries/log_entry_datasets.ts index 9eae8daa3e74f..4386b6ccef9c1 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/queries/log_entry_datasets.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/queries/log_entry_datasets.ts @@ -6,7 +6,7 @@ */ import * as rt from 'io-ts'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { commonSearchSuccessResponseFieldsRT } from '../../../../utils/elasticsearch_runtime_types'; diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts index 3210f01116f76..aca0483037912 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { InfraPluginRequestHandlerContext, InfraRequestHandlerContext } from '../../types'; import { TracingSpan, startTracingSpan } from '../../../common/performance_tracing'; import { fetchMlJob, getLogEntryDatasets } from './common'; diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index 7023f7007763c..d1d136c741876 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from 'src/core/server'; import { compareDatasetsByMaximumAnomalyScore, diff --git a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts index 8b05d7c44e3f5..dd68de4e49d34 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as rt from 'io-ts'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; import { defaultRequestParameters } from './common'; diff --git a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_examples.ts b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_examples.ts index d903225facd57..d6099404daa80 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_examples.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_examples.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as rt from 'io-ts'; import { partitionField } from '../../../../common/log_analysis'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; diff --git a/x-pack/plugins/infra/server/routes/log_analysis/validation/datasets.ts b/x-pack/plugins/infra/server/routes/log_analysis/validation/datasets.ts index ef789c1b41349..4237ee2ae9abc 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/validation/datasets.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/validation/datasets.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { InfraBackendLibs } from '../../../lib/infra_types'; import { diff --git a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts index f0d7b18d91a5d..9a92012c21fe4 100644 --- a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts +++ b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts @@ -85,11 +85,13 @@ export const initLogSourceConfigurationRoutes = ({ framework, sources }: InfraBa ? sources.updateSourceConfiguration( requestContext.core.savedObjects.client, sourceId, + // @ts-ignore patchedSourceConfigurationProperties ) : sources.createSourceConfiguration( requestContext.core.savedObjects.client, sourceId, + // @ts-ignore patchedSourceConfigurationProperties )); diff --git a/x-pack/plugins/infra/server/routes/metadata/lib/get_node_info.ts b/x-pack/plugins/infra/server/routes/metadata/lib/get_node_info.ts index 06035ed40adf1..94becdf6d2811 100644 --- a/x-pack/plugins/infra/server/routes/metadata/lib/get_node_info.ts +++ b/x-pack/plugins/infra/server/routes/metadata/lib/get_node_info.ts @@ -55,7 +55,7 @@ export const getNodeInfo = async ( const params = { allow_no_indices: true, ignore_unavailable: true, - terminateAfter: 1, + terminate_after: 1, index: sourceConfiguration.metricAlias, body: { size: 1, diff --git a/x-pack/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts b/x-pack/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts index 9bf809ba3b3f4..164d94d9f692f 100644 --- a/x-pack/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts +++ b/x-pack/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts @@ -24,7 +24,7 @@ export const getPodNodeName = async ( const params = { allow_no_indices: true, ignore_unavailable: true, - terminateAfter: 1, + terminate_after: 1, index: sourceConfiguration.metricAlias, body: { size: 1, diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts index be25bbbf022ee..640d62c366726 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts @@ -24,7 +24,7 @@ export const getDatasetForField = async ( const params = { allow_no_indices: true, ignore_unavailable: true, - terminateAfter: 1, + terminate_after: 1, index: indexPattern, body: { query: { diff --git a/x-pack/plugins/infra/server/routes/metrics_sources/index.ts b/x-pack/plugins/infra/server/routes/metrics_sources/index.ts index 0123e4678697c..24ea04e3e14f9 100644 --- a/x-pack/plugins/infra/server/routes/metrics_sources/index.ts +++ b/x-pack/plugins/infra/server/routes/metrics_sources/index.ts @@ -88,11 +88,13 @@ export const initMetricsSourceConfigurationRoutes = (libs: InfraBackendLibs) => ? sources.updateSourceConfiguration( requestContext.core.savedObjects.client, sourceId, + // @ts-ignore patchedSourceConfigurationProperties ) : sources.createSourceConfiguration( requestContext.core.savedObjects.client, sourceId, + // @ts-ignore patchedSourceConfigurationProperties )); diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts index 85a1b95cf70aa..b0d2eeb987861 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { of, throwError } from 'rxjs'; import { elasticsearchServiceMock, @@ -230,7 +230,7 @@ describe('LogEntries search strategy', () => { mockDependencies ); - await expect(response.toPromise()).rejects.toThrowError(ResponseError); + await expect(response.toPromise()).rejects.toThrowError(errors.ResponseError); }); it('forwards cancellation to the underlying search strategy', async () => { @@ -307,7 +307,7 @@ const createEsSearchStrategyMock = (esSearchResponse: IEsSearchResponse) => ({ return of(esSearchResponse); } else { return throwError( - new ResponseError({ + new errors.ResponseError({ body: {}, headers: {}, meta: {} as any, diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.ts b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.ts index 651758d9cd976..b401b68d0e3d3 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.ts @@ -113,7 +113,6 @@ export const logEntriesSearchStrategyProvider = ({ messageFormattingRules, ]): IEsSearchRequest => { return { - // @ts-expect-error @elastic/elasticsearch declares indices_boost as Record params: createGetLogEntriesQuery( indices, params.startTimestamp, diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts index ec3d4aa52a6b5..1f03878ba6feb 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { of, throwError } from 'rxjs'; import { elasticsearchServiceMock, @@ -196,7 +196,7 @@ describe('LogEntry search strategy', () => { mockDependencies ); - await expect(response.toPromise()).rejects.toThrowError(ResponseError); + await expect(response.toPromise()).rejects.toThrowError(errors.ResponseError); }); it('forwards cancellation to the underlying search strategy', async () => { @@ -262,7 +262,7 @@ const createEsSearchStrategyMock = (esSearchResponse: IEsSearchResponse) => ({ return of(esSearchResponse); } else { return throwError( - new ResponseError({ + new errors.ResponseError({ body: {}, headers: {}, meta: {} as any, diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.ts b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.ts index 1f0f13eeb6ca9..565318578f990 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.ts @@ -84,7 +84,6 @@ export const logEntrySearchStrategyProvider = ({ tiebreakerField, runtimeMappings, }): IEsSearchRequest => ({ - // @ts-expect-error `Field` is not assignable to `SearchRequest.docvalue_fields` params: createGetLogEntryQuery( indices, params.logEntryId, diff --git a/x-pack/plugins/infra/server/services/log_entries/queries/log_entries.ts b/x-pack/plugins/infra/server/services/log_entries/queries/log_entries.ts index 9022195dce85d..6ca6d5ecd0191 100644 --- a/x-pack/plugins/infra/server/services/log_entries/queries/log_entries.ts +++ b/x-pack/plugins/infra/server/services/log_entries/queries/log_entries.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as rt from 'io-ts'; import { LogEntryAfterCursor, @@ -53,7 +53,6 @@ export const createGetLogEntriesQuery = ( }, }, fields, - // @ts-expect-error @elastic/elasticsearch doesn't declare "runtime_mappings" property runtime_mappings: runtimeMappings, _source: false, ...createSortClause(sortDirection, timestampField, tiebreakerField), @@ -87,7 +86,7 @@ const createHighlightClause = (highlightQuery: JsonObject | undefined, fields: s highlightQuery ? { highlight: { - boundary_scanner: 'word', + boundary_scanner: 'word' as const, fields: fields.reduce( (highlightFieldConfigs, fieldName) => ({ ...highlightFieldConfigs, diff --git a/x-pack/plugins/infra/server/services/log_entries/queries/log_entry.ts b/x-pack/plugins/infra/server/services/log_entries/queries/log_entry.ts index 8da2f1d685db3..856f8b1af9770 100644 --- a/x-pack/plugins/infra/server/services/log_entries/queries/log_entry.ts +++ b/x-pack/plugins/infra/server/services/log_entries/queries/log_entry.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import * as rt from 'io-ts'; import { jsonArrayRT } from '../../../../common/typed_json'; import { @@ -32,7 +32,6 @@ export const createGetLogEntryQuery = ( }, }, fields: ['*'], - // @ts-expect-error @elastic/elasticsearch doesn't declare "runtime_mappings" property runtime_mappings: runtimeMappings, sort: [{ [timestampField]: 'desc' }, { [tiebreakerField]: 'desc' }], _source: false, diff --git a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts index 1ab290796e36d..b5b4b731472c4 100644 --- a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts +++ b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; +import { TransportResult } from '@elastic/elasticsearch'; import { InfraDatabaseSearchResponse } from '../lib/adapters/framework'; export const getAllCompositeData = async < @@ -15,7 +15,7 @@ export const getAllCompositeData = async < >( esClientSearch: ( options: Options - ) => Promise>>, + ) => Promise>>, options: Options, bucketSelector: (response: InfraDatabaseSearchResponse<{}, Aggregation>) => Bucket[], onAfterKey: (options: Options, response: InfraDatabaseSearchResponse<{}, Aggregation>) => Options, diff --git a/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts index d2669e7c0012b..248797c652c6a 100644 --- a/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts +++ b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Pipeline, Processor } from '../types'; export function deserializePipelines(pipelinesByName: { diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts index 5368b59b35a41..a2882fd7855d6 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts @@ -41,6 +41,7 @@ export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) = const { body: { has_all_requested: hasAllPrivileges, cluster }, } = await clusterClient.asCurrentUser.security.hasPrivileges({ + // @ts-expect-error @elastic/elasticsearch SecurityClusterPrivilege doesn’t contain all the priviledges body: { cluster: APP_CLUSTER_REQUIRED_PRIVILEGES }, }); diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts index c133b9237102a..c6d628294a734 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { API_BASE_PATH } from '../../../common/constants'; @@ -38,7 +38,7 @@ export const registerSimulateRoute = ({ verbose, body: { pipeline, - docs: documents as estypes.IngestSimulatePipelineDocument[], + docs: documents as estypes.IngestSimulateDocument[], }, }); diff --git a/x-pack/plugins/lens/common/expressions/xy_chart/xy_args.ts b/x-pack/plugins/lens/common/expressions/xy_chart/xy_args.ts index fb794eda22dbe..f00608135820a 100644 --- a/x-pack/plugins/lens/common/expressions/xy_chart/xy_args.ts +++ b/x-pack/plugins/lens/common/expressions/xy_chart/xy_args.ts @@ -12,8 +12,7 @@ import type { LayerArgs } from './layer_config'; import type { LegendConfigResult } from './legend_config'; import type { TickLabelsConfigResult } from './tick_labels_config'; import type { LabelsOrientationConfigResult } from './labels_orientation_config'; - -export type ValueLabelConfig = 'hide' | 'inside' | 'outside'; +import type { ValueLabelConfig } from '../../types'; export type XYCurveType = 'LINEAR' | 'CURVE_MONOTONE_X'; diff --git a/x-pack/plugins/lens/common/types.ts b/x-pack/plugins/lens/common/types.ts index 38e198c01e730..307ed856c7c66 100644 --- a/x-pack/plugins/lens/common/types.ts +++ b/x-pack/plugins/lens/common/types.ts @@ -62,3 +62,6 @@ export interface CustomPaletteParams { export type RequiredPaletteParamTypes = Required; export type LayerType = 'data' | 'referenceLine'; + +// Shared by XY Chart and Heatmap as for now +export type ValueLabelConfig = 'hide' | 'inside' | 'outside'; diff --git a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx index 677cb9d20c25b..c999656071ef4 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx @@ -288,6 +288,9 @@ export const HeatmapComponent: FC = ({ maxHeight: 'fill', label: { visible: args.gridConfig.isCellLabelVisible ?? false, + minFontSize: 8, + maxFontSize: 18, + useGlobalMinFontSize: true, // override the min if there's a different directive upstream }, border: { strokeWidth: 0, diff --git a/x-pack/plugins/lens/public/heatmap_visualization/toolbar_component.tsx b/x-pack/plugins/lens/public/heatmap_visualization/toolbar_component.tsx index 80954516f0418..88966acd22691 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/toolbar_component.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/toolbar_component.tsx @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Position } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import type { VisualizationToolbarProps } from '../types'; -import { LegendSettingsPopover } from '../shared_components'; +import { LegendSettingsPopover, ToolbarPopover, ValueLabelsSettings } from '../shared_components'; import type { HeatmapVisualizationState } from './types'; const legendOptions: Array<{ id: string; value: 'auto' | 'show' | 'hide'; label: string }> = [ @@ -37,11 +37,29 @@ export const HeatmapToolbar = memo( const legendMode = state.legend.isVisible ? 'show' : 'hide'; return ( - + + + { + setState({ + ...state, + gridConfig: { ...state.gridConfig, isCellLabelVisible: newMode === 'inside' }, + }); + }} + /> + { diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index 84302f25d0a02..9be07a4f44dcd 100644 --- a/x-pack/plugins/lens/public/index.ts +++ b/x-pack/plugins/lens/public/index.ts @@ -22,11 +22,11 @@ export type { XYLayerConfig, LegendConfig, SeriesType, - ValueLabelConfig, YAxisMode, XYCurveType, YConfig, } from '../common/expressions'; +export type { ValueLabelConfig } from '../common/types'; export type { DatatableVisualizationState } from './datatable_visualization/visualization'; export type { IndexPatternPersistedState, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index b85652481d5b2..2877094ac81f8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -52,7 +52,7 @@ jest.mock('lodash', () => { const dataPluginMockValue = dataPluginMock.createStartContract(); // need to overwrite the formatter field first -dataPluginMockValue.fieldFormats.deserialize = jest.fn().mockImplementation(({ params }) => { +dataPluginMockValue.fieldFormats.deserialize = jest.fn().mockImplementation(({ id, params }) => { return { convert: ({ gte, lt }: { gte: string; lt: string }) => { if (params?.id === 'custom') { @@ -61,6 +61,9 @@ dataPluginMockValue.fieldFormats.deserialize = jest.fn().mockImplementation(({ p if (params?.id === 'bytes') { return `Bytes format: ${gte} - ${lt}`; } + if (!id) { + return 'Error'; + } return `${gte} - ${lt}`; }, }; @@ -476,6 +479,49 @@ describe('ranges', () => { expect(instance.find(DragDropBuckets).children).toHaveLength(1); }); + it('should use the parentFormat to create the trigger label', () => { + const updateLayerSpy = jest.fn(); + + const instance = mount( + + ); + + expect( + instance.find('[data-test-subj="indexPattern-ranges-popover-trigger"]').first().text() + ).toBe('0 - 1000'); + }); + + it('should not print error if the parentFormat is not provided', () => { + // while in the actual React implementation will print an error, here + // we intercept the formatter without an id assigned an print "Error" + const updateLayerSpy = jest.fn(); + + const instance = mount( + + ); + + expect( + instance.find('[data-test-subj="indexPattern-ranges-popover-trigger"]').first().text() + ).not.toBe('Error'); + }); + it('should add a new range', () => { const updateLayerSpy = jest.fn(); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index 29e7de18ca4ad..6e397a926c7a0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -196,7 +196,7 @@ export const rangeOperation: OperationDefinition { + let props: VisualOptionsProps; + beforeEach(() => { + props = { + onValueLabelChange: jest.fn(), + }; + }); + + it('should not render the component if not enabled', () => { + const component = shallow(); + expect(component.find('[data-test-subj="lens-value-labels-visibility-btn"]').length).toEqual(0); + }); + + it('should set hide as default value', () => { + const component = shallow(); + expect( + component.find('[data-test-subj="lens-value-labels-visibility-btn"]').prop('idSelected') + ).toEqual(`value_labels_hide`); + }); + + it('should have called onValueLabelChange function on ButtonGroup change', () => { + const component = shallow(); + component + .find('[data-test-subj="lens-value-labels-visibility-btn"]') + .simulate('change', 'value_labels_inside'); + expect(props.onValueLabelChange).toHaveBeenCalled(); + }); + + it('should render the passed value if given', () => { + const component = shallow(); + expect( + component.find('[data-test-subj="lens-value-labels-visibility-btn"]').prop('idSelected') + ).toEqual(`value_labels_inside`); + }); +}); diff --git a/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx b/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx new file mode 100644 index 0000000000000..64d9f5475379a --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButtonGroup, EuiFormRow } from '@elastic/eui'; +import { ValueLabelConfig } from '../../common/types'; + +const valueLabelsOptions: Array<{ + id: string; + value: ValueLabelConfig; + label: string; + 'data-test-subj': string; +}> = [ + { + id: `value_labels_hide`, + value: 'hide', + label: i18n.translate('xpack.lens.shared.valueLabelsVisibility.auto', { + defaultMessage: 'Hide', + }), + 'data-test-subj': 'lns_valueLabels_hide', + }, + { + id: `value_labels_inside`, + value: 'inside', + label: i18n.translate('xpack.lens.shared.valueLabelsVisibility.inside', { + defaultMessage: 'Show', + }), + 'data-test-subj': 'lns_valueLabels_inside', + }, +]; + +export interface VisualOptionsProps { + isVisible?: boolean; + valueLabels?: ValueLabelConfig; + onValueLabelChange: (newMode: ValueLabelConfig) => void; +} + +export const ValueLabelsSettings: FC = ({ + isVisible = true, + valueLabels = 'hide', + onValueLabelChange, +}) => { + if (!isVisible) { + return null; + } + const label = i18n.translate('xpack.lens.shared.chartValueLabelVisibilityLabel', { + defaultMessage: 'Labels', + }); + const isSelected = + valueLabelsOptions.find(({ value }) => value === valueLabels)?.id || 'value_labels_hide'; + return ( + {label}}> + { + const newMode = valueLabelsOptions.find(({ id }) => id === modeId); + if (newMode) { + onValueLabelChange(newMode.value); + } + }} + /> + + ); +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 5f9abba3806cf..e91f9d54ca86c 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -1445,6 +1445,40 @@ describe('xy_expression', () => { }); }); + test('sets up correct yScaleType equal to binary_linear for bytes formatting', () => { + const { args, data } = sampleArgs(); + data.tables.first.columns[0].meta = { + type: 'number', + params: { id: 'bytes', params: { pattern: '0,0.00b' } }, + }; + + const wrapper = mountWithIntl( + + ); + + expect(wrapper.find(LineSeries).at(0).prop('yScaleType')).toEqual('linear_binary'); + }); + test('allowBrushingLastHistogramBin should be fakse for ordinal data', () => { const { args, data } = sampleArgs(); diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 32ca4c982c10e..a3022e830c861 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -31,6 +31,7 @@ import { LabelOverflowConstraint, DisplayValueStyle, RecursivePartial, + ScaleType, } from '@elastic/charts'; import { I18nProvider } from '@kbn/i18n/react'; import type { @@ -767,6 +768,8 @@ export function XYChart({ axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) ); + const formatter = table?.columns.find((column) => column.id === accessor)?.meta?.params; + const seriesProps: SeriesSpec = { splitSeriesAccessors: splitAccessor ? [splitAccessor] : [], stackAccessors: isStacked ? [xAccessor as string] : [], @@ -775,7 +778,10 @@ export function XYChart({ yAccessors: [accessor], data: rows, xScaleType: xAccessor ? xScaleType : 'ordinal', - yScaleType, + yScaleType: + formatter?.id === 'bytes' && yScaleType === ScaleType.Linear + ? ScaleType.LinearBinary + : yScaleType, color: ({ yAccessor, seriesKeys }) => { const overwriteColor = getSeriesColor(layer, accessor); if (overwriteColor !== null) { diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index 4729cfb96f324..475571b2965f6 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -20,7 +20,6 @@ import { LensIconChartLine } from '../assets/chart_line'; import type { VisualizationType } from '../types'; import type { SeriesType, - ValueLabelConfig, LegendConfig, AxisExtentConfig, XYLayerConfig, @@ -29,6 +28,7 @@ import type { FittingFunction, LabelsOrientationConfig, } from '../../common/expressions'; +import type { ValueLabelConfig } from '../../common/types'; // Persisted parts of the state export interface XYState { diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx index 2a19897445e63..8ea6f9ace6320 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ToolbarPopover, TooltipWrapper } from '../../../shared_components'; +import { ToolbarPopover, TooltipWrapper, ValueLabelsSettings } from '../../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; import { FillOpacityOption } from './fill_opacity_option'; @@ -102,14 +102,17 @@ export const VisualOptionsPopover: React.FC = ({ }} /> - { setState({ ...state, valueLabels: newMode }); }} + /> + + { setState({ ...state, fittingFunction: newVal }); }} diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx index 851b14839d7f7..ce4e05223b5a3 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx @@ -7,70 +7,23 @@ import React from 'react'; import { shallowWithIntl as shallow, mountWithIntl as mount } from '@kbn/test/jest'; -import { EuiSuperSelect, EuiButtonGroup } from '@elastic/eui'; +import { EuiSuperSelect } from '@elastic/eui'; import { MissingValuesOptions } from './missing_values_option'; describe('Missing values option', () => { it('should show currently selected fitting function', () => { const component = shallow( - + ); expect(component.find(EuiSuperSelect).prop('valueOfSelected')).toEqual('Carry'); }); - it('should show currently selected value labels display setting', () => { - const component = mount( - - ); - - expect(component.find(EuiButtonGroup).prop('idSelected')).toEqual('value_labels_inside'); - }); - - it('should show display field when enabled', () => { - const component = mount( - - ); - - expect(component.exists('[data-test-subj="lnsValueLabelsDisplay"]')).toEqual(true); - }); - - it('should hide in display value label option when disabled', () => { - const component = mount( - - ); - - expect(component.exists('[data-test-subj="lnsValueLabelsDisplay"]')).toEqual(false); - }); - it('should show the fitting option when enabled', () => { const component = mount( ); @@ -82,9 +35,7 @@ describe('Missing values option', () => { const component = mount( ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx index b12e2d2f57112..a858d1c879efe 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx @@ -7,85 +7,23 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonGroup, EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; import { fittingFunctionDefinitions } from '../../../../common/expressions'; -import type { FittingFunction, ValueLabelConfig } from '../../../../common/expressions'; +import type { FittingFunction } from '../../../../common/expressions'; export interface MissingValuesOptionProps { - valueLabels?: ValueLabelConfig; fittingFunction?: FittingFunction; - onValueLabelChange: (newMode: ValueLabelConfig) => void; onFittingFnChange: (newMode: FittingFunction) => void; - isValueLabelsEnabled?: boolean; isFittingEnabled?: boolean; } -const valueLabelsOptions: Array<{ - id: string; - value: 'hide' | 'inside' | 'outside'; - label: string; - 'data-test-subj': string; -}> = [ - { - id: `value_labels_hide`, - value: 'hide', - label: i18n.translate('xpack.lens.xyChart.valueLabelsVisibility.auto', { - defaultMessage: 'Hide', - }), - 'data-test-subj': 'lnsXY_valueLabels_hide', - }, - { - id: `value_labels_inside`, - value: 'inside', - label: i18n.translate('xpack.lens.xyChart.valueLabelsVisibility.inside', { - defaultMessage: 'Show', - }), - 'data-test-subj': 'lnsXY_valueLabels_inside', - }, -]; - export const MissingValuesOptions: React.FC = ({ - onValueLabelChange, onFittingFnChange, - valueLabels, fittingFunction, - isValueLabelsEnabled = true, isFittingEnabled = true, }) => { - const valueLabelsVisibilityMode = valueLabels || 'hide'; - return ( <> - {isValueLabelsEnabled && ( - - {i18n.translate('xpack.lens.shared.chartValueLabelVisibilityLabel', { - defaultMessage: 'Labels', - })} - - } - > - value === valueLabelsVisibilityMode)!.id - } - onChange={(modeId) => { - const newMode = valueLabelsOptions.find(({ id }) => id === modeId)!.value; - onValueLabelChange(newMode); - }} - /> - - )} {isFittingEnabled && ( { /> ); - expect(component.find(MissingValuesOptions).prop('isValueLabelsEnabled')).toEqual(false); + expect(component.find(ValueLabelsSettings).prop('isVisible')).toEqual(false); expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); @@ -196,7 +196,7 @@ describe('Visual options popover', () => { /> ); - expect(component.find(MissingValuesOptions).prop('isValueLabelsEnabled')).toEqual(true); + expect(component.find(ValueLabelsSettings).prop('isVisible')).toEqual(true); }); it('should hide in the popover the display option for area and line series', () => { @@ -213,7 +213,7 @@ describe('Visual options popover', () => { /> ); - expect(component.find(MissingValuesOptions).prop('isValueLabelsEnabled')).toEqual(false); + expect(component.find(ValueLabelsSettings).prop('isVisible')).toEqual(false); }); it('should keep the display option for bar series with multiple layers', () => { @@ -245,6 +245,6 @@ describe('Visual options popover', () => { /> ); - expect(component.find(MissingValuesOptions).prop('isValueLabelsEnabled')).toEqual(true); + expect(component.find(ValueLabelsSettings).prop('isVisible')).toEqual(true); }); }); diff --git a/x-pack/plugins/lens/server/plugin.tsx b/x-pack/plugins/lens/server/plugin.tsx index e242fc8e4c5d6..42e68c6223b6d 100644 --- a/x-pack/plugins/lens/server/plugin.tsx +++ b/x-pack/plugins/lens/server/plugin.tsx @@ -7,7 +7,6 @@ import { Plugin, CoreSetup, CoreStart, PluginInitializerContext, Logger } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { Observable } from 'rxjs'; import { PluginStart as DataPluginStart } from 'src/plugins/data/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { FieldFormatsStart } from 'src/plugins/field_formats/server'; @@ -41,13 +40,12 @@ export interface LensServerPluginSetup { } export class LensServerPlugin implements Plugin { - private readonly kibanaIndexConfig: Observable<{ kibana: { index: string } }>; private readonly telemetryLogger: Logger; constructor(private initializerContext: PluginInitializerContext) { - this.kibanaIndexConfig = initializerContext.config.legacy.globalConfig$; this.telemetryLogger = initializerContext.logger.get('usage'); } + setup(core: CoreSetup, plugins: PluginSetupContract) { setupSavedObjects(core); setupRoutes(core, this.initializerContext.logger.get()); @@ -60,12 +58,7 @@ export class LensServerPlugin implements Plugin taskManager as TaskManagerStartContract) ); - initializeLensTelemetry( - this.telemetryLogger, - core, - this.kibanaIndexConfig, - plugins.taskManager - ); + initializeLensTelemetry(this.telemetryLogger, core, plugins.taskManager); } plugins.embeddable.registerEmbeddableFactory(lensEmbeddableFactory()); diff --git a/x-pack/plugins/lens/server/routes/existing_fields.ts b/x-pack/plugins/lens/server/routes/existing_fields.ts index f35b0a7f23179..704b248faeadb 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.ts @@ -6,7 +6,8 @@ */ import Boom from '@hapi/boom'; -import { errors, estypes } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { RequestHandlerContext, ElasticsearchClient } from 'src/core/server'; import { CoreSetup, Logger } from 'src/core/server'; diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/x-pack/plugins/lens/server/routes/field_stats.ts index 88e8e600aa906..9e48c00b9d8cb 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/x-pack/plugins/lens/server/routes/field_stats.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { errors, estypes } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import DateMath from '@elastic/datemath'; import { schema } from '@kbn/config-schema'; import { CoreSetup } from 'src/core/server'; diff --git a/x-pack/plugins/lens/server/usage/task.ts b/x-pack/plugins/lens/server/usage/task.ts index 9227ca885359b..6dfeb736eb45e 100644 --- a/x-pack/plugins/lens/server/usage/task.ts +++ b/x-pack/plugins/lens/server/usage/task.ts @@ -6,8 +6,6 @@ */ import { CoreSetup, Logger, ElasticsearchClient } from 'kibana/server'; -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import moment from 'moment'; import { RunContext, @@ -28,10 +26,9 @@ export const TASK_ID = `Lens-${TELEMETRY_TASK_TYPE}`; export function initializeLensTelemetry( logger: Logger, core: CoreSetup, - config: Observable<{ kibana: { index: string } }>, taskManager: TaskManagerSetupContract ) { - registerLensTelemetryTask(logger, core, config, taskManager); + registerLensTelemetryTask(logger, core, taskManager); } export function scheduleLensTelemetry(logger: Logger, taskManager?: TaskManagerStartContract) { @@ -43,14 +40,13 @@ export function scheduleLensTelemetry(logger: Logger, taskManager?: TaskManagerS function registerLensTelemetryTask( logger: Logger, core: CoreSetup, - config: Observable<{ kibana: { index: string } }>, taskManager: TaskManagerSetupContract ) { taskManager.registerTaskDefinitions({ [TELEMETRY_TASK_TYPE]: { title: 'Lens usage fetch task', timeout: '1m', - createTaskRunner: telemetryTaskRunner(logger, core, config), + createTaskRunner: telemetryTaskRunner(logger, core), }, }); } @@ -177,11 +173,7 @@ export async function getDailyEvents( }; } -export function telemetryTaskRunner( - logger: Logger, - core: CoreSetup, - config: Observable<{ kibana: { index: string } }> -) { +export function telemetryTaskRunner(logger: Logger, core: CoreSetup) { return ({ taskInstance }: RunContext) => { const { state } = taskInstance; const getEsClient = async () => { @@ -191,7 +183,7 @@ export function telemetryTaskRunner( return { async run() { - const kibanaIndex = (await config.pipe(first()).toPromise()).kibana.index; + const kibanaIndex = core.savedObjects.getKibanaIndex(); return Promise.all([ getDailyEvents(kibanaIndex, getEsClient), diff --git a/x-pack/plugins/license_management/server/lib/permissions.ts b/x-pack/plugins/license_management/server/lib/permissions.ts index 517854fad8e83..06395fb6302b6 100644 --- a/x-pack/plugins/license_management/server/lib/permissions.ts +++ b/x-pack/plugins/license_management/server/lib/permissions.ts @@ -20,14 +20,12 @@ export async function getPermissions({ isSecurityEnabled, client }: GetPermissio }; } - const options = { - body: { - cluster: ['manage'], // License management requires "manage" cluster privileges - }, - }; - try { - const { body: response } = await client.asCurrentUser.security.hasPrivileges(options); + const { body: response } = await client.asCurrentUser.security.hasPrivileges({ + body: { + cluster: ['manage'], // License management requires "manage" cluster privileges + }, + }); return { hasPermission: response.cluster.manage, }; diff --git a/x-pack/plugins/licensing/server/plugin.test.ts b/x-pack/plugins/licensing/server/plugin.test.ts index 1fe4bbf238e19..71a98098bb0f5 100644 --- a/x-pack/plugins/licensing/server/plugin.test.ts +++ b/x-pack/plugins/licensing/server/plugin.test.ts @@ -6,7 +6,7 @@ */ import { take, toArray } from 'rxjs/operators'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import moment from 'moment'; import { LicenseType } from '../common/types'; import { ElasticsearchError } from './types'; @@ -102,9 +102,6 @@ describe('licensing plugin', () => { await license$.pipe(take(1)).toPromise(); expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1); - expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledWith({ - accept_enterprise: true, - }); }); it('observable receives updated licenses', async () => { diff --git a/x-pack/plugins/licensing/server/plugin.ts b/x-pack/plugins/licensing/server/plugin.ts index 00d2ae602fcae..83379fe48ac9e 100644 --- a/x-pack/plugins/licensing/server/plugin.ts +++ b/x-pack/plugins/licensing/server/plugin.ts @@ -10,7 +10,7 @@ import moment from 'moment'; import { createHash } from 'crypto'; import stringify from 'json-stable-stringify'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { MaybePromise } from '@kbn/utility-types'; import { isPromise } from '@kbn/std'; import { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx index 1b25a2cb91e85..280dd8acbc7e5 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx @@ -81,6 +81,7 @@ export interface ExceptionBuilderProps { isAndDisabled: boolean; isNestedDisabled: boolean; isOrDisabled: boolean; + isOrHidden?: boolean; listId: string; listNamespaceType: NamespaceType; listType: ExceptionListType; @@ -103,6 +104,7 @@ export const ExceptionBuilderComponent = ({ isAndDisabled, isNestedDisabled, isOrDisabled, + isOrHidden = false, listId, listNamespaceType, listType, @@ -433,6 +435,7 @@ export const ExceptionBuilderComponent = ({ { expect(wrapper.find('[data-test-subj="exceptionsNestedButton"] button')).toHaveLength(0); }); + test('it hides "or" button', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="exceptionsOrButton"] button')).toHaveLength(0); + }); + test('it invokes "onOrClicked" when "or" button is clicked', () => { const onOrClicked = jest.fn(); diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx index 3846b844bb55a..aa308ecdc3452 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx @@ -20,6 +20,7 @@ interface BuilderLogicButtonsProps { isNested: boolean; isNestedDisabled: boolean; isOrDisabled: boolean; + isOrHidden?: boolean; showNestedButton: boolean; onAddClickWhenNested: () => void; onAndClicked: () => void; @@ -32,6 +33,7 @@ export const BuilderLogicButtons: React.FC = ({ isNested, isNestedDisabled = true, isOrDisabled = false, + isOrHidden = false, showNestedButton = false, onAddClickWhenNested, onAndClicked, @@ -50,18 +52,20 @@ export const BuilderLogicButtons: React.FC = ({ {i18n.AND} - - - {i18n.OR} - - + {!isOrHidden && ( + + + {i18n.OR} + + + )} {showNestedButton && ( ({ failed: 0, diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts b/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts index 2f213ccfbad06..682c77cf5c83b 100644 --- a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DATE_NOW, diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts b/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts index 2cfbaf26f9d6a..5dde9cc14d4a1 100644 --- a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts +++ b/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DATE_NOW, diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts b/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts index 1c1ce872a402d..99c2f18877032 100644 --- a/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts +++ b/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts index 1bf337dbd7532..565e8a3e196c5 100644 --- a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts +++ b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts @@ -7,7 +7,7 @@ import { PassThrough } from 'stream'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from 'kibana/server'; import { ErrorWithStatusCode } from '../../error_with_status_code'; diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts b/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts index db667951381b0..8d0d2501475e6 100644 --- a/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts +++ b/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isEmpty, isObject } from 'lodash/fp'; import type { Type } from '@kbn/securitysolution-io-ts-list-types'; diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts b/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts index 7db46ce1a464c..37794228bd693 100644 --- a/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts +++ b/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SortFieldOrUndefined } from '@kbn/securitysolution-io-ts-list-types'; export type TieBreaker = T & { diff --git a/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts b/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts index 8a513483f5b5e..e8fae957a5615 100644 --- a/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts +++ b/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SortFieldOrUndefined, SortOrderOrUndefined } from '@kbn/securitysolution-io-ts-list-types'; export const getSortWithTieBreaker = ({ diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts b/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts index b669b983fe46d..0a3632efe9195 100644 --- a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts +++ b/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SearchListItemArraySchema, Type } from '@kbn/securitysolution-io-ts-list-types'; import { SearchEsListItemSchema } from '../../schemas/elastic_response'; diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts index 5b0949d7b79b7..3242742c1cfd6 100644 --- a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts +++ b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ListArraySchema } from '@kbn/securitysolution-io-ts-list-types'; import { encodeHitVersion } from '@kbn/securitysolution-es-utils'; diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts index 65392f8c379d9..3edbab94a0cfd 100644 --- a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts +++ b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ListItemArraySchema, Type } from '@kbn/securitysolution-io-ts-list-types'; import { encodeHitVersion } from '@kbn/securitysolution-es-utils'; diff --git a/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts b/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts index 10c1d1ba24ae0..9fe03cd411b81 100755 --- a/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts +++ b/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Cluster } from './cluster'; describe('cluster', () => { diff --git a/x-pack/plugins/logstash/server/models/cluster/cluster.ts b/x-pack/plugins/logstash/server/models/cluster/cluster.ts index 2982284879c47..6c1712eb4797e 100755 --- a/x-pack/plugins/logstash/server/models/cluster/cluster.ts +++ b/x-pack/plugins/logstash/server/models/cluster/cluster.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /** * This model deals with a cluster object from ES and converts it to Kibana downstream diff --git a/x-pack/plugins/logstash/server/routes/pipeline/save.ts b/x-pack/plugins/logstash/server/routes/pipeline/save.ts index 48a62f83c91ca..83f6ee9b00ba9 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/save.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/save.ts @@ -47,6 +47,7 @@ export function registerPipelineSaveRoute( await client.asCurrentUser.logstash.putPipeline({ id: pipeline.id, + // @ts-expect-error description is required body: pipeline.upstreamJSON, }); diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index b6b3e636fffeb..86d1a38b4939f 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -9,22 +9,6 @@ import { i18n } from '@kbn/i18n'; import { FeatureCollection } from 'geojson'; export const EMS_APP_NAME = 'kibana'; - -export const EMS_FILES_CATALOGUE_PATH = 'ems/files'; -export const EMS_FILES_API_PATH = 'ems/files'; -export const EMS_FILES_DEFAULT_JSON_PATH = 'file'; -export const EMS_GLYPHS_PATH = 'fonts'; -export const EMS_SPRITES_PATH = 'sprites'; - -export const EMS_TILES_CATALOGUE_PATH = 'ems/tiles'; -export const EMS_TILES_API_PATH = 'ems/tiles'; -export const EMS_TILES_RASTER_STYLE_PATH = 'raster/style'; -export const EMS_TILES_RASTER_TILE_PATH = 'raster/tile'; - -export const EMS_TILES_VECTOR_STYLE_PATH = 'vector/style'; -export const EMS_TILES_VECTOR_SOURCE_PATH = 'vector/source'; -export const EMS_TILES_VECTOR_TILE_PATH = 'vector/tile'; - export const MAP_SAVED_OBJECT_TYPE = 'map'; export const APP_ID = 'maps'; export const APP_ICON = 'gisApp'; @@ -47,14 +31,7 @@ export const CHECK_IS_DRAWING_INDEX = `/${GIS_API_PATH}/checkIsDrawingIndex`; export const MVT_GETTILE_API_PATH = 'mvt/getTile'; export const MVT_GETGRIDTILE_API_PATH = 'mvt/getGridTile'; -export const MVT_SOURCE_LAYER_NAME = 'source_layer'; -// Identifies vector tile "too many features" feature. -// "too many features" feature is a box showing area that contains too many features for single ES search response -export const KBN_METADATA_FEATURE = '__kbn_metadata_feature__'; -export const KBN_FEATURE_COUNT = '__kbn_feature_count__'; -export const KBN_IS_TILE_COMPLETE = '__kbn_is_tile_complete__'; -export const KBN_VECTOR_SHAPE_TYPE_COUNTS = '__kbn_vector_shape_type_counts__'; -export const KBN_TOO_MANY_FEATURES_IMAGE_ID = '__kbn_too_many_features_image_id__'; + // Identifies centroid feature. // Centroids are a single point for representing lines, multiLines, polygons, and multiPolygons export const KBN_IS_CENTROID_FEATURE = '__kbn_is_centroid_feature__'; @@ -119,7 +96,6 @@ export const DEFAULT_MAX_RESULT_WINDOW = 10000; export const DEFAULT_MAX_INNER_RESULT_WINDOW = 100; export const DEFAULT_MAX_BUCKETS_LIMIT = 65535; -export const FEATURE_ID_PROPERTY_NAME = '__kbn__feature_id__'; export const FEATURE_VISIBLE_PROPERTY_NAME = '__kbn_isvisibleduetojoin__'; export const MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER = '_'; @@ -314,5 +290,3 @@ export const MAPS_NEW_VECTOR_LAYER_META_CREATED_BY = 'maps-new-vector-layer'; export const MAX_DRAWING_SIZE_BYTES = 10485760; // 10MB export const emsWorldLayerId = 'world_countries'; -export const emsRegionLayerId = 'administrative_regions_lvl2'; -export const emsUsaZipLayerId = 'usa_zip_codes'; diff --git a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts index 244ebc59efd17..8f681cc9de70d 100644 --- a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts @@ -10,21 +10,13 @@ import { Query } from 'src/plugins/data/public'; import { Feature } from 'geojson'; import { - FieldMeta, HeatmapStyleDescriptor, StyleDescriptor, VectorStyleDescriptor, } from './style_property_descriptor_types'; import { DataRequestDescriptor } from './data_request_descriptor_types'; import { AbstractSourceDescriptor, TermJoinSourceDescriptor } from './source_descriptor_types'; -import { VectorShapeTypeCounts } from '../get_geometry_counts'; -import { - KBN_FEATURE_COUNT, - KBN_IS_TILE_COMPLETE, - KBN_METADATA_FEATURE, - KBN_VECTOR_SHAPE_TYPE_COUNTS, - LAYER_TYPE, -} from '../constants'; +import { LAYER_TYPE } from '../constants'; export type Attribution = { label: string; @@ -38,11 +30,8 @@ export type JoinDescriptor = { export type TileMetaFeature = Feature & { properties: { - [KBN_METADATA_FEATURE]: true; - [KBN_IS_TILE_COMPLETE]: boolean; - [KBN_FEATURE_COUNT]: number; - [KBN_VECTOR_SHAPE_TYPE_COUNTS]: VectorShapeTypeCounts; - fieldMeta?: FieldMeta; + 'hits.total.relation': string; + 'hits.total.value': number; }; }; diff --git a/x-pack/plugins/maps/common/elasticsearch_util/index.ts b/x-pack/plugins/maps/common/elasticsearch_util/index.ts index 7073a4201f7a5..6febb237cdda7 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/index.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/index.ts @@ -6,7 +6,6 @@ */ export * from './es_agg_utils'; -export * from './convert_to_geojson'; export * from './elasticsearch_geo_utils'; export * from './spatial_filter_utils'; export * from './types'; diff --git a/x-pack/plugins/maps/common/ems_settings.test.ts b/x-pack/plugins/maps/common/ems_settings.test.ts index c299d535db193..82d7823250e4c 100644 --- a/x-pack/plugins/maps/common/ems_settings.test.ts +++ b/x-pack/plugins/maps/common/ems_settings.test.ts @@ -18,7 +18,6 @@ const IS_ENTERPRISE_PLUS = () => true; describe('EMSSettings', () => { const mockConfig: IEMSConfig = { includeElasticMapsService: true, - proxyElasticMapsServiceInMaps: false, emsUrl: '', emsFileApiUrl: DEFAULT_EMS_FILE_API_URL, emsTileApiUrl: DEFAULT_EMS_TILE_API_URL, diff --git a/x-pack/plugins/maps/common/ems_settings.ts b/x-pack/plugins/maps/common/ems_settings.ts index 166fc6fbdfc4c..f85351b2fdab2 100644 --- a/x-pack/plugins/maps/common/ems_settings.ts +++ b/x-pack/plugins/maps/common/ems_settings.ts @@ -15,7 +15,6 @@ import { export interface IEMSConfig { emsUrl?: string; includeElasticMapsService?: boolean; - proxyElasticMapsServiceInMaps?: boolean; emsFileApiUrl?: string; emsTileApiUrl?: string; emsLandingPageUrl?: string; @@ -63,10 +62,6 @@ export class EMSSettings { } } - isProxyElasticMapsServiceInMaps(): boolean { - return !!this._config.proxyElasticMapsServiceInMaps; - } - getEMSTileApiUrl(): string { if (this._config.emsTileApiUrl !== DEFAULT_EMS_TILE_API_URL || !this.isEMSUrlSet()) { return this._config.emsTileApiUrl!; diff --git a/x-pack/plugins/maps/common/get_geometry_counts.ts b/x-pack/plugins/maps/common/get_geometry_counts.ts deleted file mode 100644 index 2a3368560c762..0000000000000 --- a/x-pack/plugins/maps/common/get_geometry_counts.ts +++ /dev/null @@ -1,45 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Feature } from 'geojson'; -import { GEO_JSON_TYPE, VECTOR_SHAPE_TYPE } from './constants'; - -export interface VectorShapeTypeCounts { - [VECTOR_SHAPE_TYPE.POINT]: number; - [VECTOR_SHAPE_TYPE.LINE]: number; - [VECTOR_SHAPE_TYPE.POLYGON]: number; -} - -export function countVectorShapeTypes(features: Feature[]): VectorShapeTypeCounts { - const vectorShapeTypeCounts: VectorShapeTypeCounts = { - [VECTOR_SHAPE_TYPE.POINT]: 0, - [VECTOR_SHAPE_TYPE.LINE]: 0, - [VECTOR_SHAPE_TYPE.POLYGON]: 0, - }; - - for (let i = 0; i < features.length; i++) { - const feature: Feature = features[i]; - if ( - feature.geometry.type === GEO_JSON_TYPE.POINT || - feature.geometry.type === GEO_JSON_TYPE.MULTI_POINT - ) { - vectorShapeTypeCounts[VECTOR_SHAPE_TYPE.POINT] += 1; - } else if ( - feature.geometry.type === GEO_JSON_TYPE.LINE_STRING || - feature.geometry.type === GEO_JSON_TYPE.MULTI_LINE_STRING - ) { - vectorShapeTypeCounts[VECTOR_SHAPE_TYPE.LINE] += 1; - } else if ( - feature.geometry.type === GEO_JSON_TYPE.POLYGON || - feature.geometry.type === GEO_JSON_TYPE.MULTI_POLYGON - ) { - vectorShapeTypeCounts[VECTOR_SHAPE_TYPE.POLYGON] += 1; - } - } - - return vectorShapeTypeCounts; -} diff --git a/x-pack/plugins/maps/common/pluck_category_field_meta.ts b/x-pack/plugins/maps/common/pluck_category_field_meta.ts deleted file mode 100644 index c71316f864a84..0000000000000 --- a/x-pack/plugins/maps/common/pluck_category_field_meta.ts +++ /dev/null @@ -1,46 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Feature } from 'geojson'; -import { CategoryFieldMeta } from './descriptor_types'; - -export function pluckCategoryFieldMeta( - features: Feature[], - name: string, - size: number -): CategoryFieldMeta | null { - const counts = new Map(); - for (let i = 0; i < features.length; i++) { - const feature = features[i]; - const term = feature.properties ? feature.properties[name] : undefined; - // properties object may be sparse, so need to check if the field is effectively present - if (typeof term !== undefined) { - if (counts.has(term)) { - counts.set(term, counts.get(term) + 1); - } else { - counts.set(term, 1); - } - } - } - - return trimCategories(counts, size); -} - -export function trimCategories(counts: Map, size: number): CategoryFieldMeta { - const ordered = []; - for (const [key, value] of counts) { - ordered.push({ key, count: value }); - } - - ordered.sort((a, b) => { - return b.count - a.count; - }); - const truncated = ordered.slice(0, size); - return { - categories: truncated, - } as CategoryFieldMeta; -} diff --git a/x-pack/plugins/maps/common/pluck_range_field_meta.ts b/x-pack/plugins/maps/common/pluck_range_field_meta.ts deleted file mode 100644 index b0bf03896892f..0000000000000 --- a/x-pack/plugins/maps/common/pluck_range_field_meta.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Feature } from 'geojson'; -import { RangeFieldMeta } from './descriptor_types'; - -export function pluckRangeFieldMeta( - features: Feature[], - name: string, - parseValue: (rawValue: unknown) => number -): RangeFieldMeta | null { - let min = Infinity; - let max = -Infinity; - for (let i = 0; i < features.length; i++) { - const feature = features[i]; - const newValue = feature.properties ? parseValue(feature.properties[name]) : NaN; - if (!isNaN(newValue)) { - min = Math.min(min, newValue); - max = Math.max(max, newValue); - } - } - - return min === Infinity || max === -Infinity - ? null - : ({ - min, - max, - delta: max - min, - } as RangeFieldMeta); -} diff --git a/x-pack/plugins/maps/public/actions/data_request_actions.ts b/x-pack/plugins/maps/public/actions/data_request_actions.ts index b912e8c52e680..c1a6d05cc0577 100644 --- a/x-pack/plugins/maps/public/actions/data_request_actions.ts +++ b/x-pack/plugins/maps/public/actions/data_request_actions.ts @@ -282,10 +282,10 @@ function endDataLoad( if (dataId === SOURCE_DATA_REQUEST_ID) { const features = data && 'features' in data ? (data as FeatureCollection).features : []; + const layer = getLayerById(layerId, getState()); const eventHandlers = getEventHandlers(getState()); if (eventHandlers && eventHandlers.onDataLoadEnd) { - const layer = getLayerById(layerId, getState()); const resultMeta: ResultMeta = {}; if (layer && layer.getType() === LAYER_TYPE.VECTOR) { const featuresWithoutCentroids = features.filter((feature) => { @@ -301,7 +301,9 @@ function endDataLoad( }); } - dispatch(updateTooltipStateForLayer(layerId, features)); + if (layer) { + dispatch(updateTooltipStateForLayer(layer, features)); + } } dispatch({ @@ -344,7 +346,10 @@ function onDataLoadError( }); } - dispatch(updateTooltipStateForLayer(layerId)); + const layer = getLayerById(layerId, getState()); + if (layer) { + dispatch(updateTooltipStateForLayer(layer)); + } } dispatch({ @@ -359,7 +364,10 @@ function onDataLoadError( } export function updateSourceDataRequest(layerId: string, newData: object) { - return (dispatch: ThunkDispatch) => { + return ( + dispatch: ThunkDispatch, + getState: () => MapStoreState + ) => { dispatch({ type: UPDATE_SOURCE_DATA_REQUEST, dataId: SOURCE_DATA_REQUEST_ID, @@ -368,7 +376,10 @@ export function updateSourceDataRequest(layerId: string, newData: object) { }); if ('features' in newData) { - dispatch(updateTooltipStateForLayer(layerId, (newData as FeatureCollection).features)); + const layer = getLayerById(layerId, getState()); + if (layer) { + dispatch(updateTooltipStateForLayer(layer, (newData as FeatureCollection).features)); + } } dispatch(updateStyleMeta(layerId)); diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 9e937d86515e2..c9254df40bcf1 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -51,6 +51,7 @@ import { } from '../../common/descriptor_types'; import { ILayer } from '../classes/layers/layer'; import { IVectorLayer } from '../classes/layers/vector_layer'; +import { OnSourceChangeArgs } from '../classes/sources/source'; import { DRAW_MODE, LAYER_STYLE_TYPE, LAYER_TYPE } from '../../common/constants'; import { IVectorStyle } from '../classes/styles/vector/vector_style'; import { notifyLicensedFeatureUsage } from '../licensed_features'; @@ -217,7 +218,7 @@ export function setLayerVisibility(layerId: string, makeVisible: boolean) { } if (!makeVisible) { - dispatch(updateTooltipStateForLayer(layerId)); + dispatch(updateTooltipStateForLayer(layer)); } dispatch({ @@ -323,18 +324,17 @@ function updateMetricsProp(layerId: string, value: unknown) { ) => { const layer = getLayerById(layerId, getState()); const previousFields = await (layer as IVectorLayer).getFields(); - await dispatch({ + dispatch({ type: UPDATE_SOURCE_PROP, layerId, propName: 'metrics', value, }); await dispatch(updateStyleProperties(layerId, previousFields as IESAggField[])); - dispatch(syncDataForLayerId(layerId, false)); }; } -export function updateSourceProp( +function updateSourcePropWithoutSync( layerId: string, propName: string, value: unknown, @@ -356,6 +356,28 @@ export function updateSourceProp( if (newLayerType) { dispatch(updateLayerType(layerId, newLayerType)); } + }; +} + +export function updateSourceProp( + layerId: string, + propName: string, + value: unknown, + newLayerType?: LAYER_TYPE +) { + return async (dispatch: ThunkDispatch) => { + await dispatch(updateSourcePropWithoutSync(layerId, propName, value, newLayerType)); + dispatch(syncDataForLayerId(layerId, false)); + }; +} + +export function updateSourceProps(layerId: string, sourcePropChanges: OnSourceChangeArgs[]) { + return async (dispatch: ThunkDispatch) => { + // Using for loop to ensure update completes before starting next update + for (let i = 0; i < sourcePropChanges.length; i++) { + const { propName, value, newLayerType } = sourcePropChanges[i]; + await dispatch(updateSourcePropWithoutSync(layerId, propName, value, newLayerType)); + } dispatch(syncDataForLayerId(layerId, false)); }; } @@ -504,7 +526,7 @@ function removeLayerFromLayerList(layerId: string) { layerGettingRemoved.getInFlightRequestTokens().forEach((requestToken) => { dispatch(cancelRequest(requestToken)); }); - dispatch(updateTooltipStateForLayer(layerId)); + dispatch(updateTooltipStateForLayer(layerGettingRemoved)); layerGettingRemoved.destroy(); dispatch({ type: REMOVE_LAYER, diff --git a/x-pack/plugins/maps/public/actions/map_actions.ts b/x-pack/plugins/maps/public/actions/map_actions.ts index cf1e22ab90f88..d921f9748f65c 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.ts @@ -63,7 +63,7 @@ import { INITIAL_LOCATION } from '../../common/constants'; import { updateTooltipStateForLayer } from './tooltip_actions'; import { VectorLayer } from '../classes/layers/vector_layer'; import { SET_DRAW_MODE } from './ui_actions'; -import { expandToTileBoundaries } from '../../common/geo_tile_utils'; +import { expandToTileBoundaries } from '../classes/util/geo_tile_utils'; import { getToasts } from '../kibana_services'; export function setMapInitError(errorMessage: string) { @@ -171,7 +171,7 @@ export function mapExtentChanged(mapExtentState: MapExtentState) { if (prevZoom !== nextZoom) { getLayerList(getState()).map((layer) => { if (!layer.showAtZoomLevel(nextZoom)) { - dispatch(updateTooltipStateForLayer(layer.getId())); + dispatch(updateTooltipStateForLayer(layer)); } }); } diff --git a/x-pack/plugins/maps/public/actions/tooltip_actions.ts b/x-pack/plugins/maps/public/actions/tooltip_actions.ts index 67b6842caeb46..f1842ade4277e 100644 --- a/x-pack/plugins/maps/public/actions/tooltip_actions.ts +++ b/x-pack/plugins/maps/public/actions/tooltip_actions.ts @@ -10,9 +10,11 @@ import { Dispatch } from 'redux'; import { Feature } from 'geojson'; import { getOpenTooltips } from '../selectors/map_selectors'; import { SET_OPEN_TOOLTIPS } from './map_action_constants'; -import { FEATURE_ID_PROPERTY_NAME, FEATURE_VISIBLE_PROPERTY_NAME } from '../../common/constants'; +import { FEATURE_VISIBLE_PROPERTY_NAME } from '../../common/constants'; import { TooltipFeature, TooltipState } from '../../common/descriptor_types'; import { MapStoreState } from '../reducers/store'; +import { ILayer } from '../classes/layers/layer'; +import { IVectorLayer, isVectorLayer } from '../classes/layers/vector_layer'; export function closeOnClickTooltip(tooltipId: string) { return (dispatch: Dispatch, getState: () => MapStoreState) => { @@ -62,13 +64,17 @@ export function openOnHoverTooltip(tooltipState: TooltipState) { }; } -export function updateTooltipStateForLayer(layerId: string, layerFeatures: Feature[] = []) { +export function updateTooltipStateForLayer(layer: ILayer, layerFeatures: Feature[] = []) { return (dispatch: Dispatch, getState: () => MapStoreState) => { + if (!isVectorLayer(layer)) { + return; + } + const openTooltips = getOpenTooltips(getState()) .map((tooltipState) => { const nextFeatures: TooltipFeature[] = []; tooltipState.features.forEach((tooltipFeature) => { - if (tooltipFeature.layerId !== layerId) { + if (tooltipFeature.layerId !== layer.getId()) { // feature from another layer, keep it nextFeatures.push(tooltipFeature); } @@ -79,7 +85,7 @@ export function updateTooltipStateForLayer(layerId: string, layerFeatures: Featu ? layerFeature.properties![FEATURE_VISIBLE_PROPERTY_NAME] : true; return ( - isVisible && layerFeature.properties![FEATURE_ID_PROPERTY_NAME] === tooltipFeature.id + isVisible && (layer as IVectorLayer).getFeatureId(layerFeature) === tooltipFeature.id ); }); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts index 70d5cea6e4620..acfe6a9055eb6 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts @@ -34,6 +34,10 @@ export class AggField extends CountAggField { return !!this._esDocField; } + getMbFieldName(): string { + return this._source.isMvt() ? this.getName() + '.value' : this.getName(); + } + supportsFieldMeta(): boolean { // count and sum aggregations are not within field bounds so they do not support field meta. return !isMetricCountable(this._getAggType()); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts index 3bd26666005a6..b303dbc342bb2 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts @@ -43,6 +43,10 @@ export class CountAggField implements IESAggField { return this._source.getAggKey(this._getAggType(), this.getRootName()); } + getMbFieldName(): string { + return this._source.isMvt() ? '_count' : this.getName(); + } + getRootName(): string { return ''; } diff --git a/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts index f6cdcf43fe343..227084bfe0cad 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts @@ -23,6 +23,10 @@ export class TopTermPercentageField implements IESAggField { return this._topTermAggField.getSource(); } + getMbFieldName(): string { + return this.getName(); + } + getOrigin(): FIELD_ORIGIN { return this._topTermAggField.getOrigin(); } diff --git a/x-pack/plugins/maps/public/classes/fields/field.ts b/x-pack/plugins/maps/public/classes/fields/field.ts index 586f9f74da8ac..014d75caf90b6 100644 --- a/x-pack/plugins/maps/public/classes/fields/field.ts +++ b/x-pack/plugins/maps/public/classes/fields/field.ts @@ -11,6 +11,7 @@ import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property' export interface IField { getName(): string; + getMbFieldName(): string; getRootName(): string; canValueBeFormatted(): boolean; getLabel(): Promise; @@ -50,6 +51,10 @@ export class AbstractField implements IField { return this._fieldName; } + getMbFieldName(): string { + return this.getName(); + } + getRootName(): string { return this.getName(); } diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index e1043a33f28ad..051115a072608 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -63,13 +63,18 @@ export interface ILayer { getStyleForEditing(): IStyle; getCurrentStyle(): IStyle; getImmutableSourceProperties(): Promise; - renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement | null; + renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement | null; isLayerLoading(): boolean; isLoadingBounds(): boolean; isFilteredByGlobalTime(): Promise; hasErrors(): boolean; getErrors(): string; + + /* + * ILayer.getMbLayerIds returns a list of all mapbox layers assoicated with this layer. + */ getMbLayerIds(): string[]; + ownsMbLayerId(mbLayerId: string): boolean; ownsMbSourceId(mbSourceId: string): boolean; syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice): void; @@ -77,7 +82,7 @@ export interface ILayer { isInitialDataLoadComplete(): boolean; getIndexPatternIds(): string[]; getQueryableIndexPatternIds(): string[]; - getType(): LAYER_TYPE | undefined; + getType(): LAYER_TYPE; isVisible(): boolean; cloneDescriptor(): Promise; renderStyleEditor( @@ -325,9 +330,8 @@ export class AbstractLayer implements ILayer { return await source.getImmutableProperties(); } - renderSourceSettingsEditor({ onChange }: SourceEditorArgs) { - const source = this.getSourceForEditing(); - return source.renderSourceSettingsEditor({ onChange, currentLayerType: this._descriptor.type }); + renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs) { + return this.getSourceForEditing().renderSourceSettingsEditor(sourceEditorArgs); } getPrevRequestToken(dataId: string): symbol | undefined { @@ -437,7 +441,7 @@ export class AbstractLayer implements ILayer { mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none'); } - getType(): LAYER_TYPE | undefined { + getType(): LAYER_TYPE { return this._descriptor.type as LAYER_TYPE; } diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/__snapshots__/tiled_vector_layer.test.tsx.snap b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/__snapshots__/tiled_vector_layer.test.tsx.snap index d3b96936a85a1..8b4911342f841 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/__snapshots__/tiled_vector_layer.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/__snapshots__/tiled_vector_layer.test.tsx.snap @@ -1,9 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`icon should use no data icon 1`] = ` - `; diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.test.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.test.tsx index e1f134cdf2a85..fd78ea2ebde59 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.test.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.test.tsx @@ -95,8 +95,8 @@ describe('visiblity', () => { }); }); -describe('icon', () => { - it('should use no data icon', async () => { +describe('getCustomIconAndTooltipContent', () => { + it('Layers with non-elasticsearch sources should display icon', async () => { const layer: TiledVectorLayer = createLayer({}, {}); const iconAndTooltipContent = layer.getCustomIconAndTooltipContent(); diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx index 9b5298685865a..79aeab76e4185 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx @@ -7,39 +7,44 @@ import type { Map as MbMap, + AnyLayer as MbLayer, GeoJSONSource as MbGeoJSONSource, VectorSource as MbVectorSource, } from '@kbn/mapbox-gl'; import { Feature } from 'geojson'; +import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { parse as parseUrl } from 'url'; -import { i18n } from '@kbn/i18n'; +import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; +import { LAYER_TYPE, SOURCE_DATA_REQUEST_ID, SOURCE_TYPES } from '../../../../common/constants'; import { - KBN_FEATURE_COUNT, - KBN_IS_TILE_COMPLETE, - KBN_METADATA_FEATURE, - LAYER_TYPE, - SOURCE_DATA_REQUEST_ID, -} from '../../../../common/constants'; -import { + NO_RESULTS_ICON_AND_TOOLTIPCONTENT, VectorLayer, VectorLayerArguments, - NO_RESULTS_ICON_AND_TOOLTIPCONTENT, } from '../vector_layer'; import { ITiledSingleLayerVectorSource } from '../../sources/tiled_single_layer_vector_source'; import { DataRequestContext } from '../../../actions'; import { - Timeslice, StyleMetaDescriptor, + TileMetaFeature, + Timeslice, VectorLayerDescriptor, VectorSourceRequestMeta, - TileMetaFeature, } from '../../../../common/descriptor_types'; import { MVTSingleLayerVectorSourceConfig } from '../../sources/mvt_single_layer_vector_source/types'; +import { ESSearchSource } from '../../sources/es_search_source'; import { canSkipSourceUpdate } from '../../util/can_skip_fetch'; import { CustomIconAndTooltipContent } from '../layer'; +const ES_MVT_META_LAYER_NAME = 'meta'; +const ES_MVT_HITS_TOTAL_RELATION = 'hits.total.relation'; +const ES_MVT_HITS_TOTAL_VALUE = 'hits.total.value'; +const MAX_RESULT_WINDOW_DATA_REQUEST_ID = 'maxResultWindow'; + +/* + * MVT vector layer + */ export class TiledVectorLayer extends VectorLayer { static type = LAYER_TYPE.TILED_VECTOR; @@ -65,18 +70,61 @@ export class TiledVectorLayer extends VectorLayer { this._source = source as ITiledSingleLayerVectorSource; } + getFeatureId(feature: Feature): string | number | undefined { + if (!this.getSource().isESSource()) { + return feature.id; + } + + return this.getSource().getType() === SOURCE_TYPES.ES_SEARCH + ? feature.properties?._id + : feature.properties?._key; + } + _getMetaFromTiles(): TileMetaFeature[] { return this._descriptor.__metaFromTiles || []; } getCustomIconAndTooltipContent(): CustomIconAndTooltipContent { - const tileMetas = this._getMetaFromTiles(); - if (!tileMetas.length) { + const icon = this.getCurrentStyle().getIcon(); + if (!this.getSource().isESSource()) { + // Only ES-sources can have a special meta-tile, not 3rd party vector tile sources + return { + icon, + tooltipContent: null, + areResultsTrimmed: false, + }; + } + + // + // TODO ES MVT specific - move to es_tiled_vector_layer implementation + // + + const tileMetaFeatures = this._getMetaFromTiles(); + if (!tileMetaFeatures.length) { return NO_RESULTS_ICON_AND_TOOLTIPCONTENT; } - const totalFeaturesCount: number = tileMetas.reduce((acc: number, tileMeta: Feature) => { - const count = tileMeta && tileMeta.properties ? tileMeta.properties[KBN_FEATURE_COUNT] : 0; + if (this.getSource().getType() !== SOURCE_TYPES.ES_SEARCH) { + // aggregation ES sources are never trimmed + return { + icon, + tooltipContent: null, + areResultsTrimmed: false, + }; + } + + const maxResultWindow = this._getMaxResultWindow(); + if (maxResultWindow === undefined) { + return { + icon, + tooltipContent: null, + areResultsTrimmed: false, + }; + } + + const totalFeaturesCount: number = tileMetaFeatures.reduce((acc: number, tileMeta: Feature) => { + const count = + tileMeta && tileMeta.properties ? tileMeta.properties[ES_MVT_HITS_TOTAL_VALUE] : 0; return count + acc; }, 0); @@ -84,12 +132,16 @@ export class TiledVectorLayer extends VectorLayer { return NO_RESULTS_ICON_AND_TOOLTIPCONTENT; } - const isIncomplete: boolean = tileMetas.some((tileMeta: Feature) => { - return !tileMeta?.properties?.[KBN_IS_TILE_COMPLETE]; + const isIncomplete: boolean = tileMetaFeatures.some((tileMeta: TileMetaFeature) => { + if (tileMeta?.properties?.[ES_MVT_HITS_TOTAL_RELATION] === 'gte') { + return tileMeta?.properties?.[ES_MVT_HITS_TOTAL_VALUE] >= maxResultWindow + 1; + } else { + return false; + } }); return { - icon: this.getCurrentStyle().getIcon(), + icon, tooltipContent: isIncomplete ? i18n.translate('xpack.maps.tiles.resultsTrimmedMsg', { defaultMessage: `Results limited to {count} documents.`, @@ -107,6 +159,27 @@ export class TiledVectorLayer extends VectorLayer { }; } + _getMaxResultWindow(): number | undefined { + const dataRequest = this.getDataRequest(MAX_RESULT_WINDOW_DATA_REQUEST_ID); + if (!dataRequest) { + return; + } + const data = dataRequest.getData() as { maxResultWindow: number } | undefined; + return data ? data.maxResultWindow : undefined; + } + + async _syncMaxResultWindow({ startLoading, stopLoading }: DataRequestContext) { + const prevDataRequest = this.getDataRequest(MAX_RESULT_WINDOW_DATA_REQUEST_ID); + if (prevDataRequest) { + return; + } + + const requestToken = Symbol(`${this.getId()}-${MAX_RESULT_WINDOW_DATA_REQUEST_ID}`); + startLoading(MAX_RESULT_WINDOW_DATA_REQUEST_ID, requestToken); + const maxResultWindow = await (this.getSource() as ESSearchSource).getMaxResultWindow(); + stopLoading(MAX_RESULT_WINDOW_DATA_REQUEST_ID, requestToken, { maxResultWindow }); + } + async _syncMVTUrlTemplate({ startLoading, stopLoading, @@ -141,6 +214,7 @@ export class TiledVectorLayer extends VectorLayer { }, }); const canSkip = noChangesInSourceState && noChangesInSearchState; + if (canSkip) { return null; } @@ -180,6 +254,9 @@ export class TiledVectorLayer extends VectorLayer { } async syncData(syncContext: DataRequestContext) { + if (this.getSource().getType() === SOURCE_TYPES.ES_SEARCH) { + await this._syncMaxResultWindow(syncContext); + } await this._syncSourceStyleMeta(syncContext, this._source, this._style as IVectorStyle); await this._syncSourceFormatters(syncContext, this._source, this._style as IVectorStyle); await this._syncMVTUrlTemplate(syncContext); @@ -213,10 +290,18 @@ export class TiledVectorLayer extends VectorLayer { }); } + getMbLayerIds() { + return [...super.getMbLayerIds(), this._getMbTooManyFeaturesLayerId()]; + } + ownsMbSourceId(mbSourceId: string): boolean { return this._getMbSourceId() === mbSourceId; } + _getMbTooManyFeaturesLayerId() { + return this.makeMbLayerId('toomanyfeatures'); + } + _syncStylePropertiesWithMb(mbMap: MbMap) { // @ts-ignore const mbSource = mbMap.getSource(this._getMbSourceId()); @@ -236,10 +321,52 @@ export class TiledVectorLayer extends VectorLayer { this._setMbPointsProperties(mbMap, sourceMeta.layerName); this._setMbLinePolygonProperties(mbMap, sourceMeta.layerName); - this._setMbCentroidProperties(mbMap, sourceMeta.layerName); + this._setMbLabelProperties(mbMap, sourceMeta.layerName); + this._syncTooManyFeaturesProperties(mbMap); + } + + // TODO ES MVT specific - move to es_tiled_vector_layer implementation + _syncTooManyFeaturesProperties(mbMap: MbMap) { + if (this.getSource().getType() !== SOURCE_TYPES.ES_SEARCH) { + return; + } + + const maxResultWindow = this._getMaxResultWindow(); + if (maxResultWindow === undefined) { + return; + } + + const tooManyFeaturesLayerId = this._getMbTooManyFeaturesLayerId(); + + if (!mbMap.getLayer(tooManyFeaturesLayerId)) { + const mbTooManyFeaturesLayer: MbLayer = { + id: tooManyFeaturesLayerId, + type: 'line', + source: this.getId(), + paint: {}, + }; + mbTooManyFeaturesLayer['source-layer'] = ES_MVT_META_LAYER_NAME; + mbMap.addLayer(mbTooManyFeaturesLayer); + mbMap.setFilter(tooManyFeaturesLayerId, [ + 'all', + ['==', ['get', ES_MVT_HITS_TOTAL_RELATION], 'gte'], + ['>=', ['get', ES_MVT_HITS_TOTAL_VALUE], maxResultWindow + 1], + ]); + mbMap.setPaintProperty(tooManyFeaturesLayerId, 'line-color', euiThemeVars.euiColorWarning); + mbMap.setPaintProperty(tooManyFeaturesLayerId, 'line-width', 3); + mbMap.setPaintProperty(tooManyFeaturesLayerId, 'line-dasharray', [2, 1]); + mbMap.setPaintProperty(tooManyFeaturesLayerId, 'line-opacity', this.getAlpha()); + } + + this.syncVisibilityWithMb(mbMap, tooManyFeaturesLayerId); + mbMap.setLayerZoomRange(tooManyFeaturesLayerId, this.getMinZoom(), this.getMaxZoom()); } queryTileMetaFeatures(mbMap: MbMap): TileMetaFeature[] | null { + if (!this.getSource().isESSource()) { + return null; + } + // @ts-ignore const mbSource = mbMap.getSource(this._getMbSourceId()); if (!mbSource) { @@ -259,26 +386,38 @@ export class TiledVectorLayer extends VectorLayer { // querySourceFeatures can return duplicated features when features cross tile boundaries. // Tile meta will never have duplicated features since by there nature, tile meta is a feature contained within a single tile const mbFeatures = mbMap.querySourceFeatures(this._getMbSourceId(), { - sourceLayer: sourceMeta.layerName, - filter: ['==', ['get', KBN_METADATA_FEATURE], true], + sourceLayer: ES_MVT_META_LAYER_NAME, }); - const metaFeatures: TileMetaFeature[] = mbFeatures.map((mbFeature: Feature) => { + const metaFeatures: Array = ( + mbFeatures as unknown as TileMetaFeature[] + ).map((mbFeature: TileMetaFeature | null) => { const parsedProperties: Record = {}; - for (const key in mbFeature.properties) { - if (mbFeature.properties.hasOwnProperty(key)) { - parsedProperties[key] = JSON.parse(mbFeature.properties[key]); // mvt properties cannot be nested geojson + for (const key in mbFeature?.properties) { + if (mbFeature?.properties.hasOwnProperty(key)) { + parsedProperties[key] = + typeof mbFeature.properties[key] === 'string' || + typeof mbFeature.properties[key] === 'number' || + typeof mbFeature.properties[key] === 'boolean' + ? mbFeature.properties[key] + : JSON.parse(mbFeature.properties[key]); // mvt properties cannot be nested geojson } } - return { - type: 'Feature', - id: mbFeature.id, - geometry: mbFeature.geometry, - properties: parsedProperties, - } as TileMetaFeature; + + try { + return { + type: 'Feature', + id: mbFeature?.id, + geometry: mbFeature?.geometry, // this getter might throw with non-conforming geometries + properties: parsedProperties, + } as TileMetaFeature; + } catch (e) { + return null; + } }); - return metaFeatures as TileMetaFeature[]; + const filtered = metaFeatures.filter((f) => f !== null); + return filtered as TileMetaFeature[]; } _requiresPrevSourceCleanup(mbMap: MbMap): boolean { @@ -317,8 +456,13 @@ export class TiledVectorLayer extends VectorLayer { const mbLayer = mbMap.getLayer(layerIds[i]); // The mapbox type in the spec is specified with `source-layer` // but the programmable JS-object uses camelcase `sourceLayer` - // @ts-expect-error - if (mbLayer && mbLayer.sourceLayer !== tiledSourceMeta.layerName) { + if ( + mbLayer && + // @ts-expect-error + mbLayer.sourceLayer !== tiledSourceMeta.layerName && + // @ts-expect-error + mbLayer.sourceLayer !== ES_MVT_META_LAYER_NAME + ) { // If the source-pointer of one of the layers is stale, they will all be stale. // In this case, all the mb-layers need to be removed and re-added. return true; diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts index 137d443b39b91..2250e86da0ec2 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { assignFeatureIds } from './assign_feature_ids'; -import { FEATURE_ID_PROPERTY_NAME } from '../../../../common/constants'; +import { assignFeatureIds, GEOJSON_FEATURE_ID_PROPERTY_NAME } from './assign_feature_ids'; import { FeatureCollection, Feature, Point } from 'geojson'; const featureId = 'myFeature1'; @@ -34,7 +33,7 @@ test('should provide unique id when feature.id is not provided', () => { expect(typeof feature1.id).toBe('number'); expect(typeof feature2.id).toBe('number'); // @ts-ignore - expect(feature1.id).toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]); + expect(feature1.id).toBe(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]); expect(feature1.id).not.toBe(feature2.id); }); @@ -53,9 +52,9 @@ test('should preserve feature id when provided', () => { const feature1 = updatedFeatureCollection.features[0]; expect(typeof feature1.id).toBe('number'); // @ts-ignore - expect(feature1.id).not.toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]); + expect(feature1.id).not.toBe(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]); // @ts-ignore - expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(featureId); + expect(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]).toBe(featureId); }); test('should preserve feature id for falsy value', () => { @@ -73,9 +72,9 @@ test('should preserve feature id for falsy value', () => { const feature1 = updatedFeatureCollection.features[0]; expect(typeof feature1.id).toBe('number'); // @ts-ignore - expect(feature1.id).not.toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]); + expect(feature1.id).not.toBe(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]); // @ts-ignore - expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(0); + expect(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]).toBe(0); }); test('should not modify original feature properties', () => { @@ -94,6 +93,6 @@ test('should not modify original feature properties', () => { const updatedFeatureCollection = assignFeatureIds(featureCollection); const feature1 = updatedFeatureCollection.features[0]; // @ts-ignore - expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(featureId); - expect(featureProperties).not.toHaveProperty(FEATURE_ID_PROPERTY_NAME); + expect(feature1.properties[GEOJSON_FEATURE_ID_PROPERTY_NAME]).toBe(featureId); + expect(featureProperties).not.toHaveProperty(GEOJSON_FEATURE_ID_PROPERTY_NAME); }); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts index c40c8299ad04c..3611256d246fb 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts @@ -7,7 +7,8 @@ import _ from 'lodash'; import { FeatureCollection, Feature } from 'geojson'; -import { FEATURE_ID_PROPERTY_NAME } from '../../../../common/constants'; + +export const GEOJSON_FEATURE_ID_PROPERTY_NAME = '__kbn__feature_id__'; let idCounter = 0; @@ -43,7 +44,7 @@ export function assignFeatureIds(featureCollection: FeatureCollection): FeatureC geometry: feature.geometry, // do not copy geometry, this object can be massive properties: { // preserve feature id provided by source so features can be referenced across fetches - [FEATURE_ID_PROPERTY_NAME]: feature.id == null ? numericId : feature.id, + [GEOJSON_FEATURE_ID_PROPERTY_NAME]: feature.id == null ? numericId : feature.id, // create new object for properties so original is not polluted with kibana internal props ...feature.properties, }, diff --git a/x-pack/plugins/maps/common/get_centroid_features.test.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.test.ts similarity index 93% rename from x-pack/plugins/maps/common/get_centroid_features.test.ts rename to x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.test.ts index 0fac9dc3a355f..2b8d03a2c3f8c 100644 --- a/x-pack/plugins/maps/common/get_centroid_features.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.test.ts @@ -44,35 +44,6 @@ test('should not create centroid feature for point and multipoint', () => { expect(centroidFeatures.length).toBe(0); }); -test('should not create centroid for the metadata polygon', () => { - const polygonFeature: Feature = { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [35, 10], - [45, 45], - [15, 40], - [10, 20], - [35, 10], - ], - ], - }, - properties: { - __kbn_metadata_feature__: true, - prop0: 'value0', - prop1: 0.0, - }, - }; - const featureCollection: FeatureCollection = { - type: 'FeatureCollection', - features: [polygonFeature], - }; - const centroidFeatures = getCentroidFeatures(featureCollection); - expect(centroidFeatures.length).toBe(0); -}); - test('should create centroid feature for line (even number of points)', () => { const lineFeature: Feature = { type: 'Feature', diff --git a/x-pack/plugins/maps/common/get_centroid_features.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.ts similarity index 94% rename from x-pack/plugins/maps/common/get_centroid_features.ts rename to x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.ts index 8aaeb56576a84..6afe61f8a16b9 100644 --- a/x-pack/plugins/maps/common/get_centroid_features.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/get_centroid_features.ts @@ -21,18 +21,13 @@ import turfArea from '@turf/area'; import turfCenterOfMass from '@turf/center-of-mass'; import turfLength from '@turf/length'; import { lineString, polygon } from '@turf/helpers'; -import { GEO_JSON_TYPE, KBN_IS_CENTROID_FEATURE, KBN_METADATA_FEATURE } from './constants'; +import { GEO_JSON_TYPE, KBN_IS_CENTROID_FEATURE } from '../../../../common/constants'; export function getCentroidFeatures(featureCollection: FeatureCollection): Feature[] { const centroids = []; for (let i = 0; i < featureCollection.features.length; i++) { const feature = featureCollection.features[i]; - // do not add centroid for kibana added features - if (feature.properties?.[KBN_METADATA_FEATURE]) { - continue; - } - const centroid = getCentroid(feature); if (centroid) { centroids.push(centroid); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx index 8e4eb349036ea..cc30f30fe9898 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx @@ -24,7 +24,7 @@ import { DataRequestContext } from '../../../actions'; import { IVectorSource } from '../../sources/vector_source'; import { DataRequestAbortError } from '../../util/data_request'; import { DataRequest } from '../../util/data_request'; -import { getCentroidFeatures } from '../../../../common/get_centroid_features'; +import { getCentroidFeatures } from './get_centroid_features'; import { canSkipSourceUpdate } from '../../util/can_skip_fetch'; import { assignFeatureIds } from './assign_feature_ids'; diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index 3faf92715451c..675bacb10cde9 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -21,20 +21,16 @@ import { AbstractLayer } from '../layer'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { AGG_TYPE, - FEATURE_ID_PROPERTY_NAME, SOURCE_META_DATA_REQUEST_ID, SOURCE_FORMATTERS_DATA_REQUEST_ID, FEATURE_VISIBLE_PROPERTY_NAME, EMPTY_FEATURE_COLLECTION, - KBN_METADATA_FEATURE, LAYER_TYPE, FIELD_ORIGIN, - KBN_TOO_MANY_FEATURES_IMAGE_ID, FieldFormatter, SOURCE_TYPES, STYLE_TYPE, SUPPORTS_FEATURE_EDITING_REQUEST_ID, - KBN_IS_TILE_COMPLETE, VECTOR_STYLES, } from '../../../../common/constants'; import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property'; @@ -46,7 +42,7 @@ import { } from '../../util/can_skip_fetch'; import { getFeatureCollectionBounds } from '../../util/get_feature_collection_bounds'; import { - getCentroidFilterExpression, + getLabelFilterExpression, getFillFilterExpression, getLineFilterExpression, getPointFilterExpression, @@ -80,6 +76,7 @@ import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './u import { JoinState, performInnerJoins } from './perform_inner_joins'; import { buildVectorRequestMeta } from '../build_vector_request_meta'; import { getJoinAggKey } from '../../../../common/get_agg_key'; +import { GEOJSON_FEATURE_ID_PROPERTY_NAME } from './assign_feature_ids'; export function isVectorLayer(layer: ILayer) { return (layer as IVectorLayer).canShowTooltip !== undefined; @@ -93,12 +90,19 @@ export interface VectorLayerArguments { } export interface IVectorLayer extends ILayer { + /* + * IVectorLayer.getMbLayerIds returns a list of mapbox layers assoicated with this layer for identifing features with tooltips. + * Must return ILayer.getMbLayerIds or a subset of ILayer.getMbLayerIds. + */ + getMbTooltipLayerIds(): string[]; + getFields(): Promise; getStyleEditorFields(): Promise; getJoins(): InnerJoin[]; getJoinsDisabledReason(): string | null; getValidJoins(): InnerJoin[]; getSource(): IVectorSource; + getFeatureId(feature: Feature): string | number | undefined; getFeatureById(id: string | number): Feature | null; getPropertiesForTooltip(properties: GeoJsonProperties): Promise; hasJoins(): boolean; @@ -118,6 +122,9 @@ export const NO_RESULTS_ICON_AND_TOOLTIPCONTENT = { }), }; +/* + * Geojson vector layer + */ export class VectorLayer extends AbstractLayer implements IVectorLayer { static type = LAYER_TYPE.VECTOR; @@ -589,6 +596,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { timeFilters: nextMeta.timeFilters, searchSessionId: dataFilters.searchSessionId, }); + stopLoading(dataRequestId, requestToken, styleMeta, nextMeta); } catch (error) { if (!(error instanceof DataRequestAbortError)) { @@ -774,6 +782,9 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { } _getSourceFeatureCollection() { + if (this.getSource().isMvt()) { + return null; + } const sourceDataRequest = this.getSourceDataRequest(); return sourceDataRequest ? (sourceDataRequest.getData() as FeatureCollection) : null; } @@ -946,7 +957,6 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { const sourceId = this.getId(); const fillLayerId = this._getMbPolygonLayerId(); const lineLayerId = this._getMbLineLayerId(); - const tooManyFeaturesLayerId = this._getMbTooManyFeaturesLayerId(); const hasJoins = this.hasJoins(); if (!mbMap.getLayer(fillLayerId)) { @@ -973,29 +983,6 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { } mbMap.addLayer(mbLayer); } - if (!mbMap.getLayer(tooManyFeaturesLayerId)) { - const mbLayer: MbLayer = { - id: tooManyFeaturesLayerId, - type: 'fill', - source: sourceId, - paint: {}, - }; - if (mvtSourceLayer) { - mbLayer['source-layer'] = mvtSourceLayer; - } - mbMap.addLayer(mbLayer); - mbMap.setFilter(tooManyFeaturesLayerId, [ - 'all', - ['==', ['get', KBN_METADATA_FEATURE], true], - ['==', ['get', KBN_IS_TILE_COMPLETE], false], - ]); - mbMap.setPaintProperty( - tooManyFeaturesLayerId, - 'fill-pattern', - KBN_TOO_MANY_FEATURES_IMAGE_ID - ); - mbMap.setPaintProperty(tooManyFeaturesLayerId, 'fill-opacity', this.getAlpha()); - } this.getCurrentStyle().setMBPaintProperties({ alpha: this.getAlpha(), @@ -1017,21 +1004,18 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { if (!_.isEqual(lineFilterExpr, mbMap.getFilter(lineLayerId))) { mbMap.setFilter(lineLayerId, lineFilterExpr); } - - this.syncVisibilityWithMb(mbMap, tooManyFeaturesLayerId); - mbMap.setLayerZoomRange(tooManyFeaturesLayerId, this.getMinZoom(), this.getMaxZoom()); } - _setMbCentroidProperties( + _setMbLabelProperties( mbMap: MbMap, mvtSourceLayer?: string, timesliceMaskConfig?: TimesliceMaskConfig ) { - const centroidLayerId = this._getMbCentroidLayerId(); - const centroidLayer = mbMap.getLayer(centroidLayerId); - if (!centroidLayer) { + const labelLayerId = this._getMbLabelLayerId(); + const labelLayer = mbMap.getLayer(labelLayerId); + if (!labelLayer) { const mbLayer: MbLayer = { - id: centroidLayerId, + id: labelLayerId, type: 'symbol', source: this.getId(), }; @@ -1041,27 +1025,32 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { mbMap.addLayer(mbLayer); } - const filterExpr = getCentroidFilterExpression(this.hasJoins(), timesliceMaskConfig); - if (!_.isEqual(filterExpr, mbMap.getFilter(centroidLayerId))) { - mbMap.setFilter(centroidLayerId, filterExpr); + const isSourceGeoJson = !this.getSource().isMvt(); + const filterExpr = getLabelFilterExpression( + this.hasJoins(), + isSourceGeoJson, + timesliceMaskConfig + ); + if (!_.isEqual(filterExpr, mbMap.getFilter(labelLayerId))) { + mbMap.setFilter(labelLayerId, filterExpr); } this.getCurrentStyle().setMBPropertiesForLabelText({ alpha: this.getAlpha(), mbMap, - textLayerId: centroidLayerId, + textLayerId: labelLayerId, }); - this.syncVisibilityWithMb(mbMap, centroidLayerId); - mbMap.setLayerZoomRange(centroidLayerId, this.getMinZoom(), this.getMaxZoom()); + this.syncVisibilityWithMb(mbMap, labelLayerId); + mbMap.setLayerZoomRange(labelLayerId, this.getMinZoom(), this.getMaxZoom()); } _syncStylePropertiesWithMb(mbMap: MbMap, timeslice?: Timeslice) { const timesliceMaskConfig = this._getTimesliceMaskConfig(timeslice); this._setMbPointsProperties(mbMap, undefined, timesliceMaskConfig); this._setMbLinePolygonProperties(mbMap, undefined, timesliceMaskConfig); - // centroid layers added after polygon layers to ensure they are on top of polygon layers - this._setMbCentroidProperties(mbMap, undefined, timesliceMaskConfig); + // label layers added after geometry layers to ensure they are on top + this._setMbLabelProperties(mbMap, undefined, timesliceMaskConfig); } _getTimesliceMaskConfig(timeslice?: Timeslice): TimesliceMaskConfig | undefined { @@ -1092,8 +1081,12 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this.makeMbLayerId('text'); } - _getMbCentroidLayerId() { - return this.makeMbLayerId('centroid'); + // _getMbTextLayerId is labels for Points and MultiPoints + // _getMbLabelLayerId is labels for not Points and MultiPoints + // _getMbLabelLayerId used to be called _getMbCentroidLayerId + // TODO merge textLayer and labelLayer into single layer + _getMbLabelLayerId() { + return this.makeMbLayerId('label'); } _getMbSymbolLayerId() { @@ -1108,22 +1101,21 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this.makeMbLayerId('fill'); } - _getMbTooManyFeaturesLayerId() { - return this.makeMbLayerId('toomanyfeatures'); - } - - getMbLayerIds() { + getMbTooltipLayerIds() { return [ this._getMbPointLayerId(), this._getMbTextLayerId(), - this._getMbCentroidLayerId(), + this._getMbLabelLayerId(), this._getMbSymbolLayerId(), this._getMbLineLayerId(), this._getMbPolygonLayerId(), - this._getMbTooManyFeaturesLayerId(), ]; } + getMbLayerIds() { + return this.getMbTooltipLayerIds(); + } + ownsMbLayerId(mbLayerId: string) { return this.getMbLayerIds().includes(mbLayerId); } @@ -1163,6 +1155,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this.getSource().hasTooltipProperties() || this.getJoins().length > 0; } + getFeatureId(feature: Feature): string | number | undefined { + return feature.properties?.[GEOJSON_FEATURE_ID_PROPERTY_NAME]; + } + getFeatureById(id: string | number) { const featureCollection = this._getSourceFeatureCollection(); if (!featureCollection) { @@ -1170,7 +1166,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { } const targetFeature = featureCollection.features.find((feature) => { - return feature.properties?.[FEATURE_ID_PROPERTY_NAME] === id; + return this.getFeatureId(feature) === id; }); return targetFeature ? targetFeature : null; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index 78bc2592182d8..dc9637c7a7637 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -134,14 +134,14 @@ export abstract class AbstractESAggSource extends AbstractESSource implements IE return valueAggsDsl; } - async getTooltipProperties(properties: GeoJsonProperties): Promise { + async getTooltipProperties(mbProperties: GeoJsonProperties): Promise { const metricFields = await this.getFields(); const promises: Array> = []; metricFields.forEach((metricField) => { let value; - for (const key in properties) { - if (properties.hasOwnProperty(key) && metricField.getName() === key) { - value = properties[key]; + for (const key in mbProperties) { + if (mbProperties.hasOwnProperty(key) && metricField.getMbFieldName() === key) { + value = mbProperties[key]; break; } } diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/resolution_editor.test.tsx.snap b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/resolution_editor.test.tsx.snap index ca9775594a9d7..6a1dbf9e1590b 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/resolution_editor.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/resolution_editor.test.tsx.snap @@ -1,73 +1,77 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`resolution editor should add super-fine option 1`] = ` - - - + + + + + `; exports[`resolution editor should omit super-fine option 1`] = ` - - - + + + + + `; diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/update_source_editor.test.tsx.snap b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/update_source_editor.test.tsx.snap index dfce6b36396a7..0d4467792e636 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/update_source_editor.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/__snapshots__/update_source_editor.test.tsx.snap @@ -19,9 +19,9 @@ exports[`source editor geo_grid_source default vector layer config should allow /> @@ -45,6 +45,7 @@ exports[`source editor geo_grid_source default vector layer config should allow /> @@ -79,7 +80,8 @@ exports[`source editor geo_grid_source should put limitations based on heatmap-r /> diff --git a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.d.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.d.ts similarity index 89% rename from x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.d.ts rename to x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.d.ts index 3bb2e165fa740..9452620447259 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.d.ts @@ -6,7 +6,7 @@ */ import { Feature } from 'geojson'; -import { RENDER_AS } from '../constants'; +import { RENDER_AS } from '../../../../common/constants'; export function convertCompositeRespToGeoJson(esResponse: any, renderAs: RENDER_AS): Feature[]; export function convertRegularRespToGeoJson(esResponse: any, renderAs: RENDER_AS): Feature[]; diff --git a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.js b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.js similarity index 89% rename from x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.js rename to x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.js index f416847941a8a..87fb0d53efa62 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.js +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.js @@ -6,10 +6,13 @@ */ import _ from 'lodash'; -import { RENDER_AS, GEOTILE_GRID_AGG_NAME, GEOCENTROID_AGG_NAME } from '../constants'; -import { getTileBoundingBox } from '../geo_tile_utils'; -import { extractPropertiesFromBucket } from './es_agg_utils'; -import { clamp } from './elasticsearch_geo_utils'; +import { + RENDER_AS, + GEOTILE_GRID_AGG_NAME, + GEOCENTROID_AGG_NAME, +} from '../../../../common/constants'; +import { getTileBoundingBox } from '../../util/geo_tile_utils'; +import { clamp, extractPropertiesFromBucket } from '../../../../common/elasticsearch_util'; const GRID_BUCKET_KEYS_TO_IGNORE = ['key', GEOCENTROID_AGG_NAME]; diff --git a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.test.ts similarity index 98% rename from x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.test.ts rename to x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.test.ts index 2dc96038d931d..d6de17bef710b 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/convert_to_geojson.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/convert_to_geojson.test.ts @@ -7,7 +7,7 @@ // @ts-ignore import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; -import { RENDER_AS } from '../constants'; +import { RENDER_AS } from '../../../../common/constants'; describe('convertCompositeRespToGeoJson', () => { const esResponse = { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 41d5715e47b8e..8eebf01a550dd 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -296,7 +296,7 @@ describe('ESGeoGridSource', () => { ); it('getLayerName', () => { - expect(mvtGeogridSource.getLayerName()).toBe('source_layer'); + expect(mvtGeogridSource.getLayerName()).toBe('aggs'); }); it('getMinZoom', () => { @@ -312,28 +312,13 @@ describe('ESGeoGridSource', () => { vectorSourceRequestMeta ); - expect(urlTemplateWithMeta.layerName).toBe('source_layer'); + expect(urlTemplateWithMeta.layerName).toBe('aggs'); expect(urlTemplateWithMeta.minSourceZoom).toBe(0); expect(urlTemplateWithMeta.maxSourceZoom).toBe(24); expect(urlTemplateWithMeta.urlTemplate).toEqual( - "rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point" + "rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':())))&requestType=heatmap" ); }); - - it('should include searchSourceId in urlTemplateWithMeta', async () => { - const urlTemplateWithMeta = await mvtGeogridSource.getUrlTemplateWithMeta({ - ...vectorSourceRequestMeta, - searchSessionId: '1', - }); - - expect( - urlTemplateWithMeta.urlTemplate.startsWith( - "rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point&searchSessionId=1" - ) - ).toBe(true); - - expect(urlTemplateWithMeta.urlTemplate.endsWith('&searchSessionId=1')).toBe(true); - }); }); describe('Gold+ usage', () => { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index 7bd1e4dfd75f3..777787d8213f3 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -10,13 +10,9 @@ import React, { ReactElement } from 'react'; import { i18n } from '@kbn/i18n'; import rison from 'rison-node'; import { Feature } from 'geojson'; -import type { estypes } from '@elastic/elasticsearch'; -import { - convertCompositeRespToGeoJson, - convertRegularRespToGeoJson, - makeESBbox, -} from '../../../../common/elasticsearch_util'; -// @ts-expect-error +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { makeESBbox } from '../../../../common/elasticsearch_util'; +import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; import { UpdateSourceEditor } from './update_source_editor'; import { DEFAULT_MAX_BUCKETS_LIMIT, @@ -26,7 +22,6 @@ import { GIS_API_PATH, GRID_RESOLUTION, MVT_GETGRIDTILE_API_PATH, - MVT_SOURCE_LAYER_NAME, MVT_TOKEN_PARAM_NAME, RENDER_AS, SOURCE_TYPES, @@ -55,6 +50,8 @@ import { ITiledSingleLayerMvtParams } from '../tiled_single_layer_vector_source/ type ESGeoGridSourceSyncMeta = Pick; +const ES_MVT_AGGS_LAYER_NAME = 'aggs'; + export const MAX_GEOTILE_LEVEL = 29; export const clustersTitle = i18n.translate('xpack.maps.source.esGridClustersTitle', { @@ -140,6 +137,10 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle ]; } + isMvt() { + return this._descriptor.resolution === GRID_RESOLUTION.SUPER_FINE; + } + getFieldNames() { return this.getMetricFields().map((esAggMetricField) => esAggMetricField.getName()); } @@ -305,8 +306,8 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle _addNonCompositeAggsToSearchSource( searchSource: ISearchSource, indexPattern: IndexPattern, - precision: number | null, - bufferedExtent?: MapExtent | null + precision: number, + bufferedExtent?: MapExtent ) { searchSource.setField('aggs', { [GEOTILE_GRID_AGG_NAME]: { @@ -419,7 +420,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle } getLayerName(): string { - return MVT_SOURCE_LAYER_NAME; + return ES_MVT_AGGS_LAYER_NAME; } async getUrlTemplateWithMeta( @@ -427,14 +428,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle ): Promise { const indexPattern = await this.getIndexPattern(); const searchSource = await this.makeSearchSource(searchFilters, 0); - - this._addNonCompositeAggsToSearchSource( - searchSource, - indexPattern, - null, // needs to be set server-side - null // needs to be stripped server-side - ); - + searchSource.setField('aggs', this.getValueAggsDsl(indexPattern)); const dsl = searchSource.getSearchRequestBody(); const risonDsl = rison.encode(dsl); @@ -443,22 +437,18 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle `/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf` ); - const geoField = await this._getGeoField(); const urlTemplate = `${mvtUrlServicePath}\ ?geometryFieldName=${this._descriptor.geoField}\ &index=${indexPattern.title}\ &requestBody=${risonDsl}\ -&requestType=${this._descriptor.requestType}\ -&geoFieldType=${geoField.type}`; +&requestType=${this._descriptor.requestType}`; return { refreshTokenParamName: MVT_TOKEN_PARAM_NAME, layerName: this.getLayerName(), minSourceZoom: this.getMinZoom(), maxSourceZoom: this.getMaxZoom(), - urlTemplate: searchFilters.searchSessionId - ? urlTemplate + `&searchSessionId=${searchFilters.searchSessionId}` - : urlTemplate, + urlTemplate, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.js b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.js deleted file mode 100644 index 52f4e4c9b7b88..0000000000000 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.js +++ /dev/null @@ -1,61 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { GRID_RESOLUTION } from '../../../../common/constants'; -import { EuiSelect, EuiFormRow } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -const BASE_OPTIONS = [ - { - value: GRID_RESOLUTION.COARSE, - text: i18n.translate('xpack.maps.source.esGrid.coarseDropdownOption', { - defaultMessage: 'coarse', - }), - }, - { - value: GRID_RESOLUTION.FINE, - text: i18n.translate('xpack.maps.source.esGrid.fineDropdownOption', { - defaultMessage: 'fine', - }), - }, - { - value: GRID_RESOLUTION.MOST_FINE, - text: i18n.translate('xpack.maps.source.esGrid.finestDropdownOption', { - defaultMessage: 'finest', - }), - }, -]; - -export function ResolutionEditor({ resolution, onChange, includeSuperFine }) { - const options = [...BASE_OPTIONS]; - - if (includeSuperFine) { - options.push({ - value: GRID_RESOLUTION.SUPER_FINE, - text: i18n.translate('xpack.maps.source.esGrid.superFineDropDownOption', { - defaultMessage: 'super fine (beta)', - }), - }); - } - - return ( - - onChange(e.target.value)} - compressed - /> - - ); -} diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.test.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.test.tsx index 0066160402fa3..a642bbe41449f 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.test.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -// @ts-expect-error import { ResolutionEditor } from './resolution_editor'; import { GRID_RESOLUTION } from '../../../../common/constants'; @@ -16,6 +15,7 @@ const defaultProps = { resolution: GRID_RESOLUTION.COARSE, onChange: () => {}, includeSuperFine: false, + metrics: [], }; describe('resolution editor', () => { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.tsx new file mode 100644 index 0000000000000..55ce46e121273 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/resolution_editor.tsx @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ChangeEvent, Component } from 'react'; +import { EuiConfirmModal, EuiSelect, EuiFormRow } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { AggDescriptor } from '../../../../common/descriptor_types'; +import { AGG_TYPE, GRID_RESOLUTION } from '../../../../common/constants'; + +const BASE_OPTIONS = [ + { + value: GRID_RESOLUTION.COARSE, + text: i18n.translate('xpack.maps.source.esGrid.coarseDropdownOption', { + defaultMessage: 'coarse', + }), + }, + { + value: GRID_RESOLUTION.FINE, + text: i18n.translate('xpack.maps.source.esGrid.fineDropdownOption', { + defaultMessage: 'fine', + }), + }, + { + value: GRID_RESOLUTION.MOST_FINE, + text: i18n.translate('xpack.maps.source.esGrid.finestDropdownOption', { + defaultMessage: 'finest', + }), + }, +]; + +function isUnsupportedVectorTileMetric(metric: AggDescriptor) { + return metric.type === AGG_TYPE.TERMS; +} + +interface Props { + includeSuperFine: boolean; + resolution: GRID_RESOLUTION; + onChange: (resolution: GRID_RESOLUTION, metrics: AggDescriptor[]) => void; + metrics: AggDescriptor[]; +} + +interface State { + showModal: boolean; +} + +export class ResolutionEditor extends Component { + private readonly _options = [...BASE_OPTIONS]; + + constructor(props: Props) { + super(props); + + this.state = { + showModal: false, + }; + + if (props.includeSuperFine) { + this._options.push({ + value: GRID_RESOLUTION.SUPER_FINE, + text: i18n.translate('xpack.maps.source.esGrid.superFineDropDownOption', { + defaultMessage: 'super fine', + }), + }); + } + } + + _onResolutionChange = (e: ChangeEvent) => { + const resolution = e.target.value as GRID_RESOLUTION; + if (resolution === GRID_RESOLUTION.SUPER_FINE) { + const hasUnsupportedMetrics = this.props.metrics.find(isUnsupportedVectorTileMetric); + if (hasUnsupportedMetrics) { + this.setState({ showModal: true }); + return; + } + } + + this.props.onChange(resolution, this.props.metrics); + }; + + _closeModal = () => { + this.setState({ + showModal: false, + }); + }; + + _acceptModal = () => { + this._closeModal(); + const supportedMetrics = this.props.metrics.filter((metric) => { + return !isUnsupportedVectorTileMetric(metric); + }); + this.props.onChange( + GRID_RESOLUTION.SUPER_FINE, + supportedMetrics.length ? supportedMetrics : [{ type: AGG_TYPE.COUNT }] + ); + }; + + _renderModal() { + return this.state.showModal ? ( + +

+ +

+
+ ) : null; + } + + render() { + const helpText = + this.props.resolution === GRID_RESOLUTION.SUPER_FINE + ? i18n.translate('xpack.maps.source.esGrid.superFineHelpText', { + defaultMessage: 'Super fine grid resolution uses vector tiles.', + }) + : undefined; + return ( + <> + {this._renderModal()} + + + + + ); + } +} diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.test.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.test.tsx index 18a263143afea..9dab6698b73f0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.test.tsx @@ -8,14 +8,19 @@ import React from 'react'; import { shallow } from 'enzyme'; -// @ts-expect-error import { UpdateSourceEditor } from './update_source_editor'; import { GRID_RESOLUTION, LAYER_TYPE, RENDER_AS } from '../../../../common/constants'; +jest.mock('uuid/v4', () => { + return function () { + return '12345'; + }; +}); + const defaultProps = { currentLayerType: LAYER_TYPE.VECTOR, indexPatternId: 'foobar', - onChange: () => {}, + onChange: async () => {}, metrics: [], renderAs: RENDER_AS.POINT, resolution: GRID_RESOLUTION.COARSE, diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.js b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.tsx similarity index 61% rename from x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.js rename to x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.tsx index c2a0935c23719..03b5e1fe3c794 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.js +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/update_source_editor.tsx @@ -7,20 +7,40 @@ import React, { Fragment, Component } from 'react'; +import uuid from 'uuid/v4'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPanel, EuiSpacer, EuiComboBoxOptionOption, EuiTitle } from '@elastic/eui'; import { getDataViewNotFoundMessage } from '../../../../common/i18n_getters'; -import { GRID_RESOLUTION, LAYER_TYPE } from '../../../../common/constants'; +import { AGG_TYPE, GRID_RESOLUTION, LAYER_TYPE, RENDER_AS } from '../../../../common/constants'; import { MetricsEditor } from '../../../components/metrics_editor'; import { getIndexPatternService } from '../../../kibana_services'; import { ResolutionEditor } from './resolution_editor'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { isMetricCountable } from '../../util/is_metric_countable'; -import { indexPatterns } from '../../../../../../../src/plugins/data/public'; +import { IndexPatternField, indexPatterns } from '../../../../../../../src/plugins/data/public'; import { RenderAsSelect } from './render_as_select'; +import { AggDescriptor } from '../../../../common/descriptor_types'; +import { OnSourceChangeArgs } from '../source'; + +interface Props { + currentLayerType?: string; + indexPatternId: string; + onChange: (...args: OnSourceChangeArgs[]) => Promise; + metrics: AggDescriptor[]; + renderAs: RENDER_AS; + resolution: GRID_RESOLUTION; +} -export class UpdateSourceEditor extends Component { - state = { - fields: null, +interface State { + metricsEditorKey: string; + fields: IndexPatternField[]; + loadError?: string; +} + +export class UpdateSourceEditor extends Component { + private _isMounted?: boolean; + state: State = { + fields: [], + metricsEditorKey: uuid(), }; componentDidMount() { @@ -54,11 +74,11 @@ export class UpdateSourceEditor extends Component { }); } - _onMetricsChange = (metrics) => { + _onMetricsChange = (metrics: AggDescriptor[]) => { this.props.onChange({ propName: 'metrics', value: metrics }); }; - _onResolutionChange = (resolution) => { + _onResolutionChange = async (resolution: GRID_RESOLUTION, metrics: AggDescriptor[]) => { let newLayerType; if ( this.props.currentLayerType === LAYER_TYPE.VECTOR || @@ -76,22 +96,36 @@ export class UpdateSourceEditor extends Component { throw new Error('Unexpected layer-type'); } - this.props.onChange({ propName: 'resolution', value: resolution, newLayerType }); + await this.props.onChange( + { propName: 'metrics', value: metrics }, + { propName: 'resolution', value: resolution, newLayerType } + ); + + // Metrics editor persists metrics in state. + // Reset metricsEditorKey to force new instance and new internal state with latest metrics + this.setState({ metricsEditorKey: uuid() }); }; - _onRequestTypeSelect = (requestType) => { + _onRequestTypeSelect = (requestType: RENDER_AS) => { this.props.onChange({ propName: 'requestType', value: requestType }); }; + _getMetricsFilter() { + if (this.props.currentLayerType === LAYER_TYPE.HEATMAP) { + return (metric: EuiComboBoxOptionOption) => { + // these are countable metrics, where blending heatmap color blobs make sense + return metric.value ? isMetricCountable(metric.value) : false; + }; + } + + if (this.props.resolution === GRID_RESOLUTION.SUPER_FINE) { + return (metric: EuiComboBoxOptionOption) => { + return metric.value !== AGG_TYPE.TERMS; + }; + } + } + _renderMetricsPanel() { - const metricsFilter = - this.props.currentLayerType === LAYER_TYPE.HEATMAP - ? (metric) => { - //these are countable metrics, where blending heatmap color blobs make sense - return isMetricCountable(metric.value); - } - : null; - const allowMultipleMetrics = this.props.currentLayerType !== LAYER_TYPE.HEATMAP; return ( @@ -101,8 +135,9 @@ export class UpdateSourceEditor extends Component { {}} /> ); diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts index 6359abd06d3be..aad377ef53649 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts @@ -31,7 +31,7 @@ describe('ESSearchSource', () => { const esSearchSource = new ESSearchSource(mockDescriptor); expect(esSearchSource.getMinZoom()).toBe(0); expect(esSearchSource.getMaxZoom()).toBe(24); - expect(esSearchSource.getLayerName()).toBe('source_layer'); + expect(esSearchSource.getLayerName()).toBe('hits'); }); describe('getUrlTemplateWithMeta', () => { @@ -117,21 +117,7 @@ describe('ESSearchSource', () => { }); const urlTemplateWithMeta = await esSearchSource.getUrlTemplateWithMeta(searchFilters); expect(urlTemplateWithMeta.urlTemplate).toBe( - `rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape` - ); - }); - - it('should include searchSourceId in urlTemplateWithMeta', async () => { - const esSearchSource = new ESSearchSource({ - geoField: geoFieldName, - indexPatternId: 'ipId', - }); - const urlTemplateWithMeta = await esSearchSource.getUrlTemplateWithMeta({ - ...searchFilters, - searchSessionId: '1', - }); - expect(urlTemplateWithMeta.urlTemplate).toBe( - `rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape&searchSessionId=1` + `rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))` ); }); }); @@ -162,7 +148,7 @@ describe('ESSearchSource', () => { scalingType: SCALING_TYPES.MVT, }); expect(esSearchSource.getJoinsDisabledReason()).toBe( - 'Joins are not supported when scaling by mvt vector tiles' + 'Joins are not supported when scaling by vector tiles' ); }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index 75ec128f5a8aa..31cc07d03549a 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -9,8 +9,8 @@ import _ from 'lodash'; import React, { ReactElement } from 'react'; import rison from 'rison-node'; import { i18n } from '@kbn/i18n'; -import type { Filter, IndexPatternField, IndexPattern } from 'src/plugins/data/public'; import { GeoJsonProperties, Geometry, Position } from 'geojson'; +import type { Filter, IndexPatternField, IndexPattern } from 'src/plugins/data/public'; import { esFilters } from '../../../../../../../src/plugins/data/public'; import { AbstractESSource } from '../es_source'; import { @@ -35,7 +35,6 @@ import { FIELD_ORIGIN, GIS_API_PATH, MVT_GETTILE_API_PATH, - MVT_SOURCE_LAYER_NAME, MVT_TOKEN_PARAM_NAME, SCALING_TYPES, SOURCE_TYPES, @@ -54,14 +53,17 @@ import { VectorSourceRequestMeta, } from '../../../../common/descriptor_types'; import { Adapters } from '../../../../../../../src/plugins/inspector/common/adapters'; -import { TimeRange } from '../../../../../../../src/plugins/data/common'; +import { + SortDirection, + SortDirectionNumeric, + TimeRange, +} from '../../../../../../../src/plugins/data/common'; import { ImmutableSourceProperty, SourceEditorArgs } from '../source'; import { IField } from '../../fields/field'; import { GeoJsonWithMeta, SourceTooltipConfig } from '../vector_source'; import { ITiledSingleLayerVectorSource } from '../tiled_single_layer_vector_source'; import { ITooltipProperty } from '../../tooltips/tooltip_property'; import { DataRequest } from '../../util/data_request'; -import { SortDirection, SortDirectionNumeric } from '../../../../../../../src/plugins/data/common'; import { isValidStringConfig } from '../../util/valid_string_config'; import { TopHitsUpdateSourceEditor } from './top_hits'; import { getDocValueAndSourceFields, ScriptField } from './util/get_docvalue_source_fields'; @@ -83,6 +85,8 @@ type ESSearchSourceSyncMeta = Pick< | 'topHitsSize' >; +const ES_MVT_HITS_LAYER_NAME = 'hits'; + export function timerangeToTimeextent(timerange: TimeRange): Timeslice | undefined { const timeRangeBounds = getTimeFilter().calculateBounds(timerange); return timeRangeBounds.min !== undefined && timeRangeBounds.max !== undefined @@ -185,6 +189,8 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye sortOrder={this._descriptor.sortOrder} scalingType={this._descriptor.scalingType} filterByMapBounds={this.isFilterByMapBounds()} + hasJoins={sourceEditorArgs.hasJoins} + clearJoins={sourceEditorArgs.clearJoins} /> ); } @@ -211,6 +217,10 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye return [this._descriptor.geoField]; } + isMvt() { + return this._descriptor.scalingType === SCALING_TYPES.MVT; + } + async getImmutableProperties(): Promise { let indexPatternName = this.getIndexPatternId(); let geoFieldType = ''; @@ -748,7 +758,7 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye }); } else if (this._descriptor.scalingType === SCALING_TYPES.MVT) { reason = i18n.translate('xpack.maps.source.esSearch.joinsDisabledReasonMvt', { - defaultMessage: 'Joins are not supported when scaling by mvt vector tiles', + defaultMessage: 'Joins are not supported when scaling by vector tiles', }); } else { reason = null; @@ -757,7 +767,7 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye } getLayerName(): string { - return MVT_SOURCE_LAYER_NAME; + return ES_MVT_HITS_LAYER_NAME; } async _getEditableIndex(): Promise { @@ -828,22 +838,17 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye `/${GIS_API_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf` ); - const geoField = await this._getGeoField(); - const urlTemplate = `${mvtUrlServicePath}\ ?geometryFieldName=${this._descriptor.geoField}\ &index=${indexPattern.title}\ -&requestBody=${risonDsl}\ -&geoFieldType=${geoField.type}`; +&requestBody=${risonDsl}`; return { refreshTokenParamName: MVT_TOKEN_PARAM_NAME, layerName: this.getLayerName(), minSourceZoom: this.getMinZoom(), maxSourceZoom: this.getMaxZoom(), - urlTemplate: searchFilters.searchSessionId - ? urlTemplate + `&searchSessionId=${searchFilters.searchSessionId}` - : urlTemplate, + urlTemplate, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/update_source_editor.js b/x-pack/plugins/maps/public/classes/sources/es_search_source/update_source_editor.js index c28c8bedafaf9..ad0e03c2fe09d 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/update_source_editor.js +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/update_source_editor.js @@ -35,6 +35,8 @@ export class UpdateSourceEditor extends Component { sortOrder: PropTypes.string.isRequired, scalingType: PropTypes.string.isRequired, source: PropTypes.object, + hasJoins: PropTypes.bool.isRequired, + clearJoins: PropTypes.func.isRequired, }; state = { @@ -205,6 +207,8 @@ export class UpdateSourceEditor extends Component { scalingType={this.props.scalingType} supportsClustering={this.state.supportsClustering} clusteringDisabledReason={this.state.clusteringDisabledReason} + hasJoins={this.props.hasJoins} + clearJoins={this.props.clearJoins} /> ); diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/__snapshots__/scaling_form.test.tsx.snap b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/__snapshots__/scaling_form.test.tsx.snap index 749d55aeb5da7..bafb3172bbc11 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/__snapshots__/scaling_form.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/__snapshots__/scaling_form.test.tsx.snap @@ -46,17 +46,7 @@ exports[`scaling form should disable clusters option when clustering is not supp /> - - - Use vector tiles for faster display of large datasets. - - } + content="Use vector tiles for faster display of large datasets." delay="regular" display="inlineBlock" position="left" @@ -127,17 +117,7 @@ exports[`scaling form should render 1`] = ` onChange={[Function]} /> - - - Use vector tiles for faster display of large datasets. - - } + content="Use vector tiles for faster display of large datasets." delay="regular" display="inlineBlock" position="left" diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.test.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.test.tsx index c02d855f13aa4..aa3c7b51df5bb 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.test.tsx @@ -26,6 +26,8 @@ const defaultProps = { scalingType: SCALING_TYPES.LIMIT, supportsClustering: true, termFields: [], + hasJoins: false, + clearJoins: () => {}, }; describe('scaling form', () => { diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx index 2d202e934cea9..896b493507322 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx @@ -7,15 +7,14 @@ import React, { Component, Fragment } from 'react'; import { + EuiConfirmModal, EuiFormRow, - EuiHorizontalRule, EuiRadio, EuiSpacer, EuiSwitch, EuiSwitchEvent, EuiTitle, EuiToolTip, - EuiBetaBadge, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -35,15 +34,20 @@ interface Props { scalingType: SCALING_TYPES; supportsClustering: boolean; clusteringDisabledReason?: string | null; + hasJoins: boolean; + clearJoins: () => void; } interface State { + nextScalingType?: SCALING_TYPES; maxResultWindow: string; + showModal: boolean; } export class ScalingForm extends Component { - state = { + state: State = { maxResultWindow: DEFAULT_MAX_RESULT_WINDOW.toLocaleString(), + showModal: false, }; _isMounted = false; @@ -68,7 +72,15 @@ export class ScalingForm extends Component { } } - _onScalingTypeChange = (optionId: string): void => { + _onScalingTypeSelect = (optionId: SCALING_TYPES): void => { + if (this.props.hasJoins && optionId !== SCALING_TYPES.LIMIT) { + this._openModal(optionId); + } else { + this._onScalingTypeChange(optionId); + } + }; + + _onScalingTypeChange = (optionId: SCALING_TYPES): void => { let layerType; if (optionId === SCALING_TYPES.CLUSTERS) { layerType = LAYER_TYPE.BLENDED_VECTOR; @@ -85,6 +97,69 @@ export class ScalingForm extends Component { this.props.onChange({ propName: 'filterByMapBounds', value: event.target.checked }); }; + _openModal = (optionId: SCALING_TYPES) => { + this.setState({ + nextScalingType: optionId, + showModal: true, + }); + }; + + _closeModal = () => { + this.setState({ + nextScalingType: undefined, + showModal: false, + }); + }; + + _acceptModal = () => { + this.props.clearJoins(); + this._onScalingTypeChange(this.state.nextScalingType!); + this._closeModal(); + }; + + _renderModal() { + if (!this.state.showModal || this.state.nextScalingType === undefined) { + return null; + } + + const scalingOptionLabel = + this.state.nextScalingType === SCALING_TYPES.CLUSTERS + ? i18n.translate('xpack.maps.source.esSearch.scalingModal.clusters', { + defaultMessage: `clusters`, + }) + : i18n.translate('xpack.maps.source.esSearch.scalingModal.vectorTiles', { + defaultMessage: `vector tiles`, + }); + return ( + +

+ +

+
+ ); + } + _renderClusteringRadio() { const clusteringRadio = ( { values: { maxResultWindow: this.state.maxResultWindow }, })} checked={this.props.scalingType === SCALING_TYPES.CLUSTERS} - onChange={() => this._onScalingTypeChange(SCALING_TYPES.CLUSTERS)} + onChange={() => this._onScalingTypeSelect(SCALING_TYPES.CLUSTERS)} disabled={!this.props.supportsClustering} /> ); @@ -108,36 +183,6 @@ export class ScalingForm extends Component { ); } - _renderMVTRadio() { - const labelText = i18n.translate('xpack.maps.source.esSearch.useMVTVectorTiles', { - defaultMessage: 'Use vector tiles', - }); - const mvtRadio = ( - this._onScalingTypeChange(SCALING_TYPES.MVT)} - /> - ); - - const enabledInfo = ( - <> - - - {i18n.translate('xpack.maps.source.esSearch.mvtDescription', { - defaultMessage: 'Use vector tiles for faster display of large datasets.', - })} - - ); - - return ( - - {mvtRadio} - - ); - } - render() { let filterByBoundsSwitch; if (this.props.scalingType === SCALING_TYPES.LIMIT) { @@ -157,6 +202,7 @@ export class ScalingForm extends Component { return ( + {this._renderModal()}
@@ -174,10 +220,24 @@ export class ScalingForm extends Component { values: { maxResultWindow: this.state.maxResultWindow }, })} checked={this.props.scalingType === SCALING_TYPES.LIMIT} - onChange={() => this._onScalingTypeChange(SCALING_TYPES.LIMIT)} + onChange={() => this._onScalingTypeSelect(SCALING_TYPES.LIMIT)} /> {this._renderClusteringRadio()} - {this._renderMVTRadio()} + + this._onScalingTypeSelect(SCALING_TYPES.MVT)} + /> +
diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts index 0fa6335c1e0d9..ed95fdbb022fd 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts @@ -20,7 +20,7 @@ import { getDataViewNotFoundMessage } from '../../../../common/i18n_getters'; import { createExtentFilter } from '../../../../common/elasticsearch_util'; import { copyPersistentState } from '../../../reducers/copy_persistent_state'; import { DataRequestAbortError } from '../../util/data_request'; -import { expandToTileBoundaries } from '../../../../common/geo_tile_utils'; +import { expandToTileBoundaries } from '../../util/geo_tile_utils'; import { IVectorSource } from '../vector_source'; import { TimeRange } from '../../../../../../../src/plugins/data/common'; import { diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/__snapshots__/mvt_field_config_editor.test.tsx.snap b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/__snapshots__/mvt_field_config_editor.test.tsx.snap index f6d0129e85abf..b8f7af8b3844e 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/__snapshots__/mvt_field_config_editor.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/__snapshots__/mvt_field_config_editor.test.tsx.snap @@ -5,7 +5,6 @@ exports[`should render error for dupes 1`] = ` { _renderFieldConfig() { return this.state.currentFields.map((mvtFieldConfig: MVTFieldDescriptor, index: number) => { return ( - <> - + + {this._renderFieldNameInput(mvtFieldConfig, index)} {this._renderFieldTypeDropDown(mvtFieldConfig, index)} {this._renderFieldButtonDelete(index)} - + ); }); } diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx index 34a30ae9ec977..387bb9c3ca1ff 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx @@ -82,6 +82,10 @@ export class MVTSingleLayerVectorSource .filter((f) => f !== null) as MVTField[]; } + isMvt() { + return true; + } + async supportsFitToBounds() { return false; } diff --git a/x-pack/plugins/maps/public/classes/sources/source.ts b/x-pack/plugins/maps/public/classes/sources/source.ts index 4c2cffcf8b070..0ecca16fde07b 100644 --- a/x-pack/plugins/maps/public/classes/sources/source.ts +++ b/x-pack/plugins/maps/public/classes/sources/source.ts @@ -29,8 +29,10 @@ export type OnSourceChangeArgs = { }; export type SourceEditorArgs = { - onChange: (...args: OnSourceChangeArgs[]) => void; - currentLayerType?: string; + clearJoins: () => void; + currentLayerType: string; + hasJoins: boolean; + onChange: (...args: OnSourceChangeArgs[]) => Promise; }; export type ImmutableSourceProperty = { @@ -43,6 +45,7 @@ export interface ISource { destroy(): void; getDisplayName(): Promise; getInspectorAdapters(): Adapters | undefined; + getType(): string; isFieldAware(): boolean; isFilterByMapBounds(): boolean; isGeoGridPrecisionAware(): boolean; @@ -101,6 +104,10 @@ export class AbstractSource implements ISource { return this._inspectorAdapters; } + getType(): string { + return this._descriptor.type; + } + async getDisplayName(): Promise { return ''; } diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index 3c0adf64216e6..7042374296bbe 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -9,7 +9,7 @@ import type { Query } from 'src/plugins/data/common'; import { FeatureCollection, GeoJsonProperties, Geometry, Position } from 'geojson'; import { Filter, TimeRange } from 'src/plugins/data/public'; import { VECTOR_SHAPE_TYPE } from '../../../../common/constants'; -import { TooltipProperty, ITooltipProperty } from '../../tooltips/tooltip_property'; +import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property'; import { AbstractSource, ISource } from '../source'; import { IField } from '../../fields/field'; import { @@ -44,6 +44,7 @@ export interface BoundsRequestMeta { } export interface IVectorSource extends ISource { + isMvt(): boolean; getTooltipProperties(properties: GeoJsonProperties): Promise; getBoundsForFilters( layerDataFilters: BoundsRequestMeta, @@ -89,6 +90,10 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return []; } + isMvt() { + return false; + } + createField({ fieldName }: { fieldName: string }): IField { throw new Error('Not implemented'); } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap index 64da5777988d1..be8c9b0750b94 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap @@ -384,546 +384,6 @@ exports[`should render 1`] = ` `; -exports[`should render line-style with label properties when ES-source is rendered as mvt 1`] = ` - - - - - - - - - - - - - - - - - - - -`; - -exports[`should render polygon-style without label properties when 3rd party mvt 1`] = ` - - - - - - - - - - - -`; - exports[`should render with no style fields 1`] = ` { class MockField extends AbstractField {} -function createLayerMock( - numFields: number, - supportedShapeTypes: VECTOR_SHAPE_TYPE[], - layerType: LAYER_TYPE = LAYER_TYPE.VECTOR, - isESSource: boolean = false -) { +function createLayerMock(numFields: number, supportedShapeTypes: VECTOR_SHAPE_TYPE[]) { const fields: IField[] = []; for (let i = 0; i < numFields; i++) { fields.push(new MockField({ fieldName: `field${i}`, origin: FIELD_ORIGIN.SOURCE })); @@ -45,17 +39,11 @@ function createLayerMock( getStyleEditorFields: async () => { return fields; }, - getType() { - return layerType; - }, getSource: () => { return { getSupportedShapeTypes: async () => { return supportedShapeTypes; }, - isESSource() { - return isESSource; - }, } as unknown as IVectorSource; }, } as unknown as IVectorLayer; @@ -111,35 +99,3 @@ test('should render with no style fields', async () => { expect(component).toMatchSnapshot(); }); - -test('should render polygon-style without label properties when 3rd party mvt', async () => { - const component = shallow( - - ); - - // Ensure all promises resolve - await new Promise((resolve) => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); - - expect(component).toMatchSnapshot(); -}); - -test('should render line-style with label properties when ES-source is rendered as mvt', async () => { - const component = shallow( - - ); - - // Ensure all promises resolve - await new Promise((resolve) => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); - - expect(component).toMatchSnapshot(); -}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx index d909f31315e7d..e11a560c8755f 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx @@ -25,7 +25,6 @@ import { DEFAULT_FILL_COLORS, DEFAULT_LINE_COLORS } from '../../color_palettes'; import { LABEL_BORDER_SIZES, - LAYER_TYPE, STYLE_TYPE, VECTOR_SHAPE_TYPE, VECTOR_STYLES, @@ -258,18 +257,7 @@ export class VectorStyleEditor extends Component { ); } - _renderLabelProperties(isPoints: boolean) { - if ( - !isPoints && - this.props.layer.getType() === LAYER_TYPE.TILED_VECTOR && - !this.props.layer.getSource().isESSource() - ) { - // This handles and edge-case - // 3rd party lines and polygons from mvt sources cannot be labeled, because they do not have label-centroid geometries inside the tile. - // These label-centroids are only added for ES-sources - return; - } - + _renderLabelProperties() { const hasLabel = this._hasLabel(); const hasLabelBorder = this._hasLabelBorder(); return ( @@ -468,7 +456,7 @@ export class VectorStyleEditor extends Component { /> - {this._renderLabelProperties(true)} + {this._renderLabelProperties()} ); } @@ -482,7 +470,7 @@ export class VectorStyleEditor extends Component { {this._renderLineWidth()} - {this._renderLabelProperties(false)} + {this._renderLabelProperties()} ); } @@ -499,7 +487,7 @@ export class VectorStyleEditor extends Component { {this._renderLineWidth()} - {this._renderLabelProperties(false)} + {this._renderLabelProperties()} ); } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index 73f8736750656..bff053fc469a0 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -135,7 +135,7 @@ export class DynamicColorProperty extends DynamicStyleProperty extends IStyleProperty { getFieldMetaOptions(): FieldMetaOptions; getField(): IField | null; getFieldName(): string; + getMbFieldName(): string; getFieldOrigin(): FIELD_ORIGIN | null; getRangeFieldMeta(): RangeFieldMeta | null; getCategoryFieldMeta(): CategoryFieldMeta | null; @@ -63,7 +58,7 @@ export interface IDynamicStyleProperty extends IStyleProperty { getFieldMetaRequest(): Promise; pluckOrdinalStyleMetaFromFeatures(features: Feature[]): RangeFieldMeta | null; pluckCategoricalStyleMetaFromFeatures(features: Feature[]): CategoryFieldMeta | null; - pluckOrdinalStyleMetaFromTileMetaFeatures(features: TileMetaFeature[]): RangeFieldMeta | null; + pluckOrdinalStyleMetaFromTileMetaFeatures(metaFeatures: TileMetaFeature[]): RangeFieldMeta | null; pluckCategoricalStyleMetaFromTileMetaFeatures( features: TileMetaFeature[] ): CategoryFieldMeta | null; @@ -213,6 +208,10 @@ export class DynamicStyleProperty return this._field ? this._field.getName() : ''; } + getMbFieldName() { + return this._field ? this._field.getMbFieldName() : ''; + } + isDynamic() { return true; } @@ -314,54 +313,36 @@ export class DynamicStyleProperty return null; } - const name = this.getFieldName(); + const mbFieldName = this.getMbFieldName(); let min = Infinity; let max = -Infinity; for (let i = 0; i < metaFeatures.length; i++) { - const fieldMeta = metaFeatures[i].properties.fieldMeta; - if (fieldMeta && fieldMeta[name] && fieldMeta[name].range) { - min = Math.min(fieldMeta[name].range?.min as number, min); - max = Math.max(fieldMeta[name].range?.max as number, max); + const fieldMeta = metaFeatures[i].properties; + const minField = `aggregations.${mbFieldName}.min`; + const maxField = `aggregations.${mbFieldName}.max`; + if ( + fieldMeta && + typeof fieldMeta[minField] === 'number' && + typeof fieldMeta[maxField] === 'number' + ) { + min = Math.min(fieldMeta[minField] as number, min); + max = Math.max(fieldMeta[maxField] as number, max); } } - return { - min, - max, - delta: max - min, - }; + + return min === Infinity || max === -Infinity + ? null + : { + min, + max, + delta: max - min, + }; } pluckCategoricalStyleMetaFromTileMetaFeatures( metaFeatures: TileMetaFeature[] ): CategoryFieldMeta | null { - const size = this.getNumberOfCategories(); - if (!this.isCategorical() || size <= 0) { - return null; - } - - const name = this.getFieldName(); - - const counts = new Map(); - for (let i = 0; i < metaFeatures.length; i++) { - const fieldMeta = metaFeatures[i].properties.fieldMeta; - if (fieldMeta && fieldMeta[name] && fieldMeta[name].categories) { - const categoryFieldMeta: CategoryFieldMeta = fieldMeta[name] - .categories as CategoryFieldMeta; - for (let c = 0; c < categoryFieldMeta.categories.length; c++) { - const category: Category = categoryFieldMeta.categories[c]; - // properties object may be sparse, so need to check if the field is effectively present - if (typeof category.key !== undefined) { - if (counts.has(category.key)) { - counts.set(category.key, (counts.get(category.key) as number) + category.count); - } else { - counts.set(category.key, category.count); - } - } - } - } - } - - return trimCategories(counts, size); + return null; } pluckOrdinalStyleMetaFromFeatures(features: Feature[]): RangeFieldMeta | null { @@ -370,9 +351,24 @@ export class DynamicStyleProperty } const name = this.getFieldName(); - return pluckRangeFieldMeta(features, name, (rawValue: unknown) => { - return parseFloat(rawValue as string); - }); + let min = Infinity; + let max = -Infinity; + for (let i = 0; i < features.length; i++) { + const feature = features[i]; + const newValue = feature.properties ? parseFloat(feature.properties[name]) : NaN; + if (!isNaN(newValue)) { + min = Math.min(min, newValue); + max = Math.max(max, newValue); + } + } + + return min === Infinity || max === -Infinity + ? null + : { + min, + max, + delta: max - min, + }; } pluckCategoricalStyleMetaFromFeatures(features: Feature[]): CategoryFieldMeta | null { @@ -381,7 +377,32 @@ export class DynamicStyleProperty return null; } - return pluckCategoryFieldMeta(features, this.getFieldName(), size); + const counts = new Map(); + for (let i = 0; i < features.length; i++) { + const feature = features[i]; + const term = feature.properties ? feature.properties[this.getFieldName()] : undefined; + // properties object may be sparse, so need to check if the field is effectively present + if (typeof term !== undefined) { + if (counts.has(term)) { + counts.set(term, counts.get(term) + 1); + } else { + counts.set(term, 1); + } + } + } + + const ordered = []; + for (const [key, value] of counts) { + ordered.push({ key, count: value }); + } + + ordered.sort((a, b) => { + return b.count - a.count; + }); + const truncated = ordered.slice(0, size); + return { + categories: truncated, + } as CategoryFieldMeta; } _pluckOrdinalStyleMetaFromFieldMetaData(styleMetaData: StyleMetaData): RangeFieldMeta | null { @@ -487,7 +508,7 @@ export class DynamicStyleProperty targetName = getComputedFieldName(this.getStyleName(), this._field.getName()); } else { // Non-geojson sources (e.g. 3rd party mvt or ES-source as mvt) - targetName = this._field.getName(); + targetName = this._field.getMbFieldName(); } } return targetName; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 1e7267b9e1e32..058ee0db08d35 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -16,7 +16,6 @@ import { FIELD_ORIGIN, GEO_JSON_TYPE, KBN_IS_CENTROID_FEATURE, - KBN_VECTOR_SHAPE_TYPE_COUNTS, LAYER_STYLE_TYPE, SOURCE_FORMATTERS_DATA_REQUEST_ID, STYLE_TYPE, @@ -76,7 +75,6 @@ import { IVectorLayer } from '../../layers/vector_layer'; import { IVectorSource } from '../../sources/vector_source'; import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper'; import { IESAggField } from '../../fields/agg'; -import { VectorShapeTypeCounts } from '../../../../common/get_geometry_counts'; const POINTS = [GEO_JSON_TYPE.POINT, GEO_JSON_TYPE.MULTI_POINT]; const LINES = [GEO_JSON_TYPE.LINE_STRING, GEO_JSON_TYPE.MULTI_LINE_STRING]; @@ -92,9 +90,8 @@ export interface IVectorStyle extends IStyle { previousFields: IField[], mapColors: string[] ): Promise<{ hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }>; - isTimeAware: () => boolean; - getIcon: () => ReactElement; - getIconFromGeometryTypes: (isLinesOnly: boolean, isPointsOnly: boolean) => ReactElement; + isTimeAware(): boolean; + getIcon(): ReactElement; hasLegendDetails: () => Promise; renderLegendDetails: () => ReactElement; clearFeatureState: (featureCollection: FeatureCollection, mbMap: MbMap, sourceId: string) => void; @@ -492,50 +489,16 @@ export class VectorStyle implements IVectorStyle { } async pluckStyleMetaFromTileMeta(metaFeatures: TileMetaFeature[]): Promise { - const shapeTypeCountMeta: VectorShapeTypeCounts = metaFeatures.reduce( - (accumulator: VectorShapeTypeCounts, tileMeta: TileMetaFeature) => { - if ( - !tileMeta || - !tileMeta.properties || - !tileMeta.properties[KBN_VECTOR_SHAPE_TYPE_COUNTS] - ) { - return accumulator; - } - - accumulator[VECTOR_SHAPE_TYPE.POINT] += - tileMeta.properties[KBN_VECTOR_SHAPE_TYPE_COUNTS][VECTOR_SHAPE_TYPE.POINT]; - accumulator[VECTOR_SHAPE_TYPE.LINE] += - tileMeta.properties[KBN_VECTOR_SHAPE_TYPE_COUNTS][VECTOR_SHAPE_TYPE.LINE]; - accumulator[VECTOR_SHAPE_TYPE.POLYGON] += - tileMeta.properties[KBN_VECTOR_SHAPE_TYPE_COUNTS][VECTOR_SHAPE_TYPE.POLYGON]; - - return accumulator; - }, - { - [VECTOR_SHAPE_TYPE.POLYGON]: 0, - [VECTOR_SHAPE_TYPE.LINE]: 0, - [VECTOR_SHAPE_TYPE.POINT]: 0, - } - ); - - const isLinesOnly = - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.LINE] > 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POINT] === 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POLYGON] === 0; - const isPointsOnly = - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.LINE] === 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POINT] > 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POLYGON] === 0; - const isPolygonsOnly = - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.LINE] === 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POINT] === 0 && - shapeTypeCountMeta[VECTOR_SHAPE_TYPE.POLYGON] > 0; - + const supportedShapeTypes = await this._source.getSupportedShapeTypes(); const styleMeta: StyleMetaDescriptor = { geometryTypes: { - isPointsOnly, - isLinesOnly, - isPolygonsOnly, + isPointsOnly: + supportedShapeTypes.length === 1 && supportedShapeTypes.includes(VECTOR_SHAPE_TYPE.POINT), + isLinesOnly: + supportedShapeTypes.length === 1 && supportedShapeTypes.includes(VECTOR_SHAPE_TYPE.LINE), + isPolygonsOnly: + supportedShapeTypes.length === 1 && + supportedShapeTypes.includes(VECTOR_SHAPE_TYPE.POLYGON), }, fieldMeta: {}, }; @@ -737,7 +700,7 @@ export class VectorStyle implements IVectorStyle { : (this._iconStyleProperty as StaticIconProperty).getOptions().value; } - getIconFromGeometryTypes(isLinesOnly: boolean, isPointsOnly: boolean) { + _getIconFromGeometryTypes(isLinesOnly: boolean, isPointsOnly: boolean) { let strokeColor; if (isLinesOnly) { strokeColor = extractColorFromStyleProperty( @@ -771,7 +734,7 @@ export class VectorStyle implements IVectorStyle { getIcon() { const isLinesOnly = this._getIsLinesOnly(); const isPointsOnly = this._getIsPointsOnly(); - return this.getIconFromGeometryTypes(isLinesOnly, isPointsOnly); + return this._getIconFromGeometryTypes(isLinesOnly, isPointsOnly); } _getLegendDetailStyleProperties = () => { diff --git a/x-pack/plugins/maps/common/geo_tile_utils.test.js b/x-pack/plugins/maps/public/classes/util/geo_tile_utils.test.ts similarity index 100% rename from x-pack/plugins/maps/common/geo_tile_utils.test.js rename to x-pack/plugins/maps/public/classes/util/geo_tile_utils.test.ts diff --git a/x-pack/plugins/maps/common/geo_tile_utils.ts b/x-pack/plugins/maps/public/classes/util/geo_tile_utils.ts similarity index 95% rename from x-pack/plugins/maps/common/geo_tile_utils.ts rename to x-pack/plugins/maps/public/classes/util/geo_tile_utils.ts index 1a8ac3cbe17ae..6e82d3b509565 100644 --- a/x-pack/plugins/maps/common/geo_tile_utils.ts +++ b/x-pack/plugins/maps/public/classes/util/geo_tile_utils.ts @@ -6,9 +6,9 @@ */ import _ from 'lodash'; -import { DECIMAL_DEGREES_PRECISION } from './constants'; -import { clampToLatBounds } from './elasticsearch_util'; -import { MapExtent } from './descriptor_types'; +import { DECIMAL_DEGREES_PRECISION } from '../../../common/constants'; +import { clampToLatBounds } from '../../../common/elasticsearch_util'; +import { MapExtent } from '../../../common/descriptor_types'; const ZOOM_TILE_KEY_INDEX = 0; const X_TILE_KEY_INDEX = 1; diff --git a/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts b/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts index 68efd416718fd..544b2697cab43 100644 --- a/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts +++ b/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts @@ -9,7 +9,6 @@ import { GEO_JSON_TYPE, FEATURE_VISIBLE_PROPERTY_NAME, KBN_IS_CENTROID_FEATURE, - KBN_METADATA_FEATURE, } from '../../../common/constants'; import { Timeslice } from '../../../common/descriptor_types'; @@ -19,7 +18,6 @@ export interface TimesliceMaskConfig { timeslice: Timeslice; } -export const EXCLUDE_TOO_MANY_FEATURES_BOX = ['!=', ['get', KBN_METADATA_FEATURE], true]; export const EXCLUDE_CENTROID_FEATURES = ['!=', ['get', KBN_IS_CENTROID_FEATURE], true]; function getFilterExpression( @@ -56,7 +54,6 @@ export function getFillFilterExpression( ): unknown[] { return getFilterExpression( [ - EXCLUDE_TOO_MANY_FEATURES_BOX, EXCLUDE_CENTROID_FEATURES, [ 'any', @@ -75,7 +72,6 @@ export function getLineFilterExpression( ): unknown[] { return getFilterExpression( [ - EXCLUDE_TOO_MANY_FEATURES_BOX, EXCLUDE_CENTROID_FEATURES, [ 'any', @@ -96,7 +92,6 @@ export function getPointFilterExpression( ): unknown[] { return getFilterExpression( [ - EXCLUDE_TOO_MANY_FEATURES_BOX, EXCLUDE_CENTROID_FEATURES, [ 'any', @@ -109,13 +104,17 @@ export function getPointFilterExpression( ); } -export function getCentroidFilterExpression( +export function getLabelFilterExpression( hasJoins: boolean, + isSourceGeoJson: boolean, timesliceMaskConfig?: TimesliceMaskConfig ): unknown[] { - return getFilterExpression( - [EXCLUDE_TOO_MANY_FEATURES_BOX, ['==', ['get', KBN_IS_CENTROID_FEATURE], true]], - hasJoins, - timesliceMaskConfig - ); + const filters: unknown[] = []; + + // centroids added for geojson sources only + if (isSourceGeoJson) { + filters.push(['==', ['get', KBN_IS_CENTROID_FEATURE], true]); + } + + return getFilterExpression(filters, hasJoins, timesliceMaskConfig); } diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap index 5fb1cc6f72585..03e8b4a90c0ca 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap @@ -55,6 +55,8 @@ exports[`EditLayerPanel is rendered 1`] = ` { import React from 'react'; import { shallow } from 'enzyme'; +import { LAYER_TYPE } from '../../../common/constants'; import { ILayer } from '../../classes/layers/layer'; import { EditLayerPanel } from './edit_layer_panel'; @@ -55,6 +56,9 @@ const mockLayer = { getId: () => { return '1'; }, + getType: () => { + return LAYER_TYPE.VECTOR; + }, getDisplayName: () => { return 'layer 1'; }, @@ -79,6 +83,9 @@ const mockLayer = { hasErrors: () => { return false; }, + hasJoins: () => { + return false; + }, supportsFitToBounds: () => { return true; }, @@ -87,7 +94,8 @@ const mockLayer = { const defaultProps = { selectedLayer: mockLayer, fitToBounds: () => {}, - updateSourceProp: () => {}, + updateSourceProps: async () => {}, + clearJoins: () => {}, }; describe('EditLayerPanel', () => { diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx index 424c4b8e16bec..7ba2f74ddc7d9 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx @@ -30,7 +30,6 @@ import { StyleSettings } from './style_settings'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; -import { LAYER_TYPE } from '../../../common/constants'; import { getData, getCore } from '../../kibana_services'; import { ILayer } from '../../classes/layers/layer'; import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer'; @@ -40,13 +39,9 @@ import { IField } from '../../classes/fields/field'; const localStorage = new Storage(window.localStorage); export interface Props { + clearJoins: (layer: ILayer) => void; selectedLayer?: ILayer; - updateSourceProp: ( - layerId: string, - propName: string, - value: unknown, - newLayerType?: LAYER_TYPE - ) => void; + updateSourceProps: (layerId: string, sourcePropChanges: OnSourceChangeArgs[]) => Promise; } interface State { @@ -141,9 +136,12 @@ export class EditLayerPanel extends Component { } _onSourceChange = (...args: OnSourceChangeArgs[]) => { - for (let i = 0; i < args.length; i++) { - const { propName, value, newLayerType } = args[i]; - this.props.updateSourceProp(this.props.selectedLayer!.getId(), propName, value, newLayerType); + return this.props.updateSourceProps(this.props.selectedLayer!.getId(), args); + }; + + _clearJoins = () => { + if (this.props.selectedLayer) { + this.props.clearJoins(this.props.selectedLayer); } }; @@ -279,6 +277,11 @@ export class EditLayerPanel extends Component { /> {this.props.selectedLayer.renderSourceSettingsEditor({ + clearJoins: this._clearJoins, + currentLayerType: this.props.selectedLayer.getType(), + hasJoins: isVectorLayer(this.props.selectedLayer) + ? (this.props.selectedLayer as IVectorLayer).hasJoins() + : false, onChange: this._onSourceChange, })} diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts index 84caa45741a62..5f9a920d38494 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts @@ -9,11 +9,12 @@ import { AnyAction } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { connect } from 'react-redux'; import { EditLayerPanel } from './edit_layer_panel'; -import { LAYER_TYPE } from '../../../common/constants'; import { getSelectedLayer } from '../../selectors/map_selectors'; -import { updateSourceProp } from '../../actions'; +import { setJoinsForLayer, updateSourceProps } from '../../actions'; import { MapStoreState } from '../../reducers/store'; +import { ILayer } from '../../classes/layers/layer'; import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer'; +import { OnSourceChangeArgs } from '../../classes/sources/source'; function mapStateToProps(state: MapStoreState) { const selectedLayer = getSelectedLayer(state); @@ -31,8 +32,11 @@ function mapStateToProps(state: MapStoreState) { function mapDispatchToProps(dispatch: ThunkDispatch) { return { - updateSourceProp: (id: string, propName: string, value: unknown, newLayerType?: LAYER_TYPE) => - dispatch(updateSourceProp(id, propName, value, newLayerType)), + clearJoins: (layer: ILayer) => { + dispatch(setJoinsForLayer(layer, [])); + }, + updateSourceProps: async (id: string, sourcePropChanges: OnSourceChangeArgs[]) => + await dispatch(updateSourceProps(id, sourcePropChanges)), }; } diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx index e99ec6a688092..24cdd9b7dc813 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx @@ -90,9 +90,7 @@ export function JoinEditor({ joins, layer, onChange, leftJoinFields, layerDispla ) : ( {renderJoins()} - - { ] as [MbPoint, MbPoint]; const selectedFeatures = this.props.mbMap.queryRenderedFeatures(mbBbox, { layers: mbEditLayerIds, - filter: ['all', EXCLUDE_TOO_MANY_FEATURES_BOX, EXCLUDE_CENTROID_FEATURES], + filter: ['all', EXCLUDE_CENTROID_FEATURES], }); if (!selectedFeatures.length) { return; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index 053e410b8c712..93dfebecd1c34 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -33,7 +33,6 @@ import { } from '../../../common/descriptor_types'; import { DECIMAL_DEGREES_PRECISION, - KBN_TOO_MANY_FEATURES_IMAGE_ID, LAYER_TYPE, RawValue, ZOOM_PRECISION, @@ -209,14 +208,6 @@ export class MbMap extends Component { }, }); - const tooManyFeaturesImageSrc = - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAA7DgAAOw4BzLahgwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAARLSURBVHic7ZnPbxRVAMe/7735sWO3293ZlUItJsivCxEE0oTYRgu1FqTQoFSwKTYx8SAH/wHjj4vRozGGi56sMcW2UfqTEuOhppE0KJc2GIuKQFDY7qzdtrudX88D3YTUdFuQN8+k87ltZt7uZz958/bNLAGwBWsYKltANmEA2QKyCQPIFpBNGEC2gGzCALIFZBMGkC0gmzCAbAHZhAFkC8gmDCBbQDZhANkCslnzARQZH6oDpNs0D5UDSUIInePcOpPLfdfnODNBuwQWIAWwNOABwHZN0x8npE6hNLJ4DPWRyFSf40wE5VOEQPBjcR0g3YlE4ybGmtK+/1NzJtOZA/xSYwZMs3nG962T2ez3It2AANaA/kSidYuivOQBs5WM1fUnk6f0u+GXJUqIuUtVXx00zRbRfkIDfBqL7a1WlIYbjvNtTTr99jXXHVpH6dMjK0R4cXq6c9rzxjcx9sKX8XitSEdhAToMI7VP10/97fsTh7PZrgWAN1lW72KE2vOm2b5chDTgtWQyn93x/bEEIetEOQIC14CxVOr1CkKefH929t0v8vn0vcdGEoljGxXl4C3PGz2YyXy+AHARDqtByAxoUdWKBKV70r4/vvTLA0CjZfX+5nkDGxirKzUTgkBIgNaysh3gnF627R+XO+dQJvP1ddcdrmSsbtA020pF+CAW21qrqmUiXIUEqGRsIwD0FQq/lzqv0bJ6rrvucBVjzwyb5ivLRTiiaW+8VV7eIEBVTAANiIIQd9RxZlc6t9Gyem647vn1jD07ZJonl4sQASoevqmgABzwwHnJzc69PGdZ3X+47sgGxuqHTPPE0ggeVtg5/QeEBMhxPg1Aa1DV2GrHPG9ZXy1G2D+wNALn9jyQEeHKAJgP+033Kgrdqij7AFwZtu3bqx3XWShMHtV1o1pRGo4YxiNd+fyEB2DKdX/4aG5u0hbwcylkBryTy/3scT6zW9Nq7ndso2Wdvea6Q1WUHuiPx1/WAXLBcWZXun94UMRcAoD/p+ddTFK6u8MwUvc7vsmyem+67oVqVT0wkEgcF+FYRNhW+L25uX6f84XThtHxIBudE5bVY/t++jFVrU/dvVSFICzAqG3PX/S8rihj2/61qK1AOUB7ksl2jdLUL7Z9rvgcQQRCFsEi5wqFmw26XnhCUQ63GcZmCly95Lrzpca0G0byk3j8tEnpU1c975tmyxoU5QcE8EAEAM5WVOzfoarHAeC2749dcpzxMwsLv07Ztg0AOzVNf03Ttu/S9T2PMlbjc25fdpyutmx2TLRbIAEA4M1otKo1EjmaoHQn4ZwBgA/kAVAK6MXXdzxv/ONcrq/HcbJBeAUWoEizqsaORaPbKglZrxMSZZyrM76f/ovzWx/m85PFWREUgQf4v7Hm/xcIA8gWkE0YQLaAbMIAsgVkEwaQLSCbMIBsAdmEAWQLyCYMIFtANmEA2QKyCQPIFpDNmg/wD3OFdEybUvJjAAAAAElFTkSuQmCC'; - const tooManyFeaturesImage = new Image(); - tooManyFeaturesImage.onload = () => { - mbMap.addImage(KBN_TOO_MANY_FEATURES_IMAGE_ID, tooManyFeaturesImage); - }; - tooManyFeaturesImage.src = tooManyFeaturesImageSrc; - let emptyImage: HTMLImageElement; mbMap.on('styleimagemissing', (e: unknown) => { if (emptyImage) { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx index 7e79113d6b242..54e3f532fe913 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx @@ -14,6 +14,7 @@ jest.mock('./tooltip_popover', () => ({ import sinon from 'sinon'; import React from 'react'; import { mount, shallow } from 'enzyme'; +import { Feature } from 'geojson'; import type { Map as MbMap, MapMouseEvent, MapboxGeoJSONFeature } from '@kbn/mapbox-gl'; import { TooltipControl } from './tooltip_control'; import { IVectorLayer } from '../../../classes/layers/vector_layer'; @@ -36,6 +37,12 @@ const mockLayer = { canShowTooltip: () => { return true; }, + getMbTooltipLayerIds: () => { + return ['foo', 'bar']; + }, + getFeatureId: (feature: Feature) => { + return feature.properties?.__kbn__feature_id__; + }, getFeatureById: () => { return { geometry: { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx index c2ad75d9cb335..dee05b54c45c6 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx @@ -19,12 +19,7 @@ import uuid from 'uuid/v4'; import { Geometry } from 'geojson'; import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; -import { - FEATURE_ID_PROPERTY_NAME, - GEO_JSON_TYPE, - LON_INDEX, - RawValue, -} from '../../../../common/constants'; +import { GEO_JSON_TYPE, LON_INDEX, RawValue } from '../../../../common/constants'; import { GEOMETRY_FILTER_ACTION, TooltipFeature, @@ -33,7 +28,6 @@ import { } from '../../../../common/descriptor_types'; import { TooltipPopover } from './tooltip_popover'; import { FeatureGeometryFilterForm } from './features_tooltip'; -import { EXCLUDE_TOO_MANY_FEATURES_BOX } from '../../../classes/util/mb_filter_expressions'; import { ILayer } from '../../../classes/layers/layer'; import { IVectorLayer, isVectorLayer } from '../../../classes/layers/vector_layer'; import { RenderToolTipContent } from '../../../classes/tooltips/tooltip_property'; @@ -132,7 +126,13 @@ export class TooltipControl extends Component { }) as IVectorLayer; } - _loadPreIndexedShape = async ({ layerId, featureId }: { layerId: string; featureId: string }) => { + _loadPreIndexedShape = async ({ + layerId, + featureId, + }: { + layerId: string; + featureId?: string | number; + }) => { const tooltipLayer = this._findLayerById(layerId); if (!tooltipLayer || typeof featureId === 'undefined') { return null; @@ -152,7 +152,7 @@ export class TooltipControl extends Component { tooltipId, }: { layerId: string; - featureId: string; + featureId?: string | number; tooltipId: string; }): TooltipFeatureAction[] { const actions = []; @@ -203,7 +203,8 @@ export class TooltipControl extends Component { if (!layer) { break; } - const featureId = mbFeature.properties?.[FEATURE_ID_PROPERTY_NAME]; + + const featureId = layer.getFeatureId(mbFeature); const layerId = layer.getId(); let match = false; for (let j = 0; j < uniqueFeatures.length; j++) { @@ -284,9 +285,10 @@ export class TooltipControl extends Component { } const targetMbFeature = mbFeatures[0]; - if (this.props.openTooltips[0] && this.props.openTooltips[0].features.length) { + const layer = this._getLayerByMbLayerId(targetMbFeature.layer.id); + if (layer && this.props.openTooltips[0] && this.props.openTooltips[0].features.length) { const firstFeature = this.props.openTooltips[0].features[0]; - if (targetMbFeature.properties?.[FEATURE_ID_PROPERTY_NAME] === firstFeature.id) { + if (layer.getFeatureId(targetMbFeature) === firstFeature.id) { // ignore hover events when hover tooltip is all ready opened for feature return; } @@ -312,7 +314,7 @@ export class TooltipControl extends Component { (accumulator: string[], layer: ILayer) => { // tooltips are only supported for vector layers, filter out all other layer types return layer.isVisible() && isVectorLayer(layer) - ? accumulator.concat(layer.getMbLayerIds()) + ? accumulator.concat((layer as IVectorLayer).getMbTooltipLayerIds()) : accumulator; }, [] @@ -347,7 +349,6 @@ export class TooltipControl extends Component { ] as [MbPoint, MbPoint]; return this.props.mbMap.queryRenderedFeatures(mbBbox, { layers: mbLayerIds, - filter: EXCLUDE_TOO_MANY_FEATURES_BOX, }); } diff --git a/x-pack/plugins/maps/public/util.test.js b/x-pack/plugins/maps/public/util.test.js index 47c3d77180077..c8c93a6a93aef 100644 --- a/x-pack/plugins/maps/public/util.test.js +++ b/x-pack/plugins/maps/public/util.test.js @@ -49,27 +49,11 @@ describe('getGlyphUrl', () => { }); }); - describe('EMS proxy enabled', () => { - beforeAll(() => { - require('./kibana_services').getEMSSettings = () => { - return { - ...MOCK_EMS_SETTINGS, - isProxyElasticMapsServiceInMaps: () => true, - }; - }; - }); - - test('should return proxied EMS fonts URL', async () => { - expect(getGlyphUrl()).toBe('http://localhost/api/maps/ems/tiles/fonts/{fontstack}/{range}'); - }); - }); - describe('EMS proxy disabled', () => { beforeAll(() => { require('./kibana_services').getEMSSettings = () => { return { ...MOCK_EMS_SETTINGS, - isProxyElasticMapsServiceInMaps: () => false, }; }; }); diff --git a/x-pack/plugins/maps/public/util.ts b/x-pack/plugins/maps/public/util.ts index f92a60ffedfdc..a6bc1412691ab 100644 --- a/x-pack/plugins/maps/public/util.ts +++ b/x-pack/plugins/maps/public/util.ts @@ -7,15 +7,7 @@ import { i18n } from '@kbn/i18n'; import { EMSClient, FileLayer, TMSService } from '@elastic/ems-client'; -import _ from 'lodash'; -import { - GIS_API_PATH, - EMS_FILES_CATALOGUE_PATH, - EMS_TILES_CATALOGUE_PATH, - EMS_GLYPHS_PATH, - EMS_APP_NAME, - FONTS_API_PATH, -} from '../common/constants'; +import { EMS_APP_NAME, FONTS_API_PATH } from '../common/constants'; import { getHttp, getTilemap, getKibanaVersion, getEMSSettings } from './kibana_services'; import { getLicenseId } from './licensed_features'; @@ -39,28 +31,14 @@ export async function getEmsTmsServices(): Promise { return getEMSClient().getTMSServices(); } -function relativeToAbsolute(url: string): string { - const a = document.createElement('a'); - a.setAttribute('href', url); - return a.href; -} - let emsClient: EMSClient | null = null; let latestLicenseId: string | undefined; export function getEMSClient(): EMSClient { if (!emsClient) { const emsSettings = getEMSSettings(); const proxyPath = ''; - const tileApiUrl = emsSettings!.isProxyElasticMapsServiceInMaps() - ? relativeToAbsolute( - getHttp().basePath.prepend(`/${GIS_API_PATH}/${EMS_TILES_CATALOGUE_PATH}`) - ) - : emsSettings!.getEMSTileApiUrl(); - const fileApiUrl = emsSettings!.isProxyElasticMapsServiceInMaps() - ? relativeToAbsolute( - getHttp().basePath.prepend(`/${GIS_API_PATH}/${EMS_FILES_CATALOGUE_PATH}`) - ) - : emsSettings!.getEMSFileApiUrl(); + const tileApiUrl = emsSettings!.getEMSTileApiUrl(); + const fileApiUrl = emsSettings!.getEMSFileApiUrl(); emsClient = new EMSClient({ language: i18n.getLocale(), @@ -89,13 +67,7 @@ export function getGlyphUrl(): string { return getHttp().basePath.prepend(`/${FONTS_API_PATH}/{fontstack}/{range}`); } - return emsSettings!.isProxyElasticMapsServiceInMaps() - ? relativeToAbsolute( - getHttp().basePath.prepend( - `/${GIS_API_PATH}/${EMS_TILES_CATALOGUE_PATH}/${EMS_GLYPHS_PATH}` - ) - ) + `/{fontstack}/{range}` - : emsSettings!.getEMSFontLibraryUrl(); + return emsSettings!.getEMSFontLibraryUrl(); } export function isRetina(): boolean { diff --git a/x-pack/plugins/maps/server/index.ts b/x-pack/plugins/maps/server/index.ts index e00951610bbed..55eaadcd28063 100644 --- a/x-pack/plugins/maps/server/index.ts +++ b/x-pack/plugins/maps/server/index.ts @@ -5,9 +5,6 @@ * 2.0. */ -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { AddConfigDeprecation } from '@kbn/config'; import { PluginInitializerContext } from 'src/core/server'; import { PluginConfigDescriptor } from 'kibana/server'; import { MapsPlugin } from './plugin'; @@ -21,37 +18,6 @@ export const config: PluginConfigDescriptor = { preserveDrawingBuffer: true, }, schema: configSchema, - deprecations: () => [ - ( - completeConfig: Record, - rootPath: string, - addDeprecation: AddConfigDeprecation - ) => { - if (_.get(completeConfig, 'map.proxyElasticMapsServiceInMaps') === undefined) { - return completeConfig; - } - addDeprecation({ - configPath: 'map.proxyElasticMapsServiceInMaps', - documentationUrl: - 'https://www.elastic.co/guide/en/kibana/current/maps-connect-to-ems.html#elastic-maps-server', - message: i18n.translate('xpack.maps.deprecation.proxyEMS.message', { - defaultMessage: 'map.proxyElasticMapsServiceInMaps is deprecated and is no longer used', - }), - correctiveActions: { - manualSteps: [ - i18n.translate('xpack.maps.deprecation.proxyEMS.step1', { - defaultMessage: - 'Remove "map.proxyElasticMapsServiceInMaps" in the Kibana config file, CLI flag, or environment variable (in Docker only).', - }), - i18n.translate('xpack.maps.deprecation.proxyEMS.step2', { - defaultMessage: 'Host Elastic Maps Service locally.', - }), - ], - }, - }); - return completeConfig; - }, - ], }; export const plugin = (initializerContext: PluginInitializerContext) => diff --git a/x-pack/plugins/maps/server/kibana_server_services.ts b/x-pack/plugins/maps/server/kibana_server_services.ts index e3c612f415c4d..f5bd4dad085d8 100644 --- a/x-pack/plugins/maps/server/kibana_server_services.ts +++ b/x-pack/plugins/maps/server/kibana_server_services.ts @@ -20,14 +20,17 @@ export const setInternalRepository = ( }; export const getInternalRepository = () => internalRepository; +let esClient: ElasticsearchClient; let indexPatternsService: IndexPatternsCommonService; export const setIndexPatternsService = async ( indexPatternsServiceFactory: IndexPatternsServiceStart['indexPatternsServiceFactory'], elasticsearchClient: ElasticsearchClient ) => { + esClient = elasticsearchClient; indexPatternsService = await indexPatternsServiceFactory( new SavedObjectsClient(getInternalRepository()), elasticsearchClient ); }; export const getIndexPatternsService = () => indexPatternsService; +export const getESClient = () => esClient; diff --git a/x-pack/plugins/maps/server/mvt/get_grid_tile.ts b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts new file mode 100644 index 0000000000000..cfc894d512450 --- /dev/null +++ b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from 'src/core/server'; +import type { DataRequestHandlerContext } from 'src/plugins/data/server'; +import { RENDER_AS } from '../../common/constants'; + +function isAbortError(error: Error) { + return error.message === 'Request aborted' || error.message === 'Aborted'; +} + +export async function getEsGridTile({ + logger, + context, + index, + geometryFieldName, + x, + y, + z, + requestBody = {}, + requestType = RENDER_AS.POINT, +}: { + x: number; + y: number; + z: number; + geometryFieldName: string; + index: string; + context: DataRequestHandlerContext; + logger: Logger; + requestBody: any; + requestType: RENDER_AS.GRID | RENDER_AS.POINT; +}): Promise { + try { + const path = `/${encodeURIComponent(index)}/_mvt/${geometryFieldName}/${z}/${x}/${y}`; + const body = { + size: 0, // no hits + grid_precision: 7, + exact_bounds: false, + extent: 4096, // full resolution, + query: requestBody.query, + grid_type: requestType === RENDER_AS.GRID ? 'grid' : 'centroid', + aggs: requestBody.aggs, + fields: requestBody.fields, + runtime_mappings: requestBody.runtime_mappings, + }; + const tile = await context.core.elasticsearch.client.asCurrentUser.transport.request({ + method: 'GET', + path, + body, + }); + return tile.body as unknown as Buffer; + } catch (e) { + if (!isAbortError(e)) { + // These are often circuit breaking exceptions + // Should return a tile with some error message + logger.warn(`Cannot generate ES-grid-tile for ${z}/${x}/${y}: ${e.message}`); + } + return null; + } +} diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index 11e1af5a7d368..0864b373af3f8 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -5,53 +5,15 @@ * 2.0. */ -// @ts-expect-error -import geojsonvt from 'geojson-vt'; -// @ts-expect-error -import vtpbf from 'vt-pbf'; +import _ from 'lodash'; import { Logger } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; -import { Feature, FeatureCollection, Polygon } from 'geojson'; -import { countVectorShapeTypes } from '../../common/get_geometry_counts'; -import { - COUNT_PROP_NAME, - ES_GEO_FIELD_TYPE, - FEATURE_ID_PROPERTY_NAME, - GEOTILE_GRID_AGG_NAME, - KBN_FEATURE_COUNT, - KBN_IS_TILE_COMPLETE, - KBN_METADATA_FEATURE, - KBN_VECTOR_SHAPE_TYPE_COUNTS, - MAX_ZOOM, - MVT_SOURCE_LAYER_NAME, - RENDER_AS, - SUPER_FINE_ZOOM_DELTA, - VECTOR_SHAPE_TYPE, -} from '../../common/constants'; - -import { - createExtentFilter, - convertRegularRespToGeoJson, - hitsToGeoJson, - isTotalHitsGreaterThan, - formatEnvelopeAsPolygon, - TotalHits, -} from '../../common/elasticsearch_util'; -import { flattenHit } from './util'; -import { ESBounds, tileToESBbox } from '../../common/geo_tile_utils'; -import { getCentroidFeatures } from '../../common/get_centroid_features'; -import { pluckRangeFieldMeta } from '../../common/pluck_range_field_meta'; -import { FieldMeta, TileMetaFeature } from '../../common/descriptor_types'; -import { pluckCategoryFieldMeta } from '../../common/pluck_category_field_meta'; - -// heuristic. largest color-palette has 30 colors. 1 color is used for 'other'. -const TERM_COUNT = 30 - 1; function isAbortError(error: Error) { return error.message === 'Request aborted' || error.message === 'Aborted'; } -export async function getGridTile({ +export async function getEsTile({ logger, context, index, @@ -60,9 +22,6 @@ export async function getGridTile({ y, z, requestBody = {}, - requestType = RENDER_AS.POINT, - searchSessionId, - abortSignal, }: { x: number; y: number; @@ -72,388 +31,32 @@ export async function getGridTile({ context: DataRequestHandlerContext; logger: Logger; requestBody: any; - requestType: RENDER_AS.GRID | RENDER_AS.POINT; - geoFieldType: ES_GEO_FIELD_TYPE; - searchSessionId?: string; - abortSignal: AbortSignal; }): Promise { try { - const tileBounds: ESBounds = tileToESBbox(x, y, z); - requestBody.query.bool.filter.push(getTileSpatialFilter(geometryFieldName, tileBounds)); - requestBody.aggs[GEOTILE_GRID_AGG_NAME].geotile_grid.precision = Math.min( - z + SUPER_FINE_ZOOM_DELTA, - MAX_ZOOM - ); - requestBody.aggs[GEOTILE_GRID_AGG_NAME].geotile_grid.bounds = tileBounds; - requestBody.track_total_hits = false; - - const response = await context - .search!.search( - { - params: { - index, - body: requestBody, - }, - }, - { - sessionId: searchSessionId, - legacyHitsTotal: false, - abortSignal, - } - ) - .toPromise(); - const features: Feature[] = convertRegularRespToGeoJson(response.rawResponse, requestType); - - if (features.length) { - const bounds = formatEnvelopeAsPolygon({ - maxLat: tileBounds.top_left.lat, - minLat: tileBounds.bottom_right.lat, - maxLon: tileBounds.bottom_right.lon, - minLon: tileBounds.top_left.lon, - }); - - const fieldNames = new Set(); - features.forEach((feature) => { - for (const key in feature.properties) { - if (feature.properties.hasOwnProperty(key) && key !== 'key' && key !== 'gridCentroid') { - fieldNames.add(key); - } - } - }); - - const fieldMeta: FieldMeta = {}; - fieldNames.forEach((fieldName: string) => { - const rangeMeta = pluckRangeFieldMeta(features, fieldName, (rawValue: unknown) => { - if (fieldName === COUNT_PROP_NAME) { - return parseFloat(rawValue as string); - } else if (typeof rawValue === 'number') { - return rawValue; - } else if (rawValue) { - return parseFloat((rawValue as { value: string }).value); - } else { - return NaN; - } - }); - - const categoryMeta = pluckCategoryFieldMeta(features, fieldName, TERM_COUNT); - - if (!fieldMeta[fieldName]) { - fieldMeta[fieldName] = {}; - } - - if (rangeMeta) { - fieldMeta[fieldName].range = rangeMeta; - } - - if (categoryMeta) { - fieldMeta[fieldName].categories = categoryMeta; - } - }); - - const metaDataFeature: TileMetaFeature = { - type: 'Feature', - properties: { - [KBN_METADATA_FEATURE]: true, - [KBN_FEATURE_COUNT]: features.length, - [KBN_IS_TILE_COMPLETE]: true, - [KBN_VECTOR_SHAPE_TYPE_COUNTS]: - requestType === RENDER_AS.GRID - ? { - [VECTOR_SHAPE_TYPE.POINT]: 0, - [VECTOR_SHAPE_TYPE.LINE]: 0, - [VECTOR_SHAPE_TYPE.POLYGON]: features.length, - } - : { - [VECTOR_SHAPE_TYPE.POINT]: features.length, - [VECTOR_SHAPE_TYPE.LINE]: 0, - [VECTOR_SHAPE_TYPE.POLYGON]: 0, - }, - fieldMeta, - }, - geometry: bounds, - }; - - features.push(metaDataFeature); - } - - const featureCollection: FeatureCollection = { - features, - type: 'FeatureCollection', + const path = `/${encodeURIComponent(index)}/_mvt/${geometryFieldName}/${z}/${x}/${y}`; + let fields = _.uniq(requestBody.docvalue_fields.concat(requestBody.stored_fields)); + fields = fields.filter((f) => f !== geometryFieldName); + const body = { + grid_precision: 0, // no aggs + exact_bounds: true, + extent: 4096, // full resolution, + query: requestBody.query, + fields, + runtime_mappings: requestBody.runtime_mappings, + track_total_hits: requestBody.size + 1, }; - - return createMvtTile(featureCollection, z, x, y); + const tile = await context.core.elasticsearch.client.asCurrentUser.transport.request({ + method: 'GET', + path, + body, + }); + return tile.body as unknown as Buffer; } catch (e) { if (!isAbortError(e)) { // These are often circuit breaking exceptions // Should return a tile with some error message - logger.warn(`Cannot generate grid-tile for ${z}/${x}/${y}: ${e.message}`); + logger.warn(`Cannot generate ES-grid-tile for ${z}/${x}/${y}: ${e.message}`); } return null; } } - -export async function getTile({ - logger, - context, - index, - geometryFieldName, - x, - y, - z, - requestBody = {}, - geoFieldType, - searchSessionId, - abortSignal, -}: { - x: number; - y: number; - z: number; - geometryFieldName: string; - index: string; - context: DataRequestHandlerContext; - logger: Logger; - requestBody: any; - geoFieldType: ES_GEO_FIELD_TYPE; - searchSessionId?: string; - abortSignal: AbortSignal; -}): Promise { - let features: Feature[]; - try { - requestBody.query.bool.filter.push( - getTileSpatialFilter(geometryFieldName, tileToESBbox(x, y, z)) - ); - - const searchOptions = { - sessionId: searchSessionId, - legacyHitsTotal: false, - abortSignal, - }; - - const countResponse = await context - .search!.search( - { - params: { - index, - body: { - size: 0, - query: requestBody.query, - track_total_hits: requestBody.size + 1, - }, - }, - }, - searchOptions - ) - .toPromise(); - - if ( - isTotalHitsGreaterThan( - countResponse.rawResponse.hits.total as unknown as TotalHits, - requestBody.size - ) - ) { - // Generate "too many features"-bounds - const bboxResponse = await context - .search!.search( - { - params: { - index, - body: { - size: 0, - query: requestBody.query, - aggs: { - data_bounds: { - geo_bounds: { - field: geometryFieldName, - }, - }, - }, - track_total_hits: false, - }, - }, - }, - searchOptions - ) - .toPromise(); - - const metaDataFeature: TileMetaFeature = { - type: 'Feature', - properties: { - [KBN_METADATA_FEATURE]: true, - [KBN_IS_TILE_COMPLETE]: false, - [KBN_FEATURE_COUNT]: 0, - [KBN_VECTOR_SHAPE_TYPE_COUNTS]: { - [VECTOR_SHAPE_TYPE.POINT]: 0, - [VECTOR_SHAPE_TYPE.LINE]: 0, - [VECTOR_SHAPE_TYPE.POLYGON]: 0, - }, - }, - geometry: esBboxToGeoJsonPolygon( - // @ts-expect-error @elastic/elasticsearch no way to declare aggregations for search response - bboxResponse.rawResponse.aggregations.data_bounds.bounds, - tileToESBbox(x, y, z) - ), - }; - features = [metaDataFeature]; - } else { - const documentsResponse = await context - .search!.search( - { - params: { - index, - body: { - ...requestBody, - track_total_hits: false, - }, - }, - }, - searchOptions - ) - .toPromise(); - - const featureCollection = hitsToGeoJson( - // @ts-expect-error hitsToGeoJson should be refactored to accept estypes.SearchHit - documentsResponse.rawResponse.hits.hits, - (hit: Record) => { - return flattenHit(geometryFieldName, hit); - }, - geometryFieldName, - geoFieldType, - [] - ); - - features = featureCollection.features; - - // Correct system-fields. - for (let i = 0; i < features.length; i++) { - const props = features[i].properties; - if (props !== null) { - props[FEATURE_ID_PROPERTY_NAME] = features[i].id; - } - } - - const counts = countVectorShapeTypes(features); - - const fieldNames = new Set(); - features.forEach((feature) => { - for (const key in feature.properties) { - if ( - feature.properties.hasOwnProperty(key) && - key !== '_index' && - key !== '_id' && - key !== FEATURE_ID_PROPERTY_NAME - ) { - fieldNames.add(key); - } - } - }); - - const fieldMeta: FieldMeta = {}; - fieldNames.forEach((fieldName: string) => { - const rangeMeta = pluckRangeFieldMeta(features, fieldName, (rawValue: unknown) => { - return typeof rawValue === 'number' ? rawValue : NaN; - }); - const categoryMeta = pluckCategoryFieldMeta(features, fieldName, TERM_COUNT); - - if (!fieldMeta[fieldName]) { - fieldMeta[fieldName] = {}; - } - - if (rangeMeta) { - fieldMeta[fieldName].range = rangeMeta; - } - - if (categoryMeta) { - fieldMeta[fieldName].categories = categoryMeta; - } - }); - - const metadataFeature: TileMetaFeature = { - type: 'Feature', - properties: { - [KBN_METADATA_FEATURE]: true, - [KBN_IS_TILE_COMPLETE]: true, - [KBN_VECTOR_SHAPE_TYPE_COUNTS]: counts, - [KBN_FEATURE_COUNT]: features.length, - fieldMeta, - }, - geometry: esBboxToGeoJsonPolygon(tileToESBbox(x, y, z), tileToESBbox(x, y, z)), - }; - - features.push(metadataFeature); - } - - const featureCollection: FeatureCollection = { - features, - type: 'FeatureCollection', - }; - - return createMvtTile(featureCollection, z, x, y); - } catch (e) { - if (!isAbortError(e)) { - logger.warn(`Cannot generate tile for ${z}/${x}/${y}: ${e.message}`); - } - return null; - } -} - -function getTileSpatialFilter(geometryFieldName: string, tileBounds: ESBounds): unknown { - const tileExtent = { - minLon: tileBounds.top_left.lon, - minLat: tileBounds.bottom_right.lat, - maxLon: tileBounds.bottom_right.lon, - maxLat: tileBounds.top_left.lat, - }; - const tileExtentFilter = createExtentFilter(tileExtent, [geometryFieldName]); - return tileExtentFilter.query; -} - -function esBboxToGeoJsonPolygon(esBounds: ESBounds, tileBounds: ESBounds): Polygon { - // Intersecting geo_shapes may push bounding box outside of tile so need to clamp to tile bounds. - let minLon = Math.max(esBounds.top_left.lon, tileBounds.top_left.lon); - const maxLon = Math.min(esBounds.bottom_right.lon, tileBounds.bottom_right.lon); - minLon = minLon > maxLon ? minLon - 360 : minLon; // fixes an ES bbox to straddle dateline - const minLat = Math.max(esBounds.bottom_right.lat, tileBounds.bottom_right.lat); - const maxLat = Math.min(esBounds.top_left.lat, tileBounds.top_left.lat); - - return { - type: 'Polygon', - coordinates: [ - [ - [minLon, minLat], - [minLon, maxLat], - [maxLon, maxLat], - [maxLon, minLat], - [minLon, minLat], - ], - ], - }; -} - -function createMvtTile( - featureCollection: FeatureCollection, - z: number, - x: number, - y: number -): Buffer | null { - featureCollection.features.push(...getCentroidFeatures(featureCollection)); - const tileIndex = geojsonvt(featureCollection, { - maxZoom: 24, // max zoom to preserve detail on; can't be higher than 24 - tolerance: 3, // simplification tolerance (higher means simpler) - extent: 4096, // tile extent (both width and height) - buffer: 64, // tile buffer on each side - debug: 0, // logging level (0 to disable, 1 or 2) - lineMetrics: false, // whether to enable line metrics tracking for LineString/MultiLineString features - promoteId: null, // name of a feature property to promote to feature.id. Cannot be used with `generateId` - generateId: false, // whether to generate feature ids. Cannot be used with `promoteId` - indexMaxZoom: 5, // max zoom in the initial tile index - indexMaxPoints: 100000, // max number of points per tile in the index - }); - const tile = tileIndex.getTile(z, x, y); - - if (tile) { - const pbf = vtpbf.fromGeojsonVt({ [MVT_SOURCE_LAYER_NAME]: tile }, { version: 2 }); - return Buffer.from(pbf); - } else { - return null; - } -} diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index 01a89aff1a661..3c61a47a383d6 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -16,10 +16,10 @@ import { MVT_GETTILE_API_PATH, API_ROOT_PATH, MVT_GETGRIDTILE_API_PATH, - ES_GEO_FIELD_TYPE, RENDER_AS, } from '../../common/constants'; -import { getGridTile, getTile } from './get_tile'; +import { getEsTile } from './get_tile'; +import { getEsGridTile } from './get_grid_tile'; const CACHE_TIMEOUT_SECONDS = 60 * 60; @@ -43,8 +43,6 @@ export function initMVTRoutes({ geometryFieldName: schema.string(), requestBody: schema.string(), index: schema.string(), - geoFieldType: schema.string(), - searchSessionId: schema.maybe(schema.string()), token: schema.maybe(schema.string()), }), }, @@ -56,14 +54,15 @@ export function initMVTRoutes({ ) => { const { query, params } = request; - const abortController = new AbortController(); - request.events.aborted$.subscribe(() => { - abortController.abort(); - }); + // todo - replace with direct abortion of raw transport request + // const abortController = new AbortController(); + // request.events.aborted$.subscribe(() => { + // abortController.abort(); + // }); const requestBodyDSL = rison.decode(query.requestBody as string); - const tile = await getTile({ + const tile = await getEsTile({ logger, context, geometryFieldName: query.geometryFieldName as string, @@ -72,9 +71,6 @@ export function initMVTRoutes({ z: parseInt((params as any).z, 10) as number, index: query.index as string, requestBody: requestBodyDSL as any, - geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, - searchSessionId: query.searchSessionId, - abortSignal: abortController.signal, }); return sendResponse(response, tile); @@ -95,8 +91,6 @@ export function initMVTRoutes({ requestBody: schema.string(), index: schema.string(), requestType: schema.string(), - geoFieldType: schema.string(), - searchSessionId: schema.maybe(schema.string()), token: schema.maybe(schema.string()), }), }, @@ -107,14 +101,16 @@ export function initMVTRoutes({ response: KibanaResponseFactory ) => { const { query, params } = request; - const abortController = new AbortController(); - request.events.aborted$.subscribe(() => { - abortController.abort(); - }); + + // todo - replace with direct abortion of raw transport request + // const abortController = new AbortController(); + // request.events.aborted$.subscribe(() => { + // abortController.abort(); + // }); const requestBodyDSL = rison.decode(query.requestBody as string); - const tile = await getGridTile({ + const tile = await getEsGridTile({ logger, context, geometryFieldName: query.geometryFieldName as string, @@ -124,9 +120,6 @@ export function initMVTRoutes({ index: query.index as string, requestBody: requestBodyDSL as any, requestType: query.requestType as RENDER_AS.POINT | RENDER_AS.GRID, - geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, - searchSessionId: query.searchSessionId, - abortSignal: abortController.signal, }); return sendResponse(response, tile); diff --git a/x-pack/plugins/maps/server/mvt/util.ts b/x-pack/plugins/maps/server/mvt/util.ts deleted file mode 100644 index b3dc606ba3f11..0000000000000 --- a/x-pack/plugins/maps/server/mvt/util.ts +++ /dev/null @@ -1,75 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// This implementation: -// - does not include meta-fields -// - does not validate the schema against the index-pattern (e.g. nested fields) -// In the context of .mvt this is sufficient: -// - only fields from the response are packed in the tile (more efficient) -// - query-dsl submitted from the client, which was generated by the IndexPattern -// todo: Ideally, this should adapt/reuse from https://github.com/elastic/kibana/blob/52b42a81faa9dd5c102b9fbb9a645748c3623121/src/plugins/data/common/index_patterns/index_patterns/flatten_hit.ts#L26 - -export function flattenHit( - geometryField: string, - hit: Record -): Record { - const flat: Record = {}; - if (hit) { - flattenSource(flat, '', hit._source as Record, geometryField); - if (hit.fields) { - flattenFields(flat, hit.fields as Array>); - } - - // Attach meta fields - flat._index = hit._index; - flat._id = hit._id; - } - return flat; -} - -function flattenSource( - accum: Record, - path: string, - properties: Record = {}, - geometryField: string -): Record { - accum = accum || {}; - for (const key in properties) { - if (properties.hasOwnProperty(key)) { - const newKey = path ? path + '.' + key : key; - let value; - if (geometryField === newKey) { - value = properties[key]; // do not deep-copy the geometry - } else if (properties[key] !== null && typeof value === 'object' && !Array.isArray(value)) { - value = flattenSource( - accum, - newKey, - properties[key] as Record, - geometryField - ); - } else { - value = properties[key]; - } - accum[newKey] = value; - } - } - return accum; -} - -function flattenFields(accum: Record = {}, fields: Array>) { - accum = accum || {}; - for (const key in fields) { - if (fields.hasOwnProperty(key)) { - const value = fields[key]; - if (Array.isArray(value)) { - accum[key] = value[0]; - } else { - accum[key] = value; - } - } - } -} diff --git a/x-pack/plugins/maps/server/plugin.ts b/x-pack/plugins/maps/server/plugin.ts index 8768580089f31..8145b2bd8bb28 100644 --- a/x-pack/plugins/maps/server/plugin.ts +++ b/x-pack/plugins/maps/server/plugin.ts @@ -83,6 +83,18 @@ export class MapsPlugin implements Plugin { }, ]); + home.sampleData.replacePanelInSampleDatasetDashboard({ + sampleDataId: 'ecommerce', + dashboardId: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', + oldEmbeddableId: '9c6f83f0-bb4d-11e8-9c84-77068524bcab', + embeddableId: '2c9c1f60-1909-11e9-919b-ffe5949a18d2', + // @ts-ignore + embeddableType: MAP_SAVED_OBJECT_TYPE, + embeddableConfig: { + isLayerTOCOpen: false, + }, + }); + home.sampleData.addSavedObjectsToSampleDataset('flights', getFlightsSavedObjects()); home.sampleData.addAppLinksToSampleDataset('flights', [ diff --git a/x-pack/plugins/maps/server/routes.js b/x-pack/plugins/maps/server/routes.js index 7587ec54218e5..da3385de4db8e 100644 --- a/x-pack/plugins/maps/server/routes.js +++ b/x-pack/plugins/maps/server/routes.js @@ -5,27 +5,7 @@ * 2.0. */ -import { - EMS_APP_NAME, - EMS_FILES_API_PATH, - EMS_FILES_CATALOGUE_PATH, - EMS_FILES_DEFAULT_JSON_PATH, - EMS_TILES_API_PATH, - EMS_TILES_CATALOGUE_PATH, - EMS_GLYPHS_PATH, - EMS_TILES_RASTER_STYLE_PATH, - EMS_TILES_RASTER_TILE_PATH, - EMS_TILES_VECTOR_STYLE_PATH, - EMS_TILES_VECTOR_SOURCE_PATH, - EMS_TILES_VECTOR_TILE_PATH, - EMS_SPRITES_PATH, - INDEX_SETTINGS_API_PATH, - FONTS_API_PATH, - API_ROOT_PATH, -} from '../common/constants'; -import { EMSClient } from '@elastic/ems-client'; -import fetch from 'node-fetch'; -import { i18n } from '@kbn/i18n'; +import { INDEX_SETTINGS_API_PATH, FONTS_API_PATH } from '../common/constants'; import { getIndexPatternSettings } from './lib/get_index_pattern_settings'; import { schema } from '@kbn/config-schema'; import fs from 'fs'; @@ -33,449 +13,10 @@ import path from 'path'; import { initMVTRoutes } from './mvt/mvt_routes'; import { initIndexingRoutes } from './data_indexing/indexing_routes'; -const EMPTY_EMS_CLIENT = { - async getFileLayers() { - return []; - }, - async getTMSServices() { - return []; - }, - async getDefaultFileManifest() { - return null; - }, - async getDefaultTMSManifest() { - return null; - }, - addQueryParams() {}, -}; - export async function initRoutes(core, getLicenseId, emsSettings, kbnVersion, logger) { - let emsClient; - let lastLicenseId; const router = core.http.createRouter(); const [, { data: dataPlugin }] = await core.getStartServices(); - function getEMSClient() { - const currentLicenseId = getLicenseId(); - if (emsClient && emsSettings.isEMSEnabled() && lastLicenseId === currentLicenseId) { - return emsClient; - } - - lastLicenseId = currentLicenseId; - if (emsSettings.isIncludeElasticMapsService()) { - emsClient = new EMSClient({ - language: i18n.getLocale(), - appVersion: kbnVersion, - appName: EMS_APP_NAME, - fileApiUrl: emsSettings.getEMSFileApiUrl(), - tileApiUrl: emsSettings.getEMSTileApiUrl(), - landingPageUrl: emsSettings.getEMSLandingPageUrl(), - fetchFunction: fetch, - }); - emsClient.addQueryParams({ - license: currentLicenseId, - is_kibana_proxy: '1', // identifies this is proxied request from kibana - }); - return emsClient; - } else { - return EMPTY_EMS_CLIENT; - } - } - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_FILES_API_PATH}/${EMS_FILES_DEFAULT_JSON_PATH}`, - validate: { - query: schema.object({ - id: schema.maybe(schema.string()), - elastic_tile_service_tos: schema.maybe(schema.string()), - my_app_name: schema.maybe(schema.string()), - my_app_version: schema.maybe(schema.string()), - license: schema.maybe(schema.string()), - }), - }, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - if (!request.query.id) { - logger.warn('Must supply id parameters to retrieve EMS file'); - return null; - } - - const fileLayers = await getEMSClient().getFileLayers(); - const layer = fileLayers.find((layer) => layer.getId() === request.query.id); - if (!layer) { - return null; - } - - try { - const file = await fetch(layer.getDefaultFormatUrl()); - const fileJson = await file.json(); - return ok({ body: fileJson }); - } catch (e) { - logger.warn(`Cannot connect to EMS for file, error: ${e.message}`); - return badRequest(`Cannot connect to EMS`); - } - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_TILES_RASTER_TILE_PATH}`, - validate: false, - }, - async (context, request, response) => { - if (!checkEMSProxyEnabled()) { - return response.badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - if ( - !request.query.id || - typeof parseInt(request.query.x, 10) !== 'number' || - typeof parseInt(request.query.y, 10) !== 'number' || - typeof parseInt(request.query.z, 10) !== 'number' - ) { - logger.warn('Must supply id/x/y/z parameters to retrieve EMS raster tile'); - return null; - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.query.id); - if (!tmsService) { - return null; - } - - const urlTemplate = await tmsService.getUrlTemplate(); - const url = urlTemplate - .replace('{x}', request.query.x) - .replace('{y}', request.query.y) - .replace('{z}', request.query.z); - - return await proxyResource({ url, contentType: 'image/png' }, response); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_FILES_CATALOGUE_PATH}/{emsVersion}/manifest`, - validate: false, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const file = await getEMSClient().getDefaultFileManifest(); //need raw manifest - const fileLayers = await getEMSClient().getFileLayers(); - - const layers = file.layers.map((layerJson) => { - const newLayerJson = { ...layerJson }; - const id = encodeURIComponent(layerJson.layer_id); - - const fileLayer = fileLayers.find((fileLayer) => fileLayer.getId() === layerJson.layer_id); - const defaultFormat = layerJson.formats.find( - (format) => format.type === fileLayer.getDefaultFormatType() - ); - - const newUrl = `${EMS_FILES_DEFAULT_JSON_PATH}?id=${id}`; - - //Only proxy default-format. Others are unused in Maps-app - newLayerJson.formats = [ - { - ...defaultFormat, - url: newUrl, - }, - ]; - return newLayerJson; - }); - //rewrite - return ok({ - body: { - layers, - }, - }); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_CATALOGUE_PATH}/{emsVersion}/manifest`, - validate: false, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const tilesManifest = await getEMSClient().getDefaultTMSManifest(); - const newServices = tilesManifest.services.map((service) => { - const newService = { - ...service, - }; - - newService.formats = []; - const rasterFormats = service.formats.filter((format) => format.format === 'raster'); - if (rasterFormats.length) { - const newUrl = `${EMS_TILES_RASTER_STYLE_PATH}?id=${service.id}`; - newService.formats.push({ - ...rasterFormats[0], - url: newUrl, - }); - } - const vectorFormats = service.formats.filter((format) => format.format === 'vector'); - if (vectorFormats.length) { - const newUrl = `${EMS_TILES_VECTOR_STYLE_PATH}?id=${service.id}`; - newService.formats.push({ - ...vectorFormats[0], - url: newUrl, - }); - } - return newService; - }); - - return ok({ - body: { - services: newServices, - }, - }); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_TILES_RASTER_STYLE_PATH}`, - validate: { - query: schema.object({ - id: schema.maybe(schema.string()), - }), - }, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - if (!request.query.id) { - logger.warn('Must supply id parameter to retrieve EMS raster style'); - return null; - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.query.id); - if (!tmsService) { - return null; - } - const style = await tmsService.getDefaultRasterStyle(); - - const newUrl = `${EMS_TILES_RASTER_TILE_PATH}?id=${request.query.id}&x={x}&y={y}&z={z}`; - return ok({ - body: { - ...style, - tiles: [newUrl], - }, - }); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_TILES_VECTOR_STYLE_PATH}`, - validate: { - query: schema.object({ - id: schema.string(), - elastic_tile_service_tos: schema.maybe(schema.string()), - my_app_name: schema.maybe(schema.string()), - my_app_version: schema.maybe(schema.string()), - license: schema.maybe(schema.string()), - }), - }, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.query.id); - if (!tmsService) { - return null; - } - - const vectorStyle = await tmsService.getVectorStyleSheetRaw(); - const newSources = {}; - for (const sourceId in vectorStyle.sources) { - if (vectorStyle.sources.hasOwnProperty(sourceId)) { - newSources[sourceId] = { - type: 'vector', - url: `${EMS_TILES_VECTOR_SOURCE_PATH}?id=${request.query.id}&sourceId=${sourceId}`, - }; - } - } - - const spritePath = `${EMS_SPRITES_PATH}/${request.query.id}/sprite`; - - return ok({ - body: { - ...vectorStyle, - glyphs: `${EMS_GLYPHS_PATH}/{fontstack}/{range}`, - sprite: spritePath, - sources: newSources, - }, - }); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_TILES_VECTOR_SOURCE_PATH}`, - validate: { - query: schema.object({ - id: schema.string(), - sourceId: schema.maybe(schema.string()), - elastic_tile_service_tos: schema.maybe(schema.string()), - my_app_name: schema.maybe(schema.string()), - my_app_version: schema.maybe(schema.string()), - license: schema.maybe(schema.string()), - }), - }, - }, - async (context, request, { ok, badRequest }) => { - if (!checkEMSProxyEnabled()) { - return badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.query.id); - if (!tmsService) { - return null; - } - - const vectorStyle = await tmsService.getVectorStyleSheet(); - const sourceManifest = vectorStyle.sources[request.query.sourceId]; - - const newUrl = `${EMS_TILES_VECTOR_TILE_PATH}?id=${request.query.id}&sourceId=${request.query.sourceId}&x={x}&y={y}&z={z}`; - return ok({ - body: { - ...sourceManifest, - tiles: [newUrl], - }, - }); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_TILES_VECTOR_TILE_PATH}`, - validate: { - query: schema.object({ - id: schema.string(), - sourceId: schema.string(), - x: schema.number(), - y: schema.number(), - z: schema.number(), - elastic_tile_service_tos: schema.maybe(schema.string()), - my_app_name: schema.maybe(schema.string()), - my_app_version: schema.maybe(schema.string()), - license: schema.maybe(schema.string()), - }), - }, - }, - async (context, request, response) => { - if (!checkEMSProxyEnabled()) { - return response.badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.query.id); - if (!tmsService) { - return null; - } - - const urlTemplate = await tmsService.getUrlTemplateForVector(request.query.sourceId); - const url = urlTemplate - .replace('{x}', request.query.x) - .replace('{y}', request.query.y) - .replace('{z}', request.query.z); - - return await proxyResource({ url }, response); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_GLYPHS_PATH}/{fontstack}/{range}`, - validate: { - params: schema.object({ - fontstack: schema.string(), - range: schema.string(), - }), - }, - }, - async (context, request, response) => { - if (!checkEMSProxyEnabled()) { - return response.badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - const url = emsSettings - .getEMSFontLibraryUrl() - .replace('{fontstack}', request.params.fontstack) - .replace('{range}', request.params.range); - - return await proxyResource({ url }, response); - } - ); - - router.get( - { - path: `${API_ROOT_PATH}/${EMS_TILES_API_PATH}/${EMS_SPRITES_PATH}/{id}/sprite{scaling?}.{extension}`, - validate: { - query: schema.object({ - elastic_tile_service_tos: schema.maybe(schema.string()), - my_app_name: schema.maybe(schema.string()), - my_app_version: schema.maybe(schema.string()), - license: schema.maybe(schema.string()), - }), - params: schema.object({ - id: schema.string(), - scaling: schema.maybe(schema.string()), - extension: schema.string(), - }), - }, - }, - async (context, request, response) => { - if (!checkEMSProxyEnabled()) { - return response.badRequest('map.proxyElasticMapsServiceInMaps disabled'); - } - - const tmsServices = await getEMSClient().getTMSServices(); - const tmsService = tmsServices.find((layer) => layer.getId() === request.params.id); - if (!tmsService) { - return null; - } - - let proxyPathUrl; - const isRetina = request.params.scaling === '@2x'; - if (request.params.extension === 'json') { - proxyPathUrl = await tmsService.getSpriteSheetJsonPath(isRetina); - } else if (request.params.extension === 'png') { - proxyPathUrl = await tmsService.getSpriteSheetPngPath(isRetina); - } else { - logger.warn(`Must have png or json extension for spritesheet`); - return null; - } - - return await proxyResource( - { - url: proxyPathUrl, - contentType: request.params.extension === 'png' ? 'image/png' : '', - }, - response - ); - } - ); - router.get( { path: `/${FONTS_API_PATH}/{fontstack}/{range}`, @@ -547,36 +88,6 @@ export async function initRoutes(core, getLicenseId, emsSettings, kbnVersion, lo } ); - function checkEMSProxyEnabled() { - const proxyEMSInMaps = emsSettings.isProxyElasticMapsServiceInMaps(); - if (!proxyEMSInMaps) { - logger.warn( - `Cannot load content from EMS when map.proxyElasticMapsServiceInMaps is turned off` - ); - } - return proxyEMSInMaps; - } - - async function proxyResource({ url, contentType }, response) { - try { - const resource = await fetch(url); - const arrayBuffer = await resource.arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - - return response.ok({ - body: buffer, - headers: { - 'content-disposition': 'inline', - 'content-length': buffer.length, - ...(contentType ? { 'Content-type': contentType } : {}), - }, - }); - } catch (e) { - logger.warn(`Cannot connect to EMS for resource, error: ${e.message}`); - return response.badRequest(`Cannot connect to EMS`); - } - } - initMVTRoutes({ router, logger }); initIndexingRoutes({ router, logger, dataPlugin }); } diff --git a/x-pack/plugins/maps/server/saved_objects/map.ts b/x-pack/plugins/maps/server/saved_objects/map.ts index 24effd651a31b..b13f24fc6ba1c 100644 --- a/x-pack/plugins/maps/server/saved_objects/map.ts +++ b/x-pack/plugins/maps/server/saved_objects/map.ts @@ -13,7 +13,8 @@ import { savedObjectMigrations } from './saved_object_migrations'; export const mapSavedObjects: SavedObjectsType = { name: 'map', hidden: false, - namespaceType: 'single', + namespaceType: 'multiple-isolated', + convertToMultiNamespaceTypeVersion: '8.0.0', mappings: { properties: { description: { type: 'text' }, diff --git a/x-pack/plugins/ml/common/constants/locator.ts b/x-pack/plugins/ml/common/constants/locator.ts index fe34557504a08..0441805a6771b 100644 --- a/x-pack/plugins/ml/common/constants/locator.ts +++ b/x-pack/plugins/ml/common/constants/locator.ts @@ -13,7 +13,8 @@ export const ML_PAGES = { SINGLE_METRIC_VIEWER: 'timeseriesexplorer', DATA_FRAME_ANALYTICS_JOBS_MANAGE: 'data_frame_analytics', DATA_FRAME_ANALYTICS_CREATE_JOB: 'data_frame_analytics/new_job', - DATA_FRAME_ANALYTICS_MODELS_MANAGE: 'data_frame_analytics/models', + TRAINED_MODELS_MANAGE: 'trained_models', + TRAINED_MODELS_NODES: 'trained_models/nodes', DATA_FRAME_ANALYTICS_EXPLORATION: 'data_frame_analytics/exploration', DATA_FRAME_ANALYTICS_MAP: 'data_frame_analytics/map', /** diff --git a/x-pack/plugins/ml/common/types/annotations.ts b/x-pack/plugins/ml/common/types/annotations.ts index 6234444322a5b..dbc146c1175d8 100644 --- a/x-pack/plugins/ml/common/types/annotations.ts +++ b/x-pack/plugins/ml/common/types/annotations.ts @@ -118,26 +118,8 @@ export function isAnnotations(arg: any): arg is Annotations { return arg.every((d: Annotation) => isAnnotation(d)); } -export interface FieldToBucket { - field: string; - missing?: string | number; -} - -export interface FieldToBucketResult { - key: string; - doc_count: number; -} - -export interface TermAggregationResult { - doc_count_error_upper_bound: number; - sum_other_doc_count: number; - buckets: FieldToBucketResult[]; -} - -export type EsAggregationResult = Record; - export interface GetAnnotationsResponse { - aggregations?: EsAggregationResult; + totalCount: number; annotations: Record; error?: string; success: boolean; @@ -145,6 +127,5 @@ export interface GetAnnotationsResponse { export interface AnnotationsTable { annotationsData: Annotations; - aggregations: EsAggregationResult; error?: string; } diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts index e1a3f6044587b..ef38504c869fb 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type DatafeedId = string; diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts index 4e23d97c0d145..3c7f8c51785d1 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts @@ -5,6 +5,6 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type DatafeedStats = estypes.MlDatafeedStats; diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts index dcf18b98e00a0..0e32f4e7a065b 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type JobId = string; export type BucketSpan = string; diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts index 5fc8b423a5ac2..995bd1e6a14fc 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type JobStats = estypes.MlJobStats; diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/model_snapshot.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/model_snapshot.ts index 0bb2162994c37..806aca3eb43ad 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/model_snapshot.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/model_snapshot.ts @@ -5,6 +5,6 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type ModelSnapshot = estypes.MlModelSnapshot; diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 306c42301e43a..ed0f3595cb94c 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -96,7 +96,7 @@ export function getPluginPrivileges() { ]; const privilege = { app: [PLUGIN_ID, 'kibana'], - excludeFromBasePrivileges: true, + excludeFromBasePrivileges: false, management: { insightsAndAlerting: ['jobsListLink'], }, diff --git a/x-pack/plugins/ml/common/types/data_frame_analytics.ts b/x-pack/plugins/ml/common/types/data_frame_analytics.ts index 1d2a75069dfe6..92c0c1d06ef93 100644 --- a/x-pack/plugins/ml/common/types/data_frame_analytics.ts +++ b/x-pack/plugins/ml/common/types/data_frame_analytics.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RuntimeMappings } from './fields'; import { EsErrorBody } from '../util/errors'; diff --git a/x-pack/plugins/ml/common/types/es_client.ts b/x-pack/plugins/ml/common/types/es_client.ts index 466075284515e..2a6a1d4c1ffab 100644 --- a/x-pack/plugins/ml/common/types/es_client.ts +++ b/x-pack/plugins/ml/common/types/es_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from '../util/object_utils'; export function isMultiBucketAggregate( diff --git a/x-pack/plugins/ml/common/types/fields.ts b/x-pack/plugins/ml/common/types/fields.ts index 33a4a94e539b8..bf7876570f485 100644 --- a/x-pack/plugins/ml/common/types/fields.ts +++ b/x-pack/plugins/ml/common/types/fields.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ES_FIELD_TYPES } from '../../../../../src/plugins/data/common'; import { ML_JOB_AGGREGATION, diff --git a/x-pack/plugins/ml/common/types/locator.ts b/x-pack/plugins/ml/common/types/locator.ts index 6c1ec2972854e..79db780b791fd 100644 --- a/x-pack/plugins/ml/common/types/locator.ts +++ b/x-pack/plugins/ml/common/types/locator.ts @@ -184,6 +184,10 @@ export interface DataFrameAnalyticsQueryState { globalState?: MlCommonGlobalState; } +export interface TrainedModelsQueryState { + modelId?: string; +} + export type DataFrameAnalyticsUrlState = MLPageState< | typeof ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE | typeof ML_PAGES.DATA_FRAME_ANALYTICS_MAP @@ -250,8 +254,14 @@ export type MlLocatorState = | DataFrameAnalyticsExplorationUrlState | CalendarEditUrlState | FilterEditUrlState - | MlGenericUrlState; + | MlGenericUrlState + | TrainedModelsUrlState; export type MlLocatorParams = MlLocatorState & SerializableRecord; export type MlLocator = LocatorPublic; + +export type TrainedModelsUrlState = MLPageState< + typeof ML_PAGES.TRAINED_MODELS_MANAGE, + TrainedModelsQueryState | undefined +>; diff --git a/x-pack/plugins/ml/common/types/results.ts b/x-pack/plugins/ml/common/types/results.ts index 74d3286438588..f840f9ad58c01 100644 --- a/x-pack/plugins/ml/common/types/results.ts +++ b/x-pack/plugins/ml/common/types/results.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { LineAnnotationDatum, RectAnnotationDatum } from '@elastic/charts'; export interface GetStoppedPartitionResult { diff --git a/x-pack/plugins/ml/common/types/trained_models.ts b/x-pack/plugins/ml/common/types/trained_models.ts index 3c4c3af748645..5ad1d85d9feb9 100644 --- a/x-pack/plugins/ml/common/types/trained_models.ts +++ b/x-pack/plugins/ml/common/types/trained_models.ts @@ -44,6 +44,7 @@ export interface TrainedModelStat { } >; }; + deployment_stats?: Omit; } type TreeNode = object; @@ -95,6 +96,7 @@ export interface TrainedModelConfigResponse { model_aliases?: string[]; } & Record; model_id: string; + model_type: 'tree_ensemble' | 'pytorch' | 'lang_ident'; tags: string[]; version: string; inference_config?: Record; @@ -117,3 +119,82 @@ export interface ModelPipelines { export interface InferenceConfigResponse { trained_model_configs: TrainedModelConfigResponse[]; } + +export interface TrainedModelDeploymentStatsResponse { + model_id: string; + model_size_bytes: number; + inference_threads: number; + model_threads: number; + state: string; + allocation_status: { target_allocation_count: number; state: string; allocation_count: number }; + nodes: Array<{ + node: Record< + string, + { + transport_address: string; + roles: string[]; + name: string; + attributes: { + 'ml.machine_memory': string; + 'xpack.installed': string; + 'ml.max_open_jobs': string; + 'ml.max_jvm_size': string; + }; + ephemeral_id: string; + } + >; + inference_count: number; + routing_state: { routing_state: string }; + average_inference_time_ms: number; + last_access: number; + }>; +} + +export interface NodeDeploymentStatsResponse { + id: string; + name: string; + transport_address: string; + attributes: Record; + roles: string[]; + allocated_models: Array<{ + inference_threads: number; + allocation_status: { + target_allocation_count: number; + state: string; + allocation_count: number; + }; + model_id: string; + state: string; + model_threads: number; + model_size_bytes: number; + }>; + memory_overview: { + machine_memory: { + /** Total machine memory in bytes */ + total: number; + jvm: number; + }; + /** Open anomaly detection jobs + hardcoded overhead */ + anomaly_detection: { + /** Total size in bytes */ + total: number; + }; + /** DFA jobs currently in training + hardcoded overhead */ + dfa_training: { + total: number; + }; + /** Allocated trained models */ + trained_models: { + total: number; + by_model: Array<{ + model_id: string; + model_size: number; + }>; + }; + }; +} + +export interface NodesOverviewResponse { + count: number; + nodes: NodeDeploymentStatsResponse[]; +} diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts index 6d069cd4383ea..e66d8de5bd15e 100644 --- a/x-pack/plugins/ml/common/util/job_utils.ts +++ b/x-pack/plugins/ml/common/util/job_utils.ts @@ -8,7 +8,7 @@ import { each, isEmpty, isEqual, pick } from 'lodash'; import semverGte from 'semver/functions/gte'; import moment, { Duration } from 'moment'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // @ts-ignore import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/ml/common/util/runtime_field_utils.ts b/x-pack/plugins/ml/common/util/runtime_field_utils.ts index 1fcf8e2e72b15..edda547d363e4 100644 --- a/x-pack/plugins/ml/common/util/runtime_field_utils.ts +++ b/x-pack/plugins/ml/common/util/runtime_field_utils.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from './object_utils'; import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common'; import type { RuntimeMappings } from '../types/fields'; diff --git a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx index 794f4b3b164e9..2be57ddf95431 100644 --- a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx +++ b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx @@ -88,7 +88,7 @@ const MlAnomalyAlertTrigger: FC = ({ const availableResultTypes = useMemo(() => { if (jobConfigs.length === 0) return Object.values(ANOMALY_RESULT_TYPE); - return (jobConfigs ?? []).some((v) => v.analysis_config.influencers.length > 0) + return (jobConfigs ?? []).some((v) => Boolean(v.analysis_config?.influencers?.length)) ? Object.values(ANOMALY_RESULT_TYPE) : [ANOMALY_RESULT_TYPE.BUCKET, ANOMALY_RESULT_TYPE.RECORD]; }, [jobConfigs]); diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 6259cecae78b5..1df0a7afe475b 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -27,7 +27,11 @@ import { MlRouter } from './routing'; import { mlApiServicesProvider } from './services/ml_api_service'; import { HttpService } from './services/http_service'; import { ML_APP_LOCATOR, ML_PAGES } from '../../common/constants/locator'; -export type MlDependencies = Omit & + +export type MlDependencies = Omit< + MlSetupDependencies, + 'share' | 'indexPatternManagement' | 'fieldFormats' +> & MlStartDependencies; interface AppProps { @@ -84,6 +88,7 @@ const App: FC = ({ coreStart, deps, appMountParams }) => { triggersActionsUi: deps.triggersActionsUi, dataVisualizer: deps.dataVisualizer, usageCollection: deps.usageCollection, + fieldFormats: deps.fieldFormats, ...coreStart, }; diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js index 26fddcc6394b0..98dc5f4204c32 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js +++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js @@ -81,7 +81,6 @@ class AnnotationsTableUI extends Component { super(props); this.state = { annotations: [], - aggregations: null, isLoading: false, queryText: `event:(${ANNOTATION_EVENT_USER} or ${ANNOTATION_EVENT_DELAYED_DATA})`, searchError: undefined, @@ -115,18 +114,11 @@ class AnnotationsTableUI extends Component { earliestMs: null, latestMs: null, maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE, - fields: [ - { - field: 'event', - missing: ANNOTATION_EVENT_USER, - }, - ], }) .toPromise() .then((resp) => { this.setState((prevState, props) => ({ annotations: resp.annotations[props.jobs[0].job_id] || [], - aggregations: resp.aggregations, errorMessage: undefined, isLoading: false, jobId: props.jobs[0].job_id, @@ -570,41 +562,35 @@ class AnnotationsTableUI extends Component { onMouseLeave: () => this.onMouseLeaveRow(), }; }; - let filterOptions = []; - const aggregations = this.props.aggregations ?? this.state.aggregations; - if (aggregations) { - const buckets = aggregations.event.buckets; - let foundUser = false; - let foundDelayedData = false; - - buckets.forEach((bucket) => { - if (bucket.key === ANNOTATION_EVENT_USER) { - foundUser = true; - } - if (bucket.key === ANNOTATION_EVENT_DELAYED_DATA) { - foundDelayedData = true; - } - }); - const adjustedBuckets = []; - if (!foundUser) { - adjustedBuckets.push({ key: ANNOTATION_EVENT_USER, doc_count: 0 }); - } - if (!foundDelayedData) { - adjustedBuckets.push({ key: ANNOTATION_EVENT_DELAYED_DATA, doc_count: 0 }); + + // Build the options to show in the Event type filter. + // Do not try and run a search using a terms agg on the event field + // because in 7.9 this field was incorrectly mapped as a text rather than keyword. + + // Always display options for user and delayed data types. + const countsByEvent = { + [ANNOTATION_EVENT_USER]: 0, + [ANNOTATION_EVENT_DELAYED_DATA]: 0, + }; + annotations.forEach((annotation) => { + // Default to user type for annotations created in early releases which didn't have an event field + const event = annotation.event ?? ANNOTATION_EVENT_USER; + if (countsByEvent[event] === undefined) { + countsByEvent[event] = 0; } + countsByEvent[event]++; + }); - filterOptions = [...adjustedBuckets, ...buckets]; - } const filters = [ { type: 'field_value_selection', field: 'event', name: 'Event', multiSelect: 'or', - options: filterOptions.map((field) => ({ - value: field.key, - name: field.key, - view: `${field.key} (${field.doc_count})`, + options: Object.entries(countsByEvent).map(([key, docCount]) => ({ + value: key, + name: key, + view: `${key} (${docCount})`, })), 'data-test-subj': 'mlAnnotationTableEventFilter', }, diff --git a/x-pack/plugins/ml/public/application/components/data_grid/common.ts b/x-pack/plugins/ml/public/application/components/data_grid/common.ts index 6fc6f298e73d8..fc6a20e9d4cda 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/common.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/common.ts @@ -6,7 +6,7 @@ */ import moment from 'moment-timezone'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useEffect, useMemo } from 'react'; import { diff --git a/x-pack/plugins/ml/public/application/components/data_grid/types.ts b/x-pack/plugins/ml/public/application/components/data_grid/types.ts index 47684ee307e99..01c135000fb0e 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/types.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/types.ts @@ -7,7 +7,7 @@ import { Dispatch, SetStateAction } from 'react'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiDataGridCellValueElementProps, EuiDataGridPaginationProps, diff --git a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node_shared/new_job_awaiting_node_shared.tsx b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node_shared/new_job_awaiting_node_shared.tsx index 5850349ff5fd6..d4ce935cc085f 100644 --- a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node_shared/new_job_awaiting_node_shared.tsx +++ b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node_shared/new_job_awaiting_node_shared.tsx @@ -6,7 +6,7 @@ */ import React, { FC, useState, useEffect, useCallback, useMemo } from 'react'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiCallOut, EuiSpacer, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; diff --git a/x-pack/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx b/x-pack/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx index 44f00477ab027..78fc10e77b2da 100644 --- a/x-pack/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx +++ b/x-pack/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx @@ -7,7 +7,7 @@ import React, { FC, useState, useEffect } from 'react'; -import { EuiPageHeader } from '@elastic/eui'; +import { EuiPageHeader, EuiBetaBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TabId } from './navigation_menu'; import { useMlKibana, useMlLocator, useNavigateToPath } from '../../contexts/kibana'; @@ -20,6 +20,7 @@ export interface Tab { id: TabId; name: any; disabled: boolean; + betaTag?: JSX.Element; } interface Props { @@ -50,6 +51,27 @@ function getTabs(disableLinks: boolean): Tab[] { }), disabled: disableLinks, }, + { + id: 'trained_models', + name: i18n.translate('xpack.ml.navMenu.trainedModelsTabLinkText', { + defaultMessage: 'Model Management', + }), + disabled: disableLinks, + betaTag: ( + + ), + }, { id: 'datavisualizer', name: i18n.translate('xpack.ml.navMenu.dataVisualizerTabLinkText', { @@ -93,6 +115,12 @@ const TAB_DATA: Record = { defaultMessage: 'Data Frame Analytics', }), }, + trained_models: { + testSubject: 'mlMainTab modelManagement', + name: i18n.translate('xpack.ml.trainedModelsTabLabel', { + defaultMessage: 'Trained Models', + }), + }, datavisualizer: { testSubject: 'mlMainTab dataVisualizer', name: i18n.translate('xpack.ml.dataVisualizerTabLabel', { @@ -173,6 +201,7 @@ export const MainTabs: FC = ({ tabId, disableLinks }) => { }, 'data-test-subj': testSubject + (id === selectedTabId ? ' selected' : ''), isSelected: id === selectedTabId, + append: tab.betaTag, }; })} /> diff --git a/x-pack/plugins/ml/public/application/components/navigation_menu/navigation_menu.tsx b/x-pack/plugins/ml/public/application/components/navigation_menu/navigation_menu.tsx index 986a88d789b36..2df9259226ce2 100644 --- a/x-pack/plugins/ml/public/application/components/navigation_menu/navigation_menu.tsx +++ b/x-pack/plugins/ml/public/application/components/navigation_menu/navigation_menu.tsx @@ -15,6 +15,7 @@ export type TabId = | 'access-denied' | 'anomaly_detection' | 'data_frame_analytics' + | 'trained_models' | 'datavisualizer' | 'overview' | 'settings'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx index d64a180bfa8b6..ecaf3515e1634 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx @@ -7,7 +7,7 @@ import React, { useMemo, useEffect, useState, FC } from 'react'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiCallOut, diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts index 7291f7bbfa838..861b3727cea1b 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts @@ -107,6 +107,11 @@ export const getScatterplotMatrixVegaLiteSpec = ( labelColor: euiTheme.euiTextSubduedColor, titleColor: euiTheme.euiTextSubduedColor, }, + legend: { + orient: 'right', + labelColor: euiTheme.euiTextSubduedColor, + titleColor: euiTheme.euiTextSubduedColor, + }, }, repeat: { column: vegaColumns, diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index e69d75a24d423..10c00098d82d5 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -21,6 +21,7 @@ import type { EmbeddableStart } from '../../../../../../../src/plugins/embeddabl import type { MapsStartApi } from '../../../../../maps/public'; import type { DataVisualizerPluginStart } from '../../../../../data_visualizer/public'; import type { TriggersAndActionsUIPublicPluginStart } from '../../../../../triggers_actions_ui/public'; +import type { FieldFormatsRegistry } from '../../../../../../../src/plugins/field_formats/common'; interface StartPlugins { data: DataPublicPluginStart; @@ -32,6 +33,7 @@ interface StartPlugins { triggersActionsUi?: TriggersAndActionsUIPublicPluginStart; dataVisualizer?: DataVisualizerPluginStart; usageCollection?: UsageCollectionSetup; + fieldFormats: FieldFormatsRegistry; } export type StartServices = CoreStart & StartPlugins & { diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/use_field_formatter.ts b/x-pack/plugins/ml/public/application/contexts/kibana/use_field_formatter.ts new file mode 100644 index 0000000000000..508ce66f40f47 --- /dev/null +++ b/x-pack/plugins/ml/public/application/contexts/kibana/use_field_formatter.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMlKibana } from './kibana_context'; + +export function useFieldFormatter(fieldType: 'bytes') { + const { + services: { fieldFormats }, + } = useMlKibana(); + + const fieldFormatter = fieldFormats.deserialize({ id: fieldType }); + return fieldFormatter.convert.bind(fieldFormatter); +} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_index_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_index_data.ts index 920f56b376747..eda63ec4285ea 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_index_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_index_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { extractErrorMessage } from '../../../../common/util/errors'; import { EsSorting, UseDataGridReturnType, getProcessedFields } from '../../components/data_grid'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx index 9b29d9108a1a1..df42c5b8eb1ca 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx @@ -127,6 +127,7 @@ export const ConfigurationStepForm: FC = ({ dependentVariable, includes, jobConfigQuery, + jobConfigQueryLanguage, jobConfigQueryString, jobType, modelMemoryLimit, @@ -150,14 +151,18 @@ export const ConfigurationStepForm: FC = ({ const [query, setQuery] = useState({ query: jobConfigQueryString ?? '', - language: SEARCH_QUERY_LANGUAGE.KUERY, + language: jobConfigQueryLanguage ?? SEARCH_QUERY_LANGUAGE.KUERY, }); const toastNotifications = getToastNotifications(); const setJobConfigQuery: ExplorationQueryBarProps['setSearchQuery'] = (update) => { if (update.query) { - setFormState({ jobConfigQuery: update.query, jobConfigQueryString: update.queryString }); + setFormState({ + jobConfigQuery: update.query, + jobConfigQueryLanguage: update.language, + jobConfigQueryString: update.queryString, + }); } setQuery({ query: update.queryString, language: update.language }); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/form_options_validation.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/form_options_validation.ts index 72853ec23fd36..1fe649ee9519a 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/form_options_validation.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/form_options_validation.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; import { EVENT_RATE_FIELD_ID } from '../../../../../../../common/types/fields'; import { ANALYSIS_CONFIG_TYPE } from '../../../../common/analytics'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/use_saved_search.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/use_saved_search.ts index 41973b5ec2d01..ad23c018afbbb 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/use_saved_search.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/use_saved_search.ts @@ -12,7 +12,7 @@ import { luceneStringToDsl, toElasticsearchQuery, } from '@kbn/es-query'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useMlContext } from '../../../../../contexts/ml'; import { SEARCH_QUERY_LANGUAGE } from '../../../../../../../common/constants/search'; import { getQueryFromSavedSearchObject } from '../../../../../util/index_utils'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts index f3779e1968985..69f66832af3c7 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts @@ -7,7 +7,7 @@ import { useEffect, useMemo, useState } from 'react'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiDataGridColumn } from '@elastic/eui'; import { CoreSetup } from 'src/core/public'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx index fb103886635a9..00a63bcf2a414 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -26,6 +26,7 @@ import { useMlKibana } from '../../../../../contexts/kibana'; // Separate imports for lazy loadable VegaChart and related code import { VegaChart } from '../../../../../components/vega_chart'; import { VegaChartLoading } from '../../../../../components/vega_chart/vega_chart_loading'; +import { useCurrentEuiTheme } from '../../../../../components/color_range_legend'; import { ErrorCallout } from '../error_callout'; import { getDependentVar, DataFrameAnalyticsConfig } from '../../../../common'; @@ -33,6 +34,7 @@ import { DataFrameTaskStateType } from '../../../analytics_management/components import { ResultsSearchQuery } from '../../../../common/analytics'; import { ExpandableSection, HEADER_ITEMS_LOADING } from '../expandable_section'; + import { EvaluateStat } from './evaluate_stat'; import { EvaluationQualityMetricsTable } from './evaluation_quality_metrics_table'; @@ -107,6 +109,7 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, se const { services: { docLinks }, } = useMlKibana(); + const { euiTheme } = useCurrentEuiTheme(); const [columns, setColumns] = useState([]); const [columnsData, setColumnsData] = useState([]); @@ -469,7 +472,8 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, se vegaSpec={getRocCurveChartVegaLiteSpec( classificationClasses, rocCurveData, - getDependentVar(jobConfig.analysis) + getDependentVar(jobConfig.analysis), + euiTheme )} />
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx index e9a6925476b02..ef5bcb83e871f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx @@ -10,6 +10,7 @@ import type { TopLevelSpec } from 'vega-lite/build/vega-lite'; import { euiPaletteColorBlind, euiPaletteGray } from '@elastic/eui'; +import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; @@ -43,7 +44,8 @@ export interface RocCurveDataRow extends RocCurveItem { export const getRocCurveChartVegaLiteSpec = ( classificationClasses: string[], data: RocCurveDataRow[], - legendTitle: string + legendTitle: string, + euiTheme: typeof euiThemeLight ): TopLevelSpec => { // we append two rows which make up the data for the diagonal baseline data.push({ tpr: 0, fpr: 0, threshold: 1, class_name: BASELINE }); @@ -59,6 +61,8 @@ export const getRocCurveChartVegaLiteSpec = ( config: { legend: { orient: 'right', + labelColor: euiTheme.euiTextSubduedColor, + titleColor: euiTheme.euiTextSubduedColor, }, view: { continuousHeight: SIZE, @@ -101,9 +105,9 @@ export const getRocCurveChartVegaLiteSpec = ( type: 'quantitative', axis: { tickColor: GRAY, - labelColor: GRAY, + labelColor: euiTheme.euiTextSubduedColor, domainColor: GRAY, - titleColor: GRAY, + titleColor: euiTheme.euiTextSubduedColor, }, }, y: { @@ -114,9 +118,9 @@ export const getRocCurveChartVegaLiteSpec = ( type: 'quantitative', axis: { tickColor: GRAY, - labelColor: GRAY, + labelColor: euiTheme.euiTextSubduedColor, domainColor: GRAY, - titleColor: GRAY, + titleColor: euiTheme.euiTextSubduedColor, }, }, tooltip: [ diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx index 3639836c6be01..27eb06d7ecd41 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { debounce } from 'lodash'; import { fromKueryExpression, luceneStringToDsl, toElasticsearchQuery } from '@kbn/es-query'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Dictionary } from '../../../../../../../common/types/common'; import { DataView } from '../../../../../../../../../../src/plugins/data_views/common'; import { Query, QueryStringInput } from '../../../../../../../../../../src/plugins/data/public'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_navigation_bar/analytics_navigation_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_navigation_bar/analytics_navigation_bar.tsx index d26b5d5cfc16f..53fe22208ec94 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_navigation_bar/analytics_navigation_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_navigation_bar/analytics_navigation_bar.tsx @@ -33,14 +33,6 @@ export const AnalyticsNavigationBar: FC<{ path: '/data_frame_analytics', testSubj: 'mlAnalyticsJobsTab', }, - { - id: 'models', - name: i18n.translate('xpack.ml.dataframe.modelsTabLabel', { - defaultMessage: 'Models', - }), - path: '/data_frame_analytics/models', - testSubj: 'mlTrainedModelsTab', - }, ]; if (jobId !== undefined || modelId !== undefined) { navTabs.push({ diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts index e7a263520af31..0b2cb8fcfc716 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts @@ -79,6 +79,7 @@ export interface State { jobType: AnalyticsJobType; jobConfigQuery: any; jobConfigQueryString: string | undefined; + jobConfigQueryLanguage: string | undefined; lambda: number | undefined; lossFunction: string | undefined; lossFunctionParameter: number | undefined; @@ -162,6 +163,7 @@ export const getInitialState = (): State => ({ jobType: undefined, jobConfigQuery: defaultSearchQuery, jobConfigQueryString: undefined, + jobConfigQueryLanguage: undefined, lambda: undefined, lossFunction: undefined, lossFunctionParameter: undefined, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx index dedbddcab4f52..1f0e0bf0aad8d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx @@ -31,7 +31,6 @@ import { NodeAvailableWarning } from '../../../components/node_available_warning import { SavedObjectsWarning } from '../../../components/saved_objects_warning'; import { UpgradeWarning } from '../../../components/upgrade'; import { AnalyticsNavigationBar } from './components/analytics_navigation_bar'; -import { ModelsList } from './components/models_management'; import { JobMap } from '../job_map'; import { usePageUrlState } from '../../../util/url_state'; import { ListingPageUrlState } from '../../../../../common/types/common'; @@ -125,7 +124,6 @@ export const Page: FC = () => { updatePageState={setDfaPageState} /> )} - {selectedTabId === 'models' && } diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index daecf7585b3ea..7d08c0fc1756e 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -255,13 +255,9 @@ export class ExplorerUI extends React.Component { tableData, swimLaneSeverity, } = this.props.explorerState; - const { annotationsData, aggregations, error: annotationsError } = annotations; + const { annotationsData, totalCount: allAnnotationsCnt, error: annotationsError } = annotations; const annotationsCnt = Array.isArray(annotationsData) ? annotationsData.length : 0; - const allAnnotationsCnt = Array.isArray(aggregations?.event?.buckets) - ? aggregations.event.buckets.reduce((acc, v) => acc + v.doc_count, 0) - : annotationsCnt; - const badge = allAnnotationsCnt > annotationsCnt ? ( @@ -449,7 +445,6 @@ export class ExplorerUI extends React.Component { diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_utils.js b/x-pack/plugins/ml/public/application/explorer/explorer_utils.js index ecf347e6b142f..af2b9b07a43fb 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_utils.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_utils.js @@ -35,7 +35,6 @@ import { SWIMLANE_TYPE, VIEW_BY_JOB_LABEL, } from './explorer_constants'; -import { ANNOTATION_EVENT_USER } from '../../../common/constants/annotations'; // create new job objects based on standard job config objects // new job objects just contain job id, bucket span in seconds and a selected flag. @@ -437,10 +436,7 @@ export function loadOverallAnnotations(selectedJobs, interval, bounds) { } export function loadAnnotationsTableData(selectedCells, selectedJobs, interval, bounds) { - const jobIds = - selectedCells !== undefined && selectedCells.viewByFieldName === VIEW_BY_JOB_LABEL - ? selectedCells.lanes - : selectedJobs.map((d) => d.id); + const jobIds = getSelectionJobIds(selectedCells, selectedJobs); const timeRange = getSelectionTimeRange(selectedCells, interval, bounds); return new Promise((resolve) => { @@ -450,12 +446,6 @@ export function loadAnnotationsTableData(selectedCells, selectedJobs, interval, earliestMs: timeRange.earliestMs, latestMs: timeRange.latestMs, maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE, - fields: [ - { - field: 'event', - missing: ANNOTATION_EVENT_USER, - }, - ], }) .toPromise() .then((resp) => { @@ -463,7 +453,7 @@ export function loadAnnotationsTableData(selectedCells, selectedJobs, interval, const errorMessage = extractErrorMessage(resp.error); return resolve({ annotationsData: [], - aggregations: {}, + totalCount: 0, error: errorMessage !== '' ? errorMessage : undefined, }); } @@ -485,14 +475,14 @@ export function loadAnnotationsTableData(selectedCells, selectedJobs, interval, d.key = (i + 1).toString(); return d; }), - aggregations: resp.aggregations, + totalCount: resp.totalCount, }); }) .catch((resp) => { const errorMessage = extractErrorMessage(resp); return resolve({ annotationsData: [], - aggregations: {}, + totalCount: 0, error: errorMessage !== '' ? errorMessage : undefined, }); }); diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts index 202a4389ef524..cfc9f076fbb3a 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts @@ -71,12 +71,10 @@ export function getExplorerDefaultState(): ExplorerState { overallAnnotations: { error: undefined, annotationsData: [], - aggregations: {}, }, annotations: { error: undefined, annotationsData: [], - aggregations: {}, }, anomalyChartsDataLoading: true, chartsData: getDefaultChartsData(), diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts index 3d8c34e0e5967..fd1df5395ff84 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { JobCreator } from './job_creator'; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts index 607a4fcf9a73c..79bf2f64ca95d 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts @@ -83,7 +83,7 @@ export class JobCreator { this._calendars = []; this._datafeed_config = createEmptyDatafeed(this._indexPatternTitle); this._detectors = this._job_config.analysis_config.detectors; - this._influencers = this._job_config.analysis_config.influencers; + this._influencers = this._job_config.analysis_config.influencers!; if (typeof indexPattern.timeFieldName === 'string') { this._job_config.data_description.time_field = indexPattern.timeFieldName; @@ -766,7 +766,7 @@ export class JobCreator { this._datafeed_config = datafeed; this._detectors = this._job_config.analysis_config.detectors; - this._influencers = this._job_config.analysis_config.influencers; + this._influencers = this._job_config.analysis_config.influencers!; if (this._job_config.groups === undefined) { this._job_config.groups = []; } diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx index f156233dfde85..f6317bcc41e54 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import React, { FC, Fragment, useState, useContext, useEffect } from 'react'; import { EuiComboBox, diff --git a/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts b/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts index 29412979e1827..ad11c879b2918 100644 --- a/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts +++ b/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts @@ -41,6 +41,13 @@ export const DATA_FRAME_ANALYTICS_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ href: '/data_frame_analytics', }); +export const TRAINED_MODELS: ChromeBreadcrumb = Object.freeze({ + text: i18n.translate('xpack.ml.trainedModelsLabel', { + defaultMessage: 'Trained Models', + }), + href: '/trained_models', +}); + export const DATA_VISUALIZER_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ text: i18n.translate('xpack.ml.datavisualizerBreadcrumbLabel', { defaultMessage: 'Data Visualizer', @@ -74,6 +81,7 @@ const breadcrumbs = { SETTINGS_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, DATA_FRAME_ANALYTICS_BREADCRUMB, + TRAINED_MODELS, DATA_VISUALIZER_BREADCRUMB, CREATE_JOB_BREADCRUMB, CALENDAR_MANAGEMENT_BREADCRUMB, diff --git a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts index 16e9a2fe0c9ce..52b4ca3213f8c 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts +++ b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts @@ -8,5 +8,4 @@ export * from './analytics_jobs_list'; export * from './analytics_job_exploration'; export * from './analytics_job_creation'; -export * from './models_list'; export * from './analytics_map'; diff --git a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx index b9e866d2e00d0..04543a28ab3e6 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx @@ -19,10 +19,7 @@ import { IndexDataVisualizerPage as Page } from '../../../datavisualizer/index_b import { checkBasicLicense } from '../../../license'; import { checkGetJobsCapabilitiesResolver } from '../../../capabilities/check_capabilities'; import { loadIndexPatterns } from '../../../util/index_utils'; -import { checkMlNodesAvailable } from '../../../ml_nodes_check'; import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; -import { ML_PAGES } from '../../../../../common/constants/locator'; -import { useCreateAndNavigateToMlLink } from '../../../contexts/kibana/use_create_url'; export const indexBasedRouteFactory = ( navigateToPath: NavigateToPath, @@ -44,16 +41,12 @@ export const indexBasedRouteFactory = ( const PageWrapper: FC = ({ location, deps }) => { const { redirectToMlAccessDeniedPage } = deps; - const redirectToJobsManagementPage = useCreateAndNavigateToMlLink( - ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE - ); const { index, savedSearchId }: Record = parse(location.search, { sort: false }); const { context } = useResolver(index, savedSearchId, deps.config, { checkBasicLicense, loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage), - checkMlNodesAvailable: () => checkMlNodesAvailable(redirectToJobsManagementPage), }); return ( diff --git a/x-pack/plugins/ml/public/application/routing/routes/index.ts b/x-pack/plugins/ml/public/application/routing/routes/index.ts index a01d5405f3001..31a8d863e3086 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/index.ts +++ b/x-pack/plugins/ml/public/application/routing/routes/index.ts @@ -14,3 +14,4 @@ export * from './data_frame_analytics'; export { timeSeriesExplorerRouteFactory } from './timeseriesexplorer'; export * from './explorer'; export * from './access_denied'; +export * from './trained_models'; diff --git a/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx b/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx index 8500d85d5580a..53057cb16c132 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx @@ -19,9 +19,6 @@ import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; import { checkBasicLicense } from '../../../license'; import { loadIndexPatterns } from '../../../util/index_utils'; import { checkGetJobsCapabilitiesResolver } from '../../../capabilities/check_capabilities'; -import { checkMlNodesAvailable } from '../../../ml_nodes_check'; -import { ML_PAGES } from '../../../../../common/constants/locator'; -import { useCreateAndNavigateToMlLink } from '../../../contexts/kibana/use_create_url'; enum MODE { NEW_JOB, @@ -85,9 +82,6 @@ const PageWrapper: FC = ({ nextStepPath, deps, mode }) = } = useMlKibana(); const { redirectToMlAccessDeniedPage } = deps; - const redirectToJobsManagementPage = useCreateAndNavigateToMlLink( - ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE - ); const newJobResolvers = { ...basicResolvers(deps), @@ -98,7 +92,6 @@ const PageWrapper: FC = ({ nextStepPath, deps, mode }) = checkBasicLicense, loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage), - checkMlNodesAvailable: () => checkMlNodesAvailable(redirectToJobsManagementPage), }; const { context } = useResolver( diff --git a/x-pack/plugins/ml/public/application/routing/routes/trained_models/index.ts b/x-pack/plugins/ml/public/application/routing/routes/trained_models/index.ts new file mode 100644 index 0000000000000..53b9ffd0ee87e --- /dev/null +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './models_list'; +export * from './nodes_list'; diff --git a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/models_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx similarity index 80% rename from x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/models_list.tsx rename to x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx index a1aca430c9283..9367a58372484 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/models_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx @@ -13,20 +13,20 @@ import { NavigateToPath } from '../../../contexts/kibana'; import { MlRoute, PageLoader, PageProps } from '../../router'; import { useResolver } from '../../use_resolver'; import { basicResolvers } from '../../resolvers'; -import { Page } from '../../../data_frame_analytics/pages/analytics_management'; import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; +import { Page } from '../../../trained_models'; export const modelsListRouteFactory = ( navigateToPath: NavigateToPath, basePath: string ): MlRoute => ({ - path: '/data_frame_analytics/models', + path: '/trained_models', render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('DATA_FRAME_ANALYTICS_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('TRAINED_MODELS', navigateToPath, basePath), { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.modelsListLabel', { + text: i18n.translate('xpack.ml.trainedModelsBreadcrumbs.modelsListLabel', { defaultMessage: 'Model Management', }), href: '', diff --git a/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx new file mode 100644 index 0000000000000..bd88527af1a8d --- /dev/null +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { NavigateToPath } from '../../../contexts/kibana'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; +import { Page } from '../../../trained_models'; + +export const nodesListRouteFactory = ( + navigateToPath: NavigateToPath, + basePath: string +): MlRoute => ({ + path: '/trained_models/nodes', + render: (props, deps) => , + breadcrumbs: [ + getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('TRAINED_MODELS', navigateToPath, basePath), + { + text: i18n.translate('xpack.ml.trainedModelsBreadcrumbs.nodesListLabel', { + defaultMessage: 'Nodes Overview', + }), + href: '', + }, + ], +}); + +const PageWrapper: FC = ({ location, deps }) => { + const { context } = useResolver(undefined, undefined, deps.config, basicResolvers(deps)); + return ( + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/services/anomaly_detector_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_detector_service.ts index eacfd826868ac..1601a5d6cceea 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_detector_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_detector_service.ts @@ -50,7 +50,7 @@ export class AnomalyDetectorService { } const influencers = new Set(); for (const job of jobs) { - for (const influencer of job.analysis_config.influencers) { + for (const influencer of job.analysis_config.influencers || []) { influencers.add(influencer); } } diff --git a/x-pack/plugins/ml/public/application/services/job_service.d.ts b/x-pack/plugins/ml/public/application/services/job_service.d.ts index 667f23da34aa0..b6575c48b21f2 100644 --- a/x-pack/plugins/ml/public/application/services/job_service.d.ts +++ b/x-pack/plugins/ml/public/application/services/job_service.d.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { TimeRange } from 'src/plugins/data/common/query/timefilter/types'; import { CombinedJob, Datafeed, Job } from '../../../common/types/anomaly_detection_jobs'; diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/annotations.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/annotations.ts index f3f9e935a92c7..006b70934c71e 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/annotations.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/annotations.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - Annotation, - FieldToBucket, - GetAnnotationsResponse, -} from '../../../../common/types/annotations'; +import { Annotation, GetAnnotationsResponse } from '../../../../common/types/annotations'; import { http, http$ } from '../http_service'; import { basePath } from './index'; @@ -19,7 +15,6 @@ export const annotations = { earliestMs: number; latestMs: number; maxAnnotations: number; - fields?: FieldToBucket[]; detectorIndex?: number; entities?: any[]; }) { @@ -36,7 +31,6 @@ export const annotations = { earliestMs: number | null; latestMs: number | null; maxAnnotations: number; - fields?: FieldToBucket[]; detectorIndex?: number; entities?: any[]; }) { diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index 29c2cd8a2408c..854d4b8014b09 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Observable } from 'rxjs'; import type { HttpStart } from 'kibana/public'; import { HttpService } from '../http_service'; diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts index fe2b76c768cba..c483b0a23c2d0 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts @@ -14,6 +14,8 @@ import { TrainedModelConfigResponse, ModelPipelines, TrainedModelStat, + NodesOverviewResponse, + TrainedModelDeploymentStatsResponse, } from '../../../../common/types/trained_models'; export interface InferenceQueryParams { @@ -114,11 +116,47 @@ export function trainedModelsApiProvider(httpService: HttpService) { * @param modelId - Model ID */ deleteTrainedModel(modelId: string) { - return httpService.http({ + return httpService.http<{ acknowledge: boolean }>({ path: `${apiBasePath}/trained_models/${modelId}`, method: 'DELETE', }); }, + + getTrainedModelDeploymentStats(modelId?: string | string[]) { + let model = modelId ?? '*'; + if (Array.isArray(modelId)) { + model = modelId.join(','); + } + + return httpService.http<{ + count: number; + deployment_stats: TrainedModelDeploymentStatsResponse[]; + }>({ + path: `${apiBasePath}/trained_models/${model}/deployment/_stats`, + method: 'GET', + }); + }, + + getTrainedModelsNodesOverview() { + return httpService.http({ + path: `${apiBasePath}/trained_models/nodes_overview`, + method: 'GET', + }); + }, + + startModelAllocation(modelId: string) { + return httpService.http<{ acknowledge: boolean }>({ + path: `${apiBasePath}/trained_models/${modelId}/deployment/_start`, + method: 'POST', + }); + }, + + stopModelAllocation(modelId: string) { + return httpService.http<{ acknowledge: boolean }>({ + path: `${apiBasePath}/trained_models/${modelId}/deployment/_stop`, + method: 'POST', + }); + }, }; } diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx index 85530de2ea718..174ab8a682b5b 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx @@ -15,7 +15,6 @@ import { extractErrorMessage } from '../../../../../common/util/errors'; import { Annotation } from '../../../../../common/types/annotations'; import { useMlKibana, useNotifications } from '../../../contexts/kibana'; import { getBoundsRoundedToInterval } from '../../../util/time_buckets'; -import { ANNOTATION_EVENT_USER } from '../../../../../common/constants/annotations'; import { getControlsForDetector } from '../../get_controls_for_detector'; import { MlAnnotationUpdatesContext } from '../../../contexts/ml/ml_annotation_updates_context'; @@ -88,12 +87,6 @@ export const TimeSeriesChartWithTooltips: FC = earliestMs: searchBounds.min.valueOf(), latestMs: searchBounds.max.valueOf(), maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE, - fields: [ - { - field: 'event', - missing: ANNOTATION_EVENT_USER, - }, - ], detectorIndex, entities: nonBlankEntities, }); diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 454bb0b489837..9b8770350909e 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -104,7 +104,6 @@ function getTimeseriesexplorerDefaultState() { entitiesLoading: false, entityValues: {}, focusAnnotationData: [], - focusAggregations: {}, focusAggregationInterval: {}, focusChartData: undefined, focusForecastData: undefined, @@ -935,7 +934,6 @@ export class TimeSeriesExplorer extends React.Component { focusAggregationInterval, focusAnnotationError, focusAnnotationData, - focusAggregations, focusChartData, focusForecastData, fullRefresh, @@ -1257,7 +1255,6 @@ export class TimeSeriesExplorer extends React.Component { detectors={detectors} jobIds={[this.props.selectedJobId]} annotations={focusAnnotationData} - aggregations={focusAggregations} isSingleMetricViewerLinkVisible={false} isNumberBadgeVisible={true} /> diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts index cb1974afd5ed8..d4548a43f3f2b 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts @@ -26,7 +26,6 @@ import { import { mlForecastService } from '../../services/forecast_service'; import { mlFunctionToESAggregation } from '../../../../common/util/job_utils'; import { GetAnnotationsResponse } from '../../../../common/types/annotations'; -import { ANNOTATION_EVENT_USER } from '../../../../common/constants/annotations'; import { aggregationTypeTransform } from '../../../../common/util/anomaly_utils'; export interface Interval { @@ -42,7 +41,6 @@ export interface FocusData { focusAnnotationError?: string; focusAnnotationData?: any[]; focusForecastData?: any; - focusAggregations?: any; } export function getFocusData( @@ -98,12 +96,6 @@ export function getFocusData( earliestMs: searchBounds.min.valueOf(), latestMs: searchBounds.max.valueOf(), maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE, - fields: [ - { - field: 'event', - missing: ANNOTATION_EVENT_USER, - }, - ], detectorIndex, entities: nonBlankEntities, }) @@ -111,7 +103,7 @@ export function getFocusData( catchError((resp) => of({ annotations: {}, - aggregations: {}, + totalCount: 0, error: extractErrorMessage(resp), success: false, } as GetAnnotationsResponse) @@ -168,7 +160,6 @@ export function getFocusData( if (annotations.error !== undefined) { refreshFocusData.focusAnnotationError = annotations.error; refreshFocusData.focusAnnotationData = []; - refreshFocusData.focusAggregations = {}; } else { refreshFocusData.focusAnnotationData = (annotations.annotations[selectedJob.job_id] ?? []) .sort((a, b) => { @@ -178,8 +169,6 @@ export function getFocusData( d.key = (i + 1).toString(); return d; }); - - refreshFocusData.focusAggregations = annotations.aggregations; } } diff --git a/x-pack/plugins/ml/public/application/trained_models/index.ts b/x-pack/plugins/ml/public/application/trained_models/index.ts new file mode 100644 index 0000000000000..99a826236c34f --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { Page } from './page'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx b/x-pack/plugins/ml/public/application/trained_models/models_management/delete_models_modal.tsx similarity index 100% rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx rename to x-pack/plugins/ml/public/application/trained_models/models_management/delete_models_modal.tsx index 0db4c5d30fbeb..09daafb885720 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/delete_models_modal.tsx @@ -6,7 +6,6 @@ */ import React, { FC } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiModal, EuiModalHeader, @@ -17,6 +16,7 @@ import { EuiButton, EuiCallOut, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { ModelItemFull } from './models_list'; interface DeleteModelsModalProps { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx similarity index 90% rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/expanded_row.tsx rename to x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx index 87a3f10992c06..4b342fe02b4d5 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx @@ -6,30 +6,30 @@ */ import React, { FC, Fragment } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; import { + EuiBadge, + EuiButtonEmpty, + EuiCodeBlock, EuiDescriptionList, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiNotificationBadge, EuiPanel, EuiSpacer, EuiTabbedContent, - EuiTitle, - EuiNotificationBadge, - EuiFlexGrid, - EuiFlexItem, - EuiCodeBlock, EuiText, - EuiHorizontalRule, - EuiFlexGroup, EuiTextColor, - EuiButtonEmpty, - EuiBadge, + EuiTitle, } from '@elastic/eui'; import { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list'; +import { FormattedMessage } from '@kbn/i18n/react'; import { ModelItemFull } from './models_list'; -import { useMlKibana } from '../../../../../contexts/kibana'; -import { timeFormatter } from '../../../../../../../common/util/date_utils'; -import { isDefined } from '../../../../../../../common/types/guards'; -import { isPopulatedObject } from '../../../../../../../common'; +import { useMlKibana } from '../../contexts/kibana'; +import { timeFormatter } from '../../../../common/util/date_utils'; +import { isDefined } from '../../../../common/types/guards'; +import { isPopulatedObject } from '../../../../common'; interface ExpandedRowProps { item: ModelItemFull; @@ -52,6 +52,38 @@ const formatterDictionary: Record JSX.Element | string | timestamp: timeFormatter, }; +export function formatToListItems( + items: Record | object +): EuiDescriptionListProps['listItems'] { + return Object.entries(items) + .filter(([, value]) => isDefined(value)) + .map(([title, value]) => { + if (title in formatterDictionary) { + return { + title, + description: formatterDictionary[title](value), + }; + } + return { + title, + description: + typeof value === 'object' ? ( + + {JSON.stringify(value, null, 2)} + + ) : ( + value.toString() + ), + }; + }); +} + export const ExpandedRow: FC = ({ item }) => { const { inference_config: inferenceConfig, @@ -83,36 +115,6 @@ export const ExpandedRow: FC = ({ item }) => { license_level, }; - function formatToListItems(items: Record): EuiDescriptionListProps['listItems'] { - return Object.entries(items) - .filter(([, value]) => isDefined(value)) - .map(([title, value]) => { - if (title in formatterDictionary) { - return { - title, - description: formatterDictionary[title](value), - }; - } - return { - title, - description: - typeof value === 'object' ? ( - - {JSON.stringify(value, null, 2)} - - ) : ( - value.toString() - ), - }; - }); - } - const { services: { share }, } = useMlKibana(); @@ -243,6 +245,27 @@ export const ExpandedRow: FC = ({ item }) => { content: ( <> + {stats.deployment_stats && ( + <> + + +
+ +
+
+ + +
+ + + )} {stats.inference_stats && ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/index.ts b/x-pack/plugins/ml/public/application/trained_models/models_management/index.ts similarity index 94% rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/index.ts rename to x-pack/plugins/ml/public/application/trained_models/models_management/index.ts index 27c378aaed25b..b15e65e5150c9 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/index.ts +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/index.ts @@ -12,4 +12,5 @@ export const ModelsTableToConfigMapping = { description: 'description', createdAt: 'create_time', type: 'type', + modelType: 'model_type', } as const; 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/trained_models/models_management/models_list.tsx similarity index 76% rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx rename to x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx index dab86534209f1..16b9aa760f535 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/trained_models/models_management/models_list.tsx @@ -6,8 +6,7 @@ */ import React, { FC, useState, useCallback, useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { groupBy } from 'lodash'; import { EuiInMemoryTable, EuiFlexGroup, @@ -21,40 +20,37 @@ import { EuiSearchBarProps, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table'; import { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types'; import { Action } from '@elastic/eui/src/components/basic_table/action_types'; -import { StatsBar, ModelsBarStats } from '../../../../../components/stats_bar'; -import { useTrainedModelsApiService } from '../../../../../services/ml_api_service/trained_models'; -import { ModelsTableToConfigMapping } from './index'; -import { DeleteModelsModal } from './delete_models_modal'; -import { - useMlKibana, - useMlLocator, - useNavigateToPath, - useNotifications, -} from '../../../../../contexts/kibana'; -import { ExpandedRow } from './expanded_row'; - -import { - TrainedModelConfigResponse, - ModelPipelines, - TrainedModelStat, -} from '../../../../../../../common/types/trained_models'; import { getAnalysisType, REFRESH_ANALYTICS_LIST_STATE, refreshAnalyticsList$, useRefreshAnalyticsList, -} from '../../../../common'; -import { ML_PAGES } from '../../../../../../../common/constants/locator'; -import { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; -import { timeFormatter } from '../../../../../../../common/util/date_utils'; -import { isPopulatedObject } from '../../../../../../../common'; -import { ListingPageUrlState } from '../../../../../../../common/types/common'; -import { usePageUrlState } from '../../../../../util/url_state'; -import { BUILT_IN_MODEL_TAG } from '../../../../../../../common/constants/data_frame_analytics'; -import { useTableSettings } from '../analytics_list/use_table_settings'; +} from '../../data_frame_analytics/common'; +import { ModelsTableToConfigMapping } from './index'; +import { ModelsBarStats, StatsBar } from '../../components/stats_bar'; +import { useMlKibana, useMlLocator, useNavigateToPath } from '../../contexts/kibana'; +import { useTrainedModelsApiService } from '../../services/ml_api_service/trained_models'; +import { + ModelPipelines, + TrainedModelConfigResponse, + TrainedModelStat, +} from '../../../../common/types/trained_models'; +import { BUILT_IN_MODEL_TAG } from '../../../../common/constants/data_frame_analytics'; +import { DataFrameAnalysisConfigType } from '../../../../common/types/data_frame_analytics'; +import { DeleteModelsModal } from './delete_models_modal'; +import { ML_PAGES } from '../../../../common/constants/locator'; +import { ListingPageUrlState } from '../../../../common/types/common'; +import { usePageUrlState } from '../../util/url_state'; +import { ExpandedRow } from './expanded_row'; +import { isPopulatedObject } from '../../../../common'; +import { timeFormatter } from '../../../../common/util/date_utils'; +import { useTableSettings } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings'; +import { useToastNotificationService } from '../../services/toast_notification_service'; type Stats = Omit; @@ -87,7 +83,7 @@ export const ModelsList: FC = () => { const urlLocator = useMlLocator()!; const [pageState, updatePageState] = usePageUrlState( - ML_PAGES.DATA_FRAME_ANALYTICS_MODELS_MANAGE, + ML_PAGES.TRAINED_MODELS_MANAGE, getDefaultModelsListState() ); @@ -96,7 +92,9 @@ export const ModelsList: FC = () => { const canDeleteDataFrameAnalytics = capabilities.ml.canDeleteDataFrameAnalytics as boolean; const trainedModelsApiService = useTrainedModelsApiService(); - const { toasts } = useNotifications(); + + const { displayErrorToast, displayDangerToast, displaySuccessToast } = + useToastNotificationService(); const [isLoading, setIsLoading] = useState(false); const [items, setItems] = useState([]); @@ -133,6 +131,7 @@ export const ModelsList: FC = () => { ...(typeof model.inference_config === 'object' ? { type: [ + model.model_type, ...Object.keys(model.inference_config), ...(isBuiltInModel(model) ? [BUILT_IN_MODEL_TYPE] : []), ], @@ -159,11 +158,12 @@ export const ModelsList: FC = () => { ); } } catch (error) { - toasts.addError(new Error(error.body?.message), { - title: i18n.translate('xpack.ml.trainedModels.modelsList.fetchFailedErrorMessage', { + displayErrorToast( + error, + i18n.translate('xpack.ml.trainedModels.modelsList.fetchFailedErrorMessage', { defaultMessage: 'Models fetch failed', - }), - }); + }) + ); } setIsLoading(false); refreshAnalyticsList$.next(REFRESH_ANALYTICS_LIST_STATE.IDLE); @@ -191,23 +191,39 @@ export const ModelsList: FC = () => { * Fetches models stats and update the original object */ const fetchModelsStats = useCallback(async (models: ModelItem[]) => { - const modelIdsToFetch = models.map((model) => model.model_id); + const { true: pytorchModels } = groupBy(models, (m) => m.model_type === 'pytorch'); try { - const { trained_model_stats: modelsStatsResponse } = - await trainedModelsApiService.getTrainedModelStats(modelIdsToFetch); + if (models) { + const { trained_model_stats: modelsStatsResponse } = + await trainedModelsApiService.getTrainedModelStats(models.map((m) => m.model_id)); - for (const { model_id: id, ...stats } of modelsStatsResponse) { - const model = models.find((m) => m.model_id === id); - model!.stats = stats; + for (const { model_id: id, ...stats } of modelsStatsResponse) { + const model = models.find((m) => m.model_id === id); + model!.stats = stats; + } } + + if (pytorchModels) { + const { deployment_stats: deploymentStatsResponse } = + await trainedModelsApiService.getTrainedModelDeploymentStats( + pytorchModels.map((m) => m.model_id) + ); + + for (const { model_id: id, ...stats } of deploymentStatsResponse) { + const model = models.find((m) => m.model_id === id); + model!.stats!.deployment_stats = stats; + } + } + return true; } catch (error) { - toasts.addError(new Error(error.body.message), { - title: i18n.translate('xpack.ml.trainedModels.modelsList.fetchModelStatsErrorMessage', { + displayErrorToast( + error, + i18n.translate('xpack.ml.trainedModels.modelsList.fetchModelStatsErrorMessage', { defaultMessage: 'Fetch model stats failed', - }), - }); + }) + ); } }, []); @@ -220,6 +236,7 @@ export const ModelsList: FC = () => { if (type) { acc.add(type); } + acc.add(item.model_type); return acc; }, new Set()); return [...result].map((v) => ({ @@ -233,7 +250,7 @@ export const ModelsList: FC = () => { if (await fetchModelsStats(models)) { setModelsToDelete(models as ModelItemFull[]); } else { - toasts.addDanger( + displayDangerToast( i18n.translate('xpack.ml.trainedModels.modelsList.unableToDeleteModelsErrorMessage', { defaultMessage: 'Unable to delete models', }) @@ -256,7 +273,7 @@ export const ModelsList: FC = () => { (model) => !modelsToDelete.some((toDelete) => toDelete.model_id === model.model_id) ) ); - toasts.addSuccess( + displaySuccessToast( i18n.translate('xpack.ml.trainedModels.modelsList.successfullyDeletedMessage', { defaultMessage: '{modelsCount, plural, one {Model {modelsToDeleteIds}} other {# models}} {modelsCount, plural, one {has} other {have}} been successfully deleted', @@ -267,14 +284,15 @@ export const ModelsList: FC = () => { }) ); } catch (error) { - toasts.addError(new Error(error?.body?.message), { - title: i18n.translate('xpack.ml.trainedModels.modelsList.fetchDeletionErrorMessage', { + displayErrorToast( + error, + i18n.translate('xpack.ml.trainedModels.modelsList.fetchDeletionErrorMessage', { defaultMessage: '{modelsCount, plural, one {Model} other {Models}} deletion failed', values: { modelsCount: modelsToDeleteIds.length, }, - }), - }); + }) + ); } } @@ -336,6 +354,77 @@ export const ModelsList: FC = () => { await navigateToPath(path, false); }, }, + { + name: i18n.translate('xpack.ml.inference.modelsList.startModelAllocationActionLabel', { + defaultMessage: 'Start allocation', + }), + description: i18n.translate('xpack.ml.inference.modelsList.startModelAllocationActionLabel', { + defaultMessage: 'Start allocation', + }), + icon: 'download', + type: 'icon', + isPrimary: true, + available: (item) => item.model_type === 'pytorch', + onClick: async (item) => { + try { + await trainedModelsApiService.startModelAllocation(item.model_id); + displaySuccessToast( + i18n.translate('xpack.ml.trainedModels.modelsList.startSuccess', { + defaultMessage: 'Deployment for "{modelId}" has been started successfully.', + values: { + modelId: item.model_id, + }, + }) + ); + } catch (e) { + displayErrorToast( + e, + i18n.translate('xpack.ml.trainedModels.modelsList.startFailed', { + defaultMessage: 'Failed to start "{modelId}"', + values: { + modelId: item.model_id, + }, + }) + ); + } + }, + }, + { + name: i18n.translate('xpack.ml.inference.modelsList.stopModelAllocationActionLabel', { + defaultMessage: 'Stop allocation', + }), + description: i18n.translate('xpack.ml.inference.modelsList.stopModelAllocationActionLabel', { + defaultMessage: 'Stop allocation', + }), + icon: 'stop', + type: 'icon', + isPrimary: true, + available: (item) => item.model_type === 'pytorch', + enabled: (item) => !isPopulatedObject(item.pipelines), + onClick: async (item) => { + try { + await trainedModelsApiService.stopModelAllocation(item.model_id); + displaySuccessToast( + i18n.translate('xpack.ml.trainedModels.modelsList.stopSuccess', { + defaultMessage: 'Deployment for "{modelId}" has been stopped successfully.', + values: { + modelId: item.model_id, + }, + }) + ); + } catch (e) { + displayErrorToast( + e, + i18n.translate('xpack.ml.trainedModels.modelsList.stopFailed', { + defaultMessage: 'Failed to stop "{modelId}"', + values: { + modelId: item.model_id, + }, + }) + ); + } + }, + }, { name: i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { defaultMessage: 'Delete model', @@ -399,7 +488,7 @@ export const ModelsList: FC = () => { defaultMessage: 'ID', }), sortable: true, - truncateText: true, + truncateText: false, 'data-test-subj': 'mlModelsTableColumnId', }, { @@ -409,7 +498,7 @@ export const ModelsList: FC = () => { defaultMessage: 'Description', }), sortable: false, - truncateText: true, + truncateText: false, 'data-test-subj': 'mlModelsTableColumnDescription', }, { diff --git a/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx b/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx new file mode 100644 index 0000000000000..da8605f075c2f --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC, useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiTab, EuiTabs } from '@elastic/eui'; +import { useNavigateToPath } from '../contexts/kibana'; + +interface Tab { + id: string; + name: string; + path: string; +} + +export const TrainedModelsNavigationBar: FC<{ + selectedTabId?: string; +}> = ({ selectedTabId }) => { + const navigateToPath = useNavigateToPath(); + + const tabs = useMemo(() => { + const navTabs = [ + { + id: 'trained_models', + name: i18n.translate('xpack.ml.trainedModels.modelsTabLabel', { + defaultMessage: 'Models', + }), + path: '/trained_models', + testSubj: 'mlTrainedModelsTab', + }, + { + id: 'nodes', + name: i18n.translate('xpack.ml.trainedModels.nodesTabLabel', { + defaultMessage: 'Nodes', + }), + path: '/trained_models/nodes', + testSubj: 'mlNodesOverviewTab', + }, + ]; + return navTabs; + }, []); + + const onTabClick = useCallback( + async (tab: Tab) => { + await navigateToPath(tab.path, true); + }, + [navigateToPath] + ); + + return ( + + {tabs.map((tab) => { + return ( + + {tab.name} + + ); + })} + + ); +}; diff --git a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/expanded_row.tsx b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/expanded_row.tsx new file mode 100644 index 0000000000000..a32747185dcc8 --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/expanded_row.tsx @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { + EuiDescriptionList, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiPanel, + EuiSpacer, + EuiTextColor, + EuiTitle, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { NodeItemWithStats } from './nodes_list'; +import { formatToListItems } from '../models_management/expanded_row'; + +interface ExpandedRowProps { + item: NodeItemWithStats; +} + +export const ExpandedRow: FC = ({ item }) => { + const { + allocated_models: allocatedModels, + attributes, + memory_overview: memoryOverview, + ...details + } = item; + + return ( + <> + + + + + + +
+ +
+
+ + +
+ + +
+ + + + +
+ +
+
+ + +
+ + + + {allocatedModels.length > 0 ? ( + + +
+ +
+
+ + + {allocatedModels.map(({ model_id: modelId, ...rest }) => { + return ( + <> + + + + +
{modelId}
+
+
+
+ + + +
+ + + + + ); + })} +
+ ) : null} +
+
+ + ); +}; diff --git a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/index.ts b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/index.ts new file mode 100644 index 0000000000000..95b30e2409a45 --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { NodesList } from './nodes_list'; diff --git a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/memory_preview_chart.tsx b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/memory_preview_chart.tsx new file mode 100644 index 0000000000000..ba790ba1c2576 --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/memory_preview_chart.tsx @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import React, { FC, useMemo } from 'react'; +import { + Chart, + Settings, + BarSeries, + ScaleType, + Axis, + Position, + SeriesColorAccessor, +} from '@elastic/charts'; +import { euiPaletteGray } from '@elastic/eui'; +import { NodeDeploymentStatsResponse } from '../../../../common/types/trained_models'; +import { useFieldFormatter } from '../../contexts/kibana/use_field_formatter'; +import { useCurrentEuiTheme } from '../../components/color_range_legend'; + +interface MemoryPreviewChartProps { + memoryOverview: NodeDeploymentStatsResponse['memory_overview']; +} + +export const MemoryPreviewChart: FC = ({ memoryOverview }) => { + const bytesFormatter = useFieldFormatter('bytes'); + + const { euiTheme } = useCurrentEuiTheme(); + + const groups = useMemo( + () => ({ + jvm: { + name: i18n.translate('xpack.ml.trainedModels.nodesList.jvmHeapSIze', { + defaultMessage: 'JVM heap size', + }), + colour: euiTheme.euiColorVis1, + }, + trained_models: { + name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsMemoryUsage', { + defaultMessage: 'Trained models', + }), + colour: euiTheme.euiColorVis2, + }, + anomaly_detection: { + name: i18n.translate('xpack.ml.trainedModels.nodesList.adMemoryUsage', { + defaultMessage: 'Anomaly detection jobs', + }), + colour: euiTheme.euiColorVis6, + }, + dfa_training: { + name: i18n.translate('xpack.ml.trainedModels.nodesList.dfaMemoryUsage', { + defaultMessage: 'Data frame analytics jobs', + }), + colour: euiTheme.euiColorVis4, + }, + available: { + name: i18n.translate('xpack.ml.trainedModels.nodesList.availableMemory', { + defaultMessage: 'Estimated available memory', + }), + colour: euiPaletteGray(5)[0], + }, + }), + [] + ); + + const chartData = [ + { + x: 0, + y: memoryOverview.machine_memory.jvm, + g: groups.jvm.name, + }, + { + x: 0, + y: memoryOverview.trained_models.total, + g: groups.trained_models.name, + }, + { + x: 0, + y: memoryOverview.anomaly_detection.total, + g: groups.anomaly_detection.name, + }, + { + x: 0, + y: memoryOverview.dfa_training.total, + g: groups.dfa_training.name, + }, + { + x: 0, + y: + memoryOverview.machine_memory.total - + memoryOverview.machine_memory.jvm - + memoryOverview.trained_models.total - + memoryOverview.dfa_training.total - + memoryOverview.anomaly_detection.total, + g: groups.available.name, + }, + ]; + + const barSeriesColorAccessor: SeriesColorAccessor = ({ specId, yAccessor, splitAccessors }) => { + const group = splitAccessors.get('g'); + + return Object.values(groups).find((v) => v.name === group)!.colour; + }; + + return ( + + + i18n.translate('xpack.ml.trainedModels.nodesList.memoryBreakdown', { + defaultMessage: 'Approximate memory breakdown based on the node info', + }), + }} + /> + + bytesFormatter(d)} + /> + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/nodes_list.tsx b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/nodes_list.tsx new file mode 100644 index 0000000000000..42e51f1ab2971 --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/nodes_list.tsx @@ -0,0 +1,216 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { FC, useCallback, useMemo, useState } from 'react'; +import { + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiInMemoryTable, + EuiSearchBarProps, + EuiSpacer, +} from '@elastic/eui'; +import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table'; +import { i18n } from '@kbn/i18n'; +import { ModelsBarStats, StatsBar } from '../../components/stats_bar'; +import { NodeDeploymentStatsResponse } from '../../../../common/types/trained_models'; +import { usePageUrlState } from '../../util/url_state'; +import { ML_PAGES } from '../../../../common/constants/locator'; +import { useTrainedModelsApiService } from '../../services/ml_api_service/trained_models'; +import { useTableSettings } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings'; +import { ExpandedRow } from './expanded_row'; +import { + REFRESH_ANALYTICS_LIST_STATE, + refreshAnalyticsList$, + useRefreshAnalyticsList, +} from '../../data_frame_analytics/common'; +import { MemoryPreviewChart } from './memory_preview_chart'; +import { useFieldFormatter } from '../../contexts/kibana/use_field_formatter'; +import { ListingPageUrlState } from '../../../../common/types/common'; +import { useToastNotificationService } from '../../services/toast_notification_service'; + +export type NodeItem = NodeDeploymentStatsResponse; + +export interface NodeItemWithStats extends NodeItem { + stats: any; +} + +export const getDefaultNodesListState = (): ListingPageUrlState => ({ + pageIndex: 0, + pageSize: 10, + sortField: 'name', + sortDirection: 'asc', +}); + +export const NodesList: FC = () => { + const trainedModelsApiService = useTrainedModelsApiService(); + const { displayErrorToast } = useToastNotificationService(); + const bytesFormatter = useFieldFormatter('bytes'); + const [items, setItems] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState>( + {} + ); + const [pageState, updatePageState] = usePageUrlState( + ML_PAGES.TRAINED_MODELS_NODES, + getDefaultNodesListState() + ); + + const searchQueryText = pageState.queryText ?? ''; + + const fetchNodesData = useCallback(async () => { + try { + const nodesResponse = await trainedModelsApiService.getTrainedModelsNodesOverview(); + setItems(nodesResponse.nodes); + setIsLoading(false); + refreshAnalyticsList$.next(REFRESH_ANALYTICS_LIST_STATE.IDLE); + } catch (e) { + displayErrorToast( + e, + i18n.translate('xpack.ml.trainedModels.nodesList.nodesFetchError', { + defaultMessage: 'Nodes fetch failed', + }) + ); + } + }, []); + + const toggleDetails = (item: NodeItem) => { + const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; + if (itemIdToExpandedRowMapValues[item.id]) { + delete itemIdToExpandedRowMapValues[item.id]; + } else { + itemIdToExpandedRowMapValues[item.id] = ; + } + setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); + }; + + const columns: Array> = [ + { + align: 'left', + width: '40px', + isExpander: true, + render: (item: NodeItem) => ( + + ), + 'data-test-subj': 'mlNodesTableRowDetailsToggle', + }, + { + field: 'name', + name: i18n.translate('xpack.ml.trainedModels.nodesList.nodeNameHeader', { + defaultMessage: 'Name', + }), + sortable: true, + truncateText: true, + 'data-test-subj': 'mlNodesTableColumnName', + }, + { + name: i18n.translate('xpack.ml.trainedModels.nodesList.nodeTotalMemoryHeader', { + defaultMessage: 'Total memory', + }), + width: '200px', + truncateText: true, + 'data-test-subj': 'mlNodesTableColumnTotalMemory', + render: (v: NodeItem) => { + return bytesFormatter(v.attributes['ml.machine_memory']); + }, + }, + { + name: i18n.translate('xpack.ml.trainedModels.nodesList.nodeMemoryUsageHeader', { + defaultMessage: 'Memory usage', + }), + truncateText: true, + 'data-test-subj': 'mlNodesTableColumnMemoryUsage', + render: (v: NodeItem) => { + return ; + }, + }, + ]; + + const nodesStats: ModelsBarStats = useMemo(() => { + return { + total: { + show: true, + value: items.length, + label: i18n.translate('xpack.ml.trainedModels.nodesList.totalAmountLabel', { + defaultMessage: 'Total machine learning nodes', + }), + }, + }; + }, [items]); + + const { onTableChange, pagination, sorting } = useTableSettings( + items, + pageState, + updatePageState + ); + + const search: EuiSearchBarProps = { + query: searchQueryText, + onChange: (searchChange) => { + if (searchChange.error !== null) { + return false; + } + updatePageState({ queryText: searchChange.queryText, pageIndex: 0 }); + return true; + }, + box: { + incremental: true, + }, + }; + + // Subscribe to the refresh observable to trigger reloading the model list. + useRefreshAnalyticsList({ + isLoading: setIsLoading, + onRefresh: fetchNodesData, + }); + + return ( + <> + + + {nodesStats && ( + + + + )} + + +
+ + allowNeutralSort={false} + columns={columns} + hasActions={true} + isExpandable={true} + itemIdToExpandedRowMap={itemIdToExpandedRowMap} + isSelectable={false} + items={items} + itemId={'id'} + loading={isLoading} + search={search} + rowProps={(item) => ({ + 'data-test-subj': `mlNodesTableRow row-${item.id}`, + })} + pagination={pagination} + onTableChange={onTableChange} + sorting={sorting} + data-test-subj={isLoading ? 'mlNodesTable loading' : 'mlNodesTable loaded'} + /> +
+ + ); +}; diff --git a/x-pack/plugins/ml/public/application/trained_models/page.tsx b/x-pack/plugins/ml/public/application/trained_models/page.tsx new file mode 100644 index 0000000000000..a6d99ca0fedc0 --- /dev/null +++ b/x-pack/plugins/ml/public/application/trained_models/page.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC, Fragment, useMemo } from 'react'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiTitle, +} from '@elastic/eui'; + +import { useLocation } from 'react-router-dom'; +import { NavigationMenu } from '../components/navigation_menu'; +import { ModelsList } from './models_management'; +import { TrainedModelsNavigationBar } from './navigation_bar'; +import { RefreshAnalyticsListButton } from '../data_frame_analytics/pages/analytics_management/components/refresh_analytics_list_button'; +import { DatePickerWrapper } from '../components/navigation_menu/date_picker_wrapper'; +import { useRefreshAnalyticsList } from '../data_frame_analytics/common'; +import { useRefreshInterval } from '../data_frame_analytics/pages/analytics_management/components/analytics_list/use_refresh_interval'; +import { NodesList } from './nodes_overview'; + +export const Page: FC = () => { + useRefreshInterval(() => {}); + + useRefreshAnalyticsList({ isLoading: () => {} }); + const location = useLocation(); + const selectedTabId = useMemo(() => location.pathname.split('/').pop(), [location]); + + return ( + + + + + + + +

+ +

+
+
+ + + + + + + + + + +
+ + + + {selectedTabId === 'trained_models' ? : null} + {selectedTabId === 'nodes' ? : null} + +
+
+
+ ); +}; diff --git a/x-pack/plugins/ml/public/application/util/custom_url_utils.test.ts b/x-pack/plugins/ml/public/application/util/custom_url_utils.test.ts index 3e2b78d3b0ebb..09f5f17dc64be 100644 --- a/x-pack/plugins/ml/public/application/util/custom_url_utils.test.ts +++ b/x-pack/plugins/ml/public/application/util/custom_url_utils.test.ts @@ -585,6 +585,45 @@ describe('ML - custom URL utils', () => { 'http://airlinecodes.info/airline-code-AAL' ); }); + + test('returns expected URL with preserving custom filter', () => { + const urlWithCustomFilter: UrlConfig = { + url_name: 'URL with a custom filter', + url_value: `discover#/?_g=(time:(from:'$earliest$',mode:absolute,to:'$latest$'))&_a=(filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,key:subSystem.keyword,negate:!f,params:(query:JDBC),type:phrase),query:(match_phrase:(subSystem.keyword:JDBC)))),index:'eap_wls_server_12c*,*:eap_wls_server_12c*',query:(language:kuery,query:'wlscluster.keyword:"$wlscluster.keyword$"'))`, + }; + + const testRecords = { + job_id: 'farequote', + result_type: 'record', + probability: 6.533287347648861e-45, + record_score: 93.84475, + initial_record_score: 94.867922946384, + bucket_span: 300, + detector_index: 0, + is_interim: false, + timestamp: 1486656600000, + partition_field_name: 'wlscluster.keyword', + partition_field_value: 'AAL', + function: 'mean', + function_description: 'mean', + typical: [99.2329899996025], + actual: [274.7279901504516], + field_name: 'wlscluster.keyword', + influencers: [ + { + influencer_field_name: 'wlscluster.keyword', + influencer_field_values: ['AAL'], + }, + ], + 'wlscluster.keyword': ['AAL'], + earliest: '2019-02-01T16:00:00.000Z', + latest: '2019-02-01T18:59:59.999Z', + }; + + expect(getUrlForRecord(urlWithCustomFilter, testRecords)).toBe( + `discover#/?_g=(time:(from:'2019-02-01T16:00:00.000Z',mode:absolute,to:'2019-02-01T18:59:59.999Z'))&_a=(filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,key:subSystem.keyword,negate:!f,params:(query:JDBC),type:phrase),query:(match_phrase:(subSystem.keyword:JDBC)))),index:'eap_wls_server_12c*,*:eap_wls_server_12c*',query:(language:kuery,query:'wlscluster.keyword:\"AAL\"'))` + ); + }); }); describe('isValidLabel', () => { diff --git a/x-pack/plugins/ml/public/embeddables/common/process_filters.ts b/x-pack/plugins/ml/public/embeddables/common/process_filters.ts index 4ce445eb4c488..1ff8259250019 100644 --- a/x-pack/plugins/ml/public/embeddables/common/process_filters.ts +++ b/x-pack/plugins/ml/public/embeddables/common/process_filters.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Filter, fromKueryExpression, diff --git a/x-pack/plugins/ml/public/locator/formatters/trained_models.ts b/x-pack/plugins/ml/public/locator/formatters/trained_models.ts new file mode 100644 index 0000000000000..d084c0675769f --- /dev/null +++ b/x-pack/plugins/ml/public/locator/formatters/trained_models.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TrainedModelsUrlState } from '../../../common/types/locator'; +import { ML_PAGES } from '../../../common/constants/locator'; + +export function formatTrainedModelsManagementUrl( + appBasePath: string, + mlUrlGeneratorState: TrainedModelsUrlState['pageState'] +): string { + return `${appBasePath}/${ML_PAGES.TRAINED_MODELS_MANAGE}`; +} diff --git a/x-pack/plugins/ml/public/locator/ml_locator.ts b/x-pack/plugins/ml/public/locator/ml_locator.ts index 5e41864c96e29..f1bcd84e77d7d 100644 --- a/x-pack/plugins/ml/public/locator/ml_locator.ts +++ b/x-pack/plugins/ml/public/locator/ml_locator.ts @@ -26,6 +26,7 @@ import { formatEditCalendarUrl, formatEditFilterUrl, } from './formatters'; +import { formatTrainedModelsManagementUrl } from './formatters/trained_models'; export { MlLocatorParams, MlLocator }; @@ -66,6 +67,9 @@ export class MlLocatorDefinition implements LocatorDefinition { case ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION: path = formatDataFrameAnalyticsExplorationUrl('', params.pageState); break; + case ML_PAGES.TRAINED_MODELS_MANAGE: + path = formatTrainedModelsManagementUrl('', params.pageState); + break; case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB: case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED: case ML_PAGES.DATA_VISUALIZER: diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 60767ecc4c43e..e5346b6618098 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -46,6 +46,10 @@ import type { DataVisualizerPluginStart } from '../../data_visualizer/public'; import type { PluginSetupContract as AlertingSetup } from '../../alerting/public'; import { registerManagementSection } from './application/management'; import type { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; +import type { + FieldFormatsSetup, + FieldFormatsStart, +} from '../../../../src/plugins/field_formats/public'; export interface MlStartDependencies { data: DataPublicPluginStart; @@ -57,6 +61,7 @@ export interface MlStartDependencies { maps?: MapsStartApi; triggersActionsUi?: TriggersAndActionsUIPublicPluginStart; dataVisualizer: DataVisualizerPluginStart; + fieldFormats: FieldFormatsStart; } export interface MlSetupDependencies { @@ -72,6 +77,7 @@ export interface MlSetupDependencies { triggersActionsUi?: TriggersAndActionsUIPublicPluginSetup; alerting?: AlertingSetup; usageCollection?: UsageCollectionSetup; + fieldFormats: FieldFormatsSetup; } export type MlCoreSetup = CoreSetup; @@ -116,6 +122,7 @@ export class MlPlugin implements Plugin { triggersActionsUi: pluginsStart.triggersActionsUi, dataVisualizer: pluginsStart.dataVisualizer, usageCollection: pluginsSetup.usageCollection, + fieldFormats: pluginsStart.fieldFormats, }, params ); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index 693731562ee82..d88bce762e093 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -38,7 +38,7 @@ const DATA_FRAME_ANALYTICS_DEEP_LINK: AppDeepLink = { title: i18n.translate('xpack.ml.deepLink.trainedModels', { defaultMessage: 'Trained Models', }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MODELS_MANAGE}`, + path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, }, ], }; diff --git a/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.test.ts b/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.test.ts index 2790ce423c1e7..e824e34a1779b 100644 --- a/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.test.ts +++ b/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.test.ts @@ -9,7 +9,7 @@ import { JobsHealthService, jobsHealthServiceProvider } from './jobs_health_serv import type { DatafeedsService } from '../../models/job_service/datafeeds'; import type { Logger } from 'kibana/server'; import { MlClient } from '../ml_client'; -import { MlJob, MlJobStats } from '@elastic/elasticsearch/api/types'; +import { MlJob, MlJobStats } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AnnotationService } from '../../models/annotation_service/annotation'; import { JobsHealthExecutorOptions } from './register_jobs_monitoring_rule_type'; import { JobAuditMessagesService } from '../../models/job_audit_messages/job_audit_messages'; diff --git a/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.ts b/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.ts index 70a8e4a777b69..2fbda6a4b37f6 100644 --- a/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.ts +++ b/x-pack/plugins/ml/server/lib/alerts/jobs_health_service.ts @@ -8,7 +8,7 @@ import { groupBy, keyBy, memoize } from 'lodash'; import { KibanaRequest, Logger, SavedObjectsClientContract } from 'kibana/server'; import { i18n } from '@kbn/i18n'; -import { MlJob } from '@elastic/elasticsearch/api/types'; +import { MlJob } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { MlClient } from '../ml_client'; import { JobSelection } from '../../routes/schemas/alerting_schema'; import { datafeedsProvider, DatafeedsService } from '../../models/job_service/datafeeds'; diff --git a/x-pack/plugins/ml/server/lib/alerts/register_jobs_monitoring_rule_type.ts b/x-pack/plugins/ml/server/lib/alerts/register_jobs_monitoring_rule_type.ts index dcf545fa4060b..5fd21d5372d23 100644 --- a/x-pack/plugins/ml/server/lib/alerts/register_jobs_monitoring_rule_type.ts +++ b/x-pack/plugins/ml/server/lib/alerts/register_jobs_monitoring_rule_type.ts @@ -7,7 +7,11 @@ import { i18n } from '@kbn/i18n'; import { KibanaRequest } from 'kibana/server'; -import { MlDatafeedState, MlJobState, MlJobStats } from '@elastic/elasticsearch/api/types'; +import { + MlDatafeedState, + MlJobState, + MlJobStats, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ML_ALERT_TYPES } from '../../../common/constants/alerts'; import { PLUGIN_ID } from '../../../common/constants/app'; import { MINIMUM_FULL_LICENSE } from '../../../common/license'; diff --git a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts index 8fa8f71e82d81..6169d9ee9db47 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts @@ -380,6 +380,17 @@ export function getMlClient( async getTrainedModelsStats(...p: Parameters) { return mlClient.getTrainedModelsStats(...p); }, + async getTrainedModelDeploymentStats( + ...p: Parameters + ) { + return mlClient.getTrainedModelDeploymentStats(...p); + }, + async startTrainedModelDeployment(...p: Parameters) { + return mlClient.startTrainedModelDeployment(...p); + }, + async stopTrainedModelDeployment(...p: Parameters) { + return mlClient.stopTrainedModelDeployment(...p); + }, async info(...p: Parameters) { return mlClient.info(...p); }, diff --git a/x-pack/plugins/ml/server/lib/ml_client/search.ts b/x-pack/plugins/ml/server/lib/ml_client/search.ts index 3062a70d9a975..bdcee216cf669 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/search.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/search.ts @@ -7,7 +7,8 @@ import Boom from '@hapi/boom'; import { IScopedClusterClient } from 'kibana/server'; -import { estypes, ApiResponse } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TransportResult } from '@elastic/elasticsearch'; import { JobSavedObjectService } from '../../saved_objects'; import { ML_RESULTS_INDEX_PATTERN } from '../../../common/constants/index_patterns'; @@ -30,7 +31,7 @@ export function searchProvider( async function anomalySearch( searchParams: estypes.SearchRequest, jobIds: string[] - ): Promise>> { + ): Promise, unknown>> { await jobIdsCheck('anomaly-detector', jobIds); const { asInternalUser } = client; const resp = await asInternalUser.search({ diff --git a/x-pack/plugins/ml/server/lib/ml_client/types.ts b/x-pack/plugins/ml/server/lib/ml_client/types.ts index 7ff1acf4ac0ce..d8c65c4f56814 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/types.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/types.ts @@ -48,6 +48,9 @@ export type MlClientParams = | Parameters | Parameters | Parameters + | Parameters + | Parameters + | Parameters | Parameters | Parameters | Parameters diff --git a/x-pack/plugins/ml/server/lib/query_utils.ts b/x-pack/plugins/ml/server/lib/query_utils.ts index e801130643345..cfaa5abaf7f23 100644 --- a/x-pack/plugins/ml/server/lib/query_utils.ts +++ b/x-pack/plugins/ml/server/lib/query_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /* * Contains utility functions for building and processing queries. */ diff --git a/x-pack/plugins/ml/server/models/annotation_service/__mocks__/get_annotations_request.json b/x-pack/plugins/ml/server/models/annotation_service/__mocks__/get_annotations_request.json index b91eb94c7fd7b..c65185a6172eb 100644 --- a/x-pack/plugins/ml/server/models/annotation_service/__mocks__/get_annotations_request.json +++ b/x-pack/plugins/ml/server/models/annotation_service/__mocks__/get_annotations_request.json @@ -1,6 +1,7 @@ { "index": ".ml-annotations-read", "size": 500, + "track_total_hits": true, "body": { "query": { "bool": { diff --git a/x-pack/plugins/ml/server/models/annotation_service/annotation.ts b/x-pack/plugins/ml/server/models/annotation_service/annotation.ts index 5807d181cc566..12b2954f63710 100644 --- a/x-pack/plugins/ml/server/models/annotation_service/annotation.ts +++ b/x-pack/plugins/ml/server/models/annotation_service/annotation.ts @@ -9,7 +9,7 @@ import Boom from '@hapi/boom'; import { each, get } from 'lodash'; import { IScopedClusterClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ANNOTATION_EVENT_USER, ANNOTATION_TYPE } from '../../../common/constants/annotations'; import { PARTITION_FIELDS } from '../../../common/constants/anomalies'; import { @@ -24,7 +24,6 @@ import { isAnnotations, getAnnotationFieldName, getAnnotationFieldValue, - EsAggregationResult, } from '../../../common/types/annotations'; import { JobId } from '../../../common/types/anomaly_detection_jobs'; @@ -35,36 +34,27 @@ interface EsResult { _id: string; } -export interface FieldToBucket { - field: string; - missing?: string | number; -} - export interface IndexAnnotationArgs { jobIds: string[]; earliestMs: number | null; latestMs: number | null; maxAnnotations: number; - fields?: FieldToBucket[]; detectorIndex?: number; entities?: any[]; event?: Annotation['event']; } -export interface AggTerm { - terms: FieldToBucket; -} - export interface GetParams { index: string; size: number; body: object; + track_total_hits: boolean; } export interface GetResponse { success: true; annotations: Record; - aggregations: EsAggregationResult; + totalCount: number; } export interface IndexParams { @@ -118,7 +108,6 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { earliestMs, latestMs, maxAnnotations, - fields, detectorIndex, entities, event, @@ -126,7 +115,7 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { const obj: GetResponse = { success: true, annotations: {}, - aggregations: {}, + totalCount: 0, }; const boolCriteria: object[] = []; @@ -215,18 +204,6 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { }); } - // Find unique buckets (e.g. events) from the queried annotations to show in dropdowns - const aggs: Record = {}; - if (fields) { - fields.forEach((fieldToBucket) => { - aggs[fieldToBucket.field] = { - terms: { - ...fieldToBucket, - }, - }; - }); - } - // Build should clause to further query for annotations in SMV // we want to show either the exact match with detector index and by/over/partition fields // OR annotations without any partition fields defined @@ -276,6 +253,7 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { const params: GetParams = { index: ML_ANNOTATIONS_INDEX_ALIAS_READ, size: maxAnnotations, + track_total_hits: true, body: { query: { bool: { @@ -295,7 +273,6 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { ...(shouldClauses ? { should: shouldClauses, minimum_should_match: 1 } : {}), }, }, - ...(fields ? { aggs } : {}), }, }; @@ -308,6 +285,9 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { throw new Error(`Annotations couldn't be retrieved from Elasticsearch.`); } + // @ts-expect-error incorrect search response type + obj.totalCount = body.hits.total.value; + // @ts-expect-error TODO fix search response types const docs: Annotations = get(body, ['hits', 'hits'], []).map((d: EsResult) => { // get the original source document and the document id, we need it @@ -321,10 +301,6 @@ export function annotationProvider({ asInternalUser }: IScopedClusterClient) { } as Annotation; }); - const aggregations = get(body, ['aggregations'], {}) as EsAggregationResult; - if (fields) { - obj.aggregations = aggregations; - } if (isAnnotations(docs) === false) { // No need to translate, this will not be exposed in the UI. throw new Error(`Annotations didn't pass integrity check.`); diff --git a/x-pack/plugins/ml/server/models/calculate_model_memory_limit/calculate_model_memory_limit.ts b/x-pack/plugins/ml/server/models/calculate_model_memory_limit/calculate_model_memory_limit.ts index 760faa8d530fc..4eb2c2421debf 100644 --- a/x-pack/plugins/ml/server/models/calculate_model_memory_limit/calculate_model_memory_limit.ts +++ b/x-pack/plugins/ml/server/models/calculate_model_memory_limit/calculate_model_memory_limit.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import numeral from '@elastic/numeral'; import { IScopedClusterClient } from 'kibana/server'; import { MLCATEGORY } from '../../../common/constants/field_types'; @@ -89,6 +89,7 @@ const cardinalityCheckProvider = (client: IScopedClusterClient) => { new Set() ); + // @ts-expect-error influencers is optional const normalizedInfluencers: estypes.Field[] = Array.isArray(influencers) ? influencers : [influencers]; diff --git a/x-pack/plugins/ml/server/models/calendar/calendar_manager.ts b/x-pack/plugins/ml/server/models/calendar/calendar_manager.ts index 791ba6d79ab5a..508abcffd0776 100644 --- a/x-pack/plugins/ml/server/models/calendar/calendar_manager.ts +++ b/x-pack/plugins/ml/server/models/calendar/calendar_manager.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { difference } from 'lodash'; import { EventManager } from './event_manager'; import type { MlClient } from '../../lib/ml_client'; diff --git a/x-pack/plugins/ml/server/models/calendar/event_manager.ts b/x-pack/plugins/ml/server/models/calendar/event_manager.ts index d30297eab5c15..46ad415167387 100644 --- a/x-pack/plugins/ml/server/models/calendar/event_manager.ts +++ b/x-pack/plugins/ml/server/models/calendar/event_manager.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { GLOBAL_CALENDAR } from '../../../common/constants/calendars'; import type { MlClient } from '../../lib/ml_client'; diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/__mocks__/mock_deployment_response.json b/x-pack/plugins/ml/server/models/data_frame_analytics/__mocks__/mock_deployment_response.json new file mode 100644 index 0000000000000..0742c249b67b0 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/__mocks__/mock_deployment_response.json @@ -0,0 +1,357 @@ +{ + "count" : 4, + "deployment_stats" : [ + { + "model_id" : "distilbert-base-uncased-finetuned-sst-2-english", + "model_size_bytes" : 267386880, + "inference_threads" : 1, + "model_threads" : 1, + "state" : "started", + "allocation_status" : { + "allocation_count" : 2, + "target_allocation_count" : 3, + "state" : "started" + }, + "nodes" : [ + { + "node" : { + "3qIoLFnbSi-DwVrYioUCdw" : { + "name" : "node3", + "ephemeral_id" : "WeA49KLuRPmJM_ulLx0ANg", + "transport_address" : "10.142.0.2:9353", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "ingest", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + }, + { + "node" : { + "DpCy7SOBQla3pu0Dq-tnYw" : { + "name" : "node2", + "ephemeral_id" : "17qcsXsNTYqbJ6uwSvdl9g", + "transport_address" : "10.142.0.2:9352", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "failed", + "reason" : "The object cannot be set twice!" + } + }, + { + "node" : { + "pt7s6lKHQJaP4QHKtU-Q0Q" : { + "name" : "node1", + "ephemeral_id" : "nMJBE9WSRQSWotk0zDPi_Q", + "transport_address" : "10.142.0.2:9351", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + } + ] + }, + { + "model_id" : "elastic__distilbert-base-cased-finetuned-conll03-english", + "model_size_bytes" : 260947500, + "inference_threads" : 1, + "model_threads" : 1, + "state" : "started", + "allocation_status" : { + "allocation_count" : 2, + "target_allocation_count" : 3, + "state" : "started" + }, + "nodes" : [ + { + "node" : { + "3qIoLFnbSi-DwVrYioUCdw" : { + "name" : "node3", + "ephemeral_id" : "WeA49KLuRPmJM_ulLx0ANg", + "transport_address" : "10.142.0.2:9353", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "ingest", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + }, + { + "node" : { + "DpCy7SOBQla3pu0Dq-tnYw" : { + "name" : "node2", + "ephemeral_id" : "17qcsXsNTYqbJ6uwSvdl9g", + "transport_address" : "10.142.0.2:9352", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "failed", + "reason" : "The object cannot be set twice!" + } + }, + { + "node" : { + "pt7s6lKHQJaP4QHKtU-Q0Q" : { + "name" : "node1", + "ephemeral_id" : "nMJBE9WSRQSWotk0zDPi_Q", + "transport_address" : "10.142.0.2:9351", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + } + ] + }, + { + "model_id" : "sentence-transformers__msmarco-minilm-l-12-v3", + "model_size_bytes" : 133378867, + "inference_threads" : 1, + "model_threads" : 1, + "state" : "started", + "allocation_status" : { + "allocation_count" : 2, + "target_allocation_count" : 3, + "state" : "started" + }, + "nodes" : [ + { + "node" : { + "3qIoLFnbSi-DwVrYioUCdw" : { + "name" : "node3", + "ephemeral_id" : "WeA49KLuRPmJM_ulLx0ANg", + "transport_address" : "10.142.0.2:9353", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "ingest", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + }, + { + "node" : { + "DpCy7SOBQla3pu0Dq-tnYw" : { + "name" : "node2", + "ephemeral_id" : "17qcsXsNTYqbJ6uwSvdl9g", + "transport_address" : "10.142.0.2:9352", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "failed", + "reason" : "The object cannot be set twice!" + } + }, + { + "node" : { + "pt7s6lKHQJaP4QHKtU-Q0Q" : { + "name" : "node1", + "ephemeral_id" : "nMJBE9WSRQSWotk0zDPi_Q", + "transport_address" : "10.142.0.2:9351", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + } + ] + }, + { + "model_id" : "typeform__mobilebert-uncased-mnli", + "model_size_bytes" : 100139008, + "inference_threads" : 1, + "model_threads" : 1, + "state" : "started", + "allocation_status" : { + "allocation_count" : 2, + "target_allocation_count" : 3, + "state" : "started" + }, + "nodes" : [ + { + "node" : { + "3qIoLFnbSi-DwVrYioUCdw" : { + "name" : "node3", + "ephemeral_id" : "WeA49KLuRPmJM_ulLx0ANg", + "transport_address" : "10.142.0.2:9353", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "ingest", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + }, + { + "node" : { + "DpCy7SOBQla3pu0Dq-tnYw" : { + "name" : "node2", + "ephemeral_id" : "17qcsXsNTYqbJ6uwSvdl9g", + "transport_address" : "10.142.0.2:9352", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml", + "transform" + ] + } + }, + "routing_state" : { + "routing_state" : "failed", + "reason" : "The object cannot be set twice!" + } + }, + { + "node" : { + "pt7s6lKHQJaP4QHKtU-Q0Q" : { + "name" : "node1", + "ephemeral_id" : "nMJBE9WSRQSWotk0zDPi_Q", + "transport_address" : "10.142.0.2:9351", + "attributes" : { + "ml.machine_memory" : "15599742976", + "xpack.installed" : "true", + "ml.max_jvm_size" : "1073741824" + }, + "roles" : [ + "data", + "master", + "ml" + ] + } + }, + "routing_state" : { + "routing_state" : "started" + }, + "inference_count" : 0, + "average_inference_time_ms" : 0.0 + } + ] + } + ] +} diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/model_provider.test.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/model_provider.test.ts new file mode 100644 index 0000000000000..4f5e1ee9b230c --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/model_provider.test.ts @@ -0,0 +1,503 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ModelService, modelsProvider } from './models_provider'; +import { IScopedClusterClient } from 'kibana/server'; +import { MlClient } from '../../lib/ml_client'; +import mockResponse from './__mocks__/mock_deployment_response.json'; +import { MemoryOverviewService } from '../memory_overview/memory_overview_service'; + +describe('Model service', () => { + const client = { + asCurrentUser: { + nodes: { + stats: jest.fn(() => { + return Promise.resolve({ + body: { + _nodes: { + total: 3, + successful: 3, + failed: 0, + }, + cluster_name: 'test_cluster', + nodes: { + '3qIoLFnbSi-DwVrYioUCdw': { + timestamp: 1635167166946, + name: 'node3', + transport_address: '10.10.10.2:9353', + host: '10.10.10.2', + ip: '10.10.10.2:9353', + roles: ['data', 'ingest', 'master', 'ml', 'transform'], + attributes: { + 'ml.machine_memory': '15599742976', + 'xpack.installed': 'true', + 'ml.max_jvm_size': '1073741824', + }, + os: { + mem: { + total_in_bytes: 15599742976, + adjusted_total_in_bytes: 15599742976, + free_in_bytes: 376324096, + used_in_bytes: 15223418880, + free_percent: 2, + used_percent: 98, + }, + }, + }, + 'DpCy7SOBQla3pu0Dq-tnYw': { + timestamp: 1635167166946, + name: 'node2', + transport_address: '10.10.10.2:9352', + host: '10.10.10.2', + ip: '10.10.10.2:9352', + roles: ['data', 'master', 'ml', 'transform'], + attributes: { + 'ml.machine_memory': '15599742976', + 'xpack.installed': 'true', + 'ml.max_jvm_size': '1073741824', + }, + os: { + timestamp: 1635167166959, + mem: { + total_in_bytes: 15599742976, + adjusted_total_in_bytes: 15599742976, + free_in_bytes: 376324096, + used_in_bytes: 15223418880, + free_percent: 2, + used_percent: 98, + }, + }, + }, + 'pt7s6lKHQJaP4QHKtU-Q0Q': { + timestamp: 1635167166945, + name: 'node1', + transport_address: '10.10.10.2:9351', + host: '10.10.10.2', + ip: '10.10.10.2:9351', + roles: ['data', 'master', 'ml'], + attributes: { + 'ml.machine_memory': '15599742976', + 'xpack.installed': 'true', + 'ml.max_jvm_size': '1073741824', + }, + os: { + timestamp: 1635167166959, + mem: { + total_in_bytes: 15599742976, + adjusted_total_in_bytes: 15599742976, + free_in_bytes: 376324096, + used_in_bytes: 15223418880, + free_percent: 2, + used_percent: 98, + }, + }, + }, + }, + }, + }); + }), + }, + }, + } as unknown as jest.Mocked; + const mlClient = { + getTrainedModelDeploymentStats: jest.fn(() => { + return Promise.resolve({ body: mockResponse }); + }), + } as unknown as jest.Mocked; + const memoryOverviewService = { + getDFAMemoryOverview: jest.fn(() => { + return Promise.resolve([{ job_id: '', node_id: '', model_size: 32165465 }]); + }), + getAnomalyDetectionMemoryOverview: jest.fn(() => { + return Promise.resolve([{ job_id: '', node_id: '', model_size: 32165465 }]); + }), + } as unknown as jest.Mocked; + + let service: ModelService; + + beforeEach(() => { + service = modelsProvider(client, mlClient, memoryOverviewService); + }); + + afterEach(() => {}); + + it('extract nodes list correctly', async () => { + expect(await service.getNodesOverview()).toEqual({ + count: 3, + nodes: [ + { + name: 'node3', + allocated_models: [ + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size_bytes: 267386880, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size_bytes: 260947500, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size_bytes: 133378867, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'typeform__mobilebert-uncased-mnli', + model_size_bytes: 100139008, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + ], + attributes: { + 'ml.machine_memory': '15599742976', + 'ml.max_jvm_size': '1073741824', + 'xpack.installed': 'true', + }, + host: '10.10.10.2', + id: '3qIoLFnbSi-DwVrYioUCdw', + ip: '10.10.10.2:9353', + memory_overview: { + anomaly_detection: { + total: 0, + }, + dfa_training: { + total: 0, + }, + machine_memory: { + jvm: 1073741824, + total: 15599742976, + }, + trained_models: { + by_model: [ + { + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size: 267386880, + }, + { + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size: 260947500, + }, + { + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size: 133378867, + }, + { + model_id: 'typeform__mobilebert-uncased-mnli', + model_size: 100139008, + }, + ], + total: 793309535, + }, + }, + roles: ['data', 'ingest', 'master', 'ml', 'transform'], + transport_address: '10.10.10.2:9353', + }, + { + name: 'node2', + allocated_models: [ + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size_bytes: 267386880, + model_threads: 1, + state: 'started', + node: { + routing_state: { + reason: 'The object cannot be set twice!', + routing_state: 'failed', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size_bytes: 260947500, + model_threads: 1, + state: 'started', + node: { + routing_state: { + reason: 'The object cannot be set twice!', + routing_state: 'failed', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size_bytes: 133378867, + model_threads: 1, + state: 'started', + node: { + routing_state: { + reason: 'The object cannot be set twice!', + routing_state: 'failed', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'typeform__mobilebert-uncased-mnli', + model_size_bytes: 100139008, + model_threads: 1, + state: 'started', + node: { + routing_state: { + reason: 'The object cannot be set twice!', + routing_state: 'failed', + }, + }, + }, + ], + attributes: { + 'ml.machine_memory': '15599742976', + 'ml.max_jvm_size': '1073741824', + 'xpack.installed': 'true', + }, + host: '10.10.10.2', + id: 'DpCy7SOBQla3pu0Dq-tnYw', + ip: '10.10.10.2:9352', + memory_overview: { + anomaly_detection: { + total: 0, + }, + dfa_training: { + total: 0, + }, + machine_memory: { + jvm: 1073741824, + total: 15599742976, + }, + trained_models: { + by_model: [ + { + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size: 267386880, + }, + { + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size: 260947500, + }, + { + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size: 133378867, + }, + { + model_id: 'typeform__mobilebert-uncased-mnli', + model_size: 100139008, + }, + ], + total: 793309535, + }, + }, + roles: ['data', 'master', 'ml', 'transform'], + transport_address: '10.10.10.2:9352', + }, + { + allocated_models: [ + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size_bytes: 267386880, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size_bytes: 260947500, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size_bytes: 133378867, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + { + allocation_status: { + allocation_count: 2, + state: 'started', + target_allocation_count: 3, + }, + inference_threads: 1, + model_id: 'typeform__mobilebert-uncased-mnli', + model_size_bytes: 100139008, + model_threads: 1, + state: 'started', + node: { + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: 'started', + }, + }, + }, + ], + attributes: { + 'ml.machine_memory': '15599742976', + 'ml.max_jvm_size': '1073741824', + 'xpack.installed': 'true', + }, + host: '10.10.10.2', + id: 'pt7s6lKHQJaP4QHKtU-Q0Q', + ip: '10.10.10.2:9351', + memory_overview: { + anomaly_detection: { + total: 0, + }, + dfa_training: { + total: 0, + }, + machine_memory: { + jvm: 1073741824, + total: 15599742976, + }, + trained_models: { + by_model: [ + { + model_id: 'distilbert-base-uncased-finetuned-sst-2-english', + model_size: 267386880, + }, + { + model_id: 'elastic__distilbert-base-cased-finetuned-conll03-english', + model_size: 260947500, + }, + { + model_id: 'sentence-transformers__msmarco-minilm-l-12-v3', + model_size: 133378867, + }, + { + model_id: 'typeform__mobilebert-uncased-mnli', + model_size: 100139008, + }, + ], + total: 793309535, + }, + }, + name: 'node1', + roles: ['data', 'master', 'ml'], + transport_address: '10.10.10.2:9351', + }, + ], + }); + }); +}); diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts index 84f0fbaea0579..b404f517e4b6f 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts @@ -5,10 +5,40 @@ * 2.0. */ -import { IScopedClusterClient } from 'kibana/server'; -import { PipelineDefinition } from '../../../common/types/trained_models'; +import type { IScopedClusterClient } from 'kibana/server'; +import { sumBy, pick } from 'lodash'; +import { NodesInfoNodeInfo } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { + NodeDeploymentStatsResponse, + PipelineDefinition, + NodesOverviewResponse, +} from '../../../common/types/trained_models'; +import type { MlClient } from '../../lib/ml_client'; +import { + MemoryOverviewService, + NATIVE_EXECUTABLE_CODE_OVERHEAD, +} from '../memory_overview/memory_overview_service'; +import { TrainedModelDeploymentStatsResponse } from '../../../common/types/trained_models'; -export function modelsProvider(client: IScopedClusterClient) { +export type ModelService = ReturnType; + +const NODE_FIELDS = [ + 'attributes', + 'name', + 'roles', + 'ip', + 'host', + 'transport_address', + 'version', +] as const; + +export type RequiredNodeFields = Pick; + +export function modelsProvider( + client: IScopedClusterClient, + mlClient: MlClient, + memoryOverviewService?: MemoryOverviewService +) { return { /** * Retrieves the map of model ids and aliases with associated pipelines. @@ -39,5 +69,107 @@ export function modelsProvider(client: IScopedClusterClient) { return modelIdsMap; }, + + /** + * Provides the ML nodes overview with allocated models. + */ + async getNodesOverview(): Promise { + if (!memoryOverviewService) { + throw new Error('Memory overview service is not provided'); + } + + const { body: deploymentStats } = await mlClient.getTrainedModelDeploymentStats({ + model_id: '*', + }); + + const { + body: { nodes: clusterNodes }, + } = await client.asCurrentUser.nodes.stats(); + + const mlNodes = Object.entries(clusterNodes).filter(([, node]) => node.roles.includes('ml')); + + const adMemoryReport = await memoryOverviewService.getAnomalyDetectionMemoryOverview(); + const dfaMemoryReport = await memoryOverviewService.getDFAMemoryOverview(); + + const nodeDeploymentStatsResponses: NodeDeploymentStatsResponse[] = mlNodes.map( + ([nodeId, node]) => { + const nodeFields = pick(node, NODE_FIELDS) as RequiredNodeFields; + + const allocatedModels = ( + deploymentStats.deployment_stats as TrainedModelDeploymentStatsResponse[] + ) + .filter((v) => v.nodes.some((n) => Object.keys(n.node)[0] === nodeId)) + .map(({ nodes, ...rest }) => { + const { node: tempNode, ...nodeRest } = nodes.find( + (v) => Object.keys(v.node)[0] === nodeId + )!; + return { + ...rest, + node: nodeRest, + }; + }); + + const modelsMemoryUsage = allocatedModels.map((v) => { + return { + model_id: v.model_id, + model_size: v.model_size_bytes, + }; + }); + + const memoryRes = { + adTotalMemory: sumBy( + adMemoryReport.filter((ad) => ad.node_id === nodeId), + 'model_size' + ), + dfaTotalMemory: sumBy( + dfaMemoryReport.filter((dfa) => dfa.node_id === nodeId), + 'model_size' + ), + trainedModelsTotalMemory: sumBy(modelsMemoryUsage, 'model_size'), + }; + + for (const key of Object.keys(memoryRes)) { + if (memoryRes[key as keyof typeof memoryRes] > 0) { + /** + * The amount of memory needed to load the ML native code shared libraries. The assumption is that the first + * ML job to run on a given node will do this, and then subsequent ML jobs on the same node will reuse the + * same already-loaded code. + */ + memoryRes[key as keyof typeof memoryRes] += NATIVE_EXECUTABLE_CODE_OVERHEAD; + break; + } + } + + return { + id: nodeId, + ...nodeFields, + allocated_models: allocatedModels, + memory_overview: { + machine_memory: { + // TODO remove ts-ignore when elasticsearch client is updated + // @ts-ignore + total: Number(node.os?.mem.adjusted_total_in_bytes ?? node.os?.mem.total_in_bytes), + jvm: Number(node.attributes['ml.max_jvm_size']), + }, + anomaly_detection: { + total: memoryRes.adTotalMemory, + }, + dfa_training: { + total: memoryRes.dfaTotalMemory, + }, + trained_models: { + total: memoryRes.trainedModelsTotalMemory, + by_model: modelsMemoryUsage, + }, + }, + }; + } + ); + + return { + count: nodeDeploymentStatsResponses.length, + nodes: nodeDeploymentStatsResponses, + }; + }, }; } diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/validation.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/validation.ts index b39debbe664d3..436ca86b5a603 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/validation.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/validation.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IScopedClusterClient } from 'kibana/server'; import { getAnalysisType } from '../../../common/util/analytics_utils'; import { ANALYSIS_CONFIG_TYPE } from '../../../common/constants/data_frame_analytics'; diff --git a/x-pack/plugins/ml/server/models/filter/filter_manager.ts b/x-pack/plugins/ml/server/models/filter/filter_manager.ts index a2b71ae572170..3a0d7a706e69c 100644 --- a/x-pack/plugins/ml/server/models/filter/filter_manager.ts +++ b/x-pack/plugins/ml/server/models/filter/filter_manager.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import Boom from '@hapi/boom'; import type { MlClient } from '../../lib/ml_client'; diff --git a/x-pack/plugins/ml/server/models/job_audit_messages/job_audit_messages.ts b/x-pack/plugins/ml/server/models/job_audit_messages/job_audit_messages.ts index 69f5c8b36f10c..313b60a35aa6d 100644 --- a/x-pack/plugins/ml/server/models/job_audit_messages/job_audit_messages.ts +++ b/x-pack/plugins/ml/server/models/job_audit_messages/job_audit_messages.ts @@ -7,8 +7,8 @@ import moment from 'moment'; import type { IScopedClusterClient } from 'kibana/server'; -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; -import type { estypes } from '@elastic/elasticsearch'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ML_NOTIFICATION_INDEX_PATTERN } from '../../../common/constants/index_patterns'; import { MESSAGE_LEVEL } from '../../../common/constants/message_levels'; import type { JobSavedObjectService } from '../../saved_objects'; diff --git a/x-pack/plugins/ml/server/models/job_service/datafeeds.ts b/x-pack/plugins/ml/server/models/job_service/datafeeds.ts index 8b3f7f4b0b0ee..a699402f9b47a 100644 --- a/x-pack/plugins/ml/server/models/job_service/datafeeds.ts +++ b/x-pack/plugins/ml/server/models/job_service/datafeeds.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import { IScopedClusterClient } from 'kibana/server'; import { JOB_STATE, DATAFEED_STATE } from '../../../common/constants/states'; diff --git a/x-pack/plugins/ml/server/models/job_service/new_job/categorization/examples.ts b/x-pack/plugins/ml/server/models/job_service/new_job/categorization/examples.ts index 4f87e4698c032..a5510977d2ade 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job/categorization/examples.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job/categorization/examples.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IScopedClusterClient } from 'kibana/server'; import { chunk } from 'lodash'; diff --git a/x-pack/plugins/ml/server/models/job_service/new_job/categorization/top_categories.ts b/x-pack/plugins/ml/server/models/job_service/new_job/categorization/top_categories.ts index 87715d9d85dbf..03477b896d7c7 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job/categorization/top_categories.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job/categorization/top_categories.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { CategoryId, Category } from '../../../../../common/types/categories'; import type { MlClient } from '../../../../lib/ml_client'; diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts b/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts index a25b3183362b3..3682245b1b640 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts @@ -6,7 +6,7 @@ */ import { cloneDeep } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { IScopedClusterClient } from 'kibana/server'; import type { Field, FieldId, NewJobCaps, RollupFields } from '../../../../common/types/fields'; import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/common'; @@ -113,7 +113,7 @@ class FieldsService { this._mlClusterClient, this._dataViewsService ); - const rollupConfigs: estypes.RollupGetRollupCapabilitiesRollupCapabilitySummary[] | null = + const rollupConfigs: estypes.RollupGetRollupCapsRollupCapabilitySummary[] | null = await rollupService.getRollupJobs(); // if a rollup index has been specified, yet there are no @@ -137,7 +137,7 @@ class FieldsService { } function combineAllRollupFields( - rollupConfigs: estypes.RollupGetRollupCapabilitiesRollupCapabilitySummary[] + rollupConfigs: estypes.RollupGetRollupCapsRollupCapabilitySummary[] ): RollupFields { const rollupFields: RollupFields = {}; rollupConfigs.forEach((conf) => { diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts b/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts index 87504a1bc0e10..f0f9a53879962 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { IScopedClusterClient } from 'kibana/server'; import type { DataViewsService, @@ -29,7 +29,7 @@ export async function rollupServiceProvider( let jobIndexPatterns: string[] = [indexPattern]; async function getRollupJobs(): Promise< - estypes.RollupGetRollupCapabilitiesRollupCapabilitySummary[] | null + estypes.RollupGetRollupCapsRollupCapabilitySummary[] | null > { if ( rollupIndexPatternObject !== null && diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_influencers.ts b/x-pack/plugins/ml/server/models/job_validation/validate_influencers.ts index ad67cfb49ca6d..212beb1ebbd4a 100644 --- a/x-pack/plugins/ml/server/models/job_validation/validate_influencers.ts +++ b/x-pack/plugins/ml/server/models/job_validation/validate_influencers.ts @@ -38,7 +38,7 @@ export async function validateInfluencers(job: CombinedJob) { // detector using 'count' and no influencers and there shouldn't // be a warning about that. if ( - influencers.length === 0 && + influencers?.length === 0 && job.analysis_config.detectors.length === 1 && detectorFieldNames.length === 0 ) { @@ -46,6 +46,7 @@ export async function validateInfluencers(job: CombinedJob) { } if ( + // @ts-expect-error influencers is optional influencers.length <= INFLUENCER_LOW_THRESHOLD && detectorFieldNames.length >= DETECTOR_FIELD_NAMES_THRESHOLD ) { @@ -59,8 +60,10 @@ export async function validateInfluencers(job: CombinedJob) { } messages.push({ id, influencerSuggestion }); + // @ts-expect-error influencers is optional } else if (influencers.length <= INFLUENCER_LOW_THRESHOLD) { messages.push({ id: 'influencer_low' }); + // @ts-expect-error influencers is optional } else if (influencers.length >= INFLUENCER_HIGH_THRESHOLD) { messages.push({ id: 'influencer_high' }); } diff --git a/x-pack/plugins/ml/server/models/memory_overview/index.ts b/x-pack/plugins/ml/server/models/memory_overview/index.ts new file mode 100644 index 0000000000000..038b1cd8d4b80 --- /dev/null +++ b/x-pack/plugins/ml/server/models/memory_overview/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { memoryOverviewServiceProvider } from './memory_overview_service'; diff --git a/x-pack/plugins/ml/server/models/memory_overview/memory_overview_service.ts b/x-pack/plugins/ml/server/models/memory_overview/memory_overview_service.ts new file mode 100644 index 0000000000000..964e0ba595ecc --- /dev/null +++ b/x-pack/plugins/ml/server/models/memory_overview/memory_overview_service.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import numeral from '@elastic/numeral'; +import { keyBy } from 'lodash'; +import { MlClient } from '../../lib/ml_client'; + +export type MemoryOverviewService = ReturnType; + +export interface MlJobMemoryOverview { + job_id: string; + node_id: string; + model_size: number; +} + +const MB = Math.pow(2, 20); + +const AD_PROCESS_MEMORY_OVERHEAD = 10 * MB; +const DFA_PROCESS_MEMORY_OVERHEAD = 5 * MB; +export const NATIVE_EXECUTABLE_CODE_OVERHEAD = 30 * MB; + +/** + * Provides a service for memory overview across ML. + * @param mlClient + */ +export function memoryOverviewServiceProvider(mlClient: MlClient) { + return { + /** + * Retrieves memory consumed my started DFA jobs. + */ + async getDFAMemoryOverview(): Promise { + const { + body: { data_frame_analytics: dfaStats }, + } = await mlClient.getDataFrameAnalyticsStats(); + + const dfaMemoryReport = dfaStats + .filter((dfa) => dfa.state === 'started') + .map((dfa) => { + return { + node_id: dfa.node?.id, + job_id: dfa.id, + }; + }) as MlJobMemoryOverview[]; + + if (dfaMemoryReport.length === 0) { + return []; + } + + const dfaMemoryKeyByJobId = keyBy(dfaMemoryReport, 'job_id'); + + const { + body: { data_frame_analytics: startedDfaJobs }, + } = await mlClient.getDataFrameAnalytics({ + id: dfaMemoryReport.map((v) => v.job_id).join(','), + }); + + startedDfaJobs.forEach((dfa) => { + dfaMemoryKeyByJobId[dfa.id].model_size = + numeral( + dfa.model_memory_limit?.toUpperCase() + // @ts-ignore + ).value() + DFA_PROCESS_MEMORY_OVERHEAD; + }); + + return dfaMemoryReport; + }, + /** + * Retrieves memory consumed by opened Anomaly Detection jobs. + */ + async getAnomalyDetectionMemoryOverview(): Promise { + const { + body: { jobs: jobsStats }, + } = await mlClient.getJobStats(); + + return jobsStats + .filter((v) => v.state === 'opened') + .map((jobStats) => { + return { + node_id: jobStats.node.id, + model_size: jobStats.model_size_stats.model_bytes + AD_PROCESS_MEMORY_OVERHEAD, + job_id: jobStats.job_id, + }; + }); + }, + }; +} diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index efa61593655ac..d99beb20883b2 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -16,7 +16,6 @@ import type { CapabilitiesStart, IClusterClient, SavedObjectsServiceStart, - SharedGlobalConfig, UiSettingsServiceStart, } from 'kibana/server'; import type { SecurityPluginSetup } from '../../security/server'; @@ -82,14 +81,11 @@ export class MlServerPlugin private dataViews: DataViewsPluginStart | null = null; private isMlReady: Promise; private setMlReady: () => void = () => {}; - private readonly kibanaIndexConfig: SharedGlobalConfig; constructor(ctx: PluginInitializerContext) { this.log = ctx.logger.get(); this.mlLicense = new MlLicense(); this.isMlReady = new Promise((resolve) => (this.setMlReady = resolve)); - - this.kibanaIndexConfig = ctx.config.legacy.get(); } public setup(coreSetup: CoreSetup, plugins: PluginsSetup): MlPluginSetup { @@ -235,7 +231,7 @@ export class MlServerPlugin } if (plugins.usageCollection) { - registerCollector(plugins.usageCollection, this.kibanaIndexConfig.kibana.index); + registerCollector(plugins.usageCollection, coreSetup.savedObjects.getKibanaIndex()); } return sharedServicesProviders; diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index 30aae3c0fb550..4e222e05c1b19 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { wrapError } from '../client/error_wrapper'; import { RouteInitialization } from '../types'; @@ -221,6 +221,7 @@ export function jobRoutes({ router, routeGuard }: RouteInitialization) { const { jobId } = request.params; const { body } = await mlClient.updateJob({ job_id: jobId, + // @ts-expect-error MlDetector is not compatible body: request.body, }); return response.ok({ diff --git a/x-pack/plugins/ml/server/routes/apidoc.json b/x-pack/plugins/ml/server/routes/apidoc.json index 226b69e06b48a..77e5443d0a257 100644 --- a/x-pack/plugins/ml/server/routes/apidoc.json +++ b/x-pack/plugins/ml/server/routes/apidoc.json @@ -123,7 +123,7 @@ "GetJobAuditMessages", "GetAllJobAuditMessages", "ClearJobAuditMessages", - + "JobValidation", "EstimateBucketSpan", "CalculateModelMemoryLimit", @@ -160,7 +160,11 @@ "TrainedModels", "GetTrainedModel", "GetTrainedModelStats", + "GetTrainedModelDeploymentStats", + "GetTrainedModelsNodesOverview", "GetTrainedModelPipelines", + "StartTrainedModelDeployment", + "StopTrainedModelDeployment", "DeleteTrainedModel", "Alerting", diff --git a/x-pack/plugins/ml/server/routes/datafeeds.ts b/x-pack/plugins/ml/server/routes/datafeeds.ts index 9f908bf61a35d..c3414b2fbc55c 100644 --- a/x-pack/plugins/ml/server/routes/datafeeds.ts +++ b/x-pack/plugins/ml/server/routes/datafeeds.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { wrapError } from '../client/error_wrapper'; import { RouteInitialization } from '../types'; import { diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 15b0b4449590c..96ca56baa38da 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { wrapError } from '../client/error_wrapper'; import type { RouteInitialization } from '../types'; diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index 106010d0f7550..a20a97a3fcb42 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -14,6 +14,7 @@ import { } from './schemas/inference_schema'; import { modelsProvider } from '../models/data_frame_analytics'; import { TrainedModelConfigResponse } from '../../common/types/trained_models'; +import { memoryOverviewServiceProvider } from '../models/memory_overview'; export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) { /** @@ -44,6 +45,8 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) ...query, ...(modelId ? { model_id: modelId } : {}), }); + // model_type is missing + // @ts-ignore const result = body.trained_model_configs as TrainedModelConfigResponse[]; try { if (withPipelines) { @@ -57,7 +60,7 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) ) ); - const pipelinesResponse = await modelsProvider(client).getModelsPipelines( + const pipelinesResponse = await modelsProvider(client, mlClient).getModelsPipelines( modelIdsAndAliases ); for (const model of result) { @@ -136,10 +139,12 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) tags: ['access:ml:canGetDataFrameAnalytics'], }, }, - routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => { + routeGuard.fullLicenseAPIGuard(async ({ client, request, mlClient, response }) => { try { const { modelId } = request.params; - const result = await modelsProvider(client).getModelsPipelines(modelId.split(',')); + const result = await modelsProvider(client, mlClient).getModelsPipelines( + modelId.split(',') + ); return response.ok({ body: [...result].map(([id, pipelines]) => ({ model_id: id, pipelines })), }); @@ -180,4 +185,132 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) } }) ); + + /** + * @apiGroup TrainedModels + * + * @api {get} /api/ml/trained_models/nodes_overview Get node overview about the models allocation + * @apiName GetTrainedModelsNodesOverview + * @apiDescription Retrieves the list of ML nodes with memory breakdown and allocated models info + */ + router.get( + { + path: '/api/ml/trained_models/nodes_overview', + validate: {}, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => { + try { + const memoryOverviewService = memoryOverviewServiceProvider(mlClient); + const result = await modelsProvider( + client, + mlClient, + memoryOverviewService + ).getNodesOverview(); + return response.ok({ + body: result, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup TrainedModels + * + * @api {post} /api/ml/trained_models/:modelId/deployment/_start Start trained model deployment + * @apiName StartTrainedModelDeployment + * @apiDescription Starts trained model deployment. + */ + router.post( + { + path: '/api/ml/trained_models/{modelId}/deployment/_start', + validate: { + params: modelIdSchema, + }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { + try { + const { modelId } = request.params; + const { body } = await mlClient.startTrainedModelDeployment({ + model_id: modelId, + }); + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup TrainedModels + * + * @api {post} /api/ml/trained_models/:modelId/deployment/_stop Stop trained model deployment + * @apiName StopTrainedModelDeployment + * @apiDescription Stops trained model deployment. + */ + router.post( + { + path: '/api/ml/trained_models/{modelId}/deployment/_stop', + validate: { + params: modelIdSchema, + }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { + try { + const { modelId } = request.params; + const { body } = await mlClient.stopTrainedModelDeployment({ + model_id: modelId, + }); + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup TrainedModels + * + * @api {get} /api/ml/trained_models/:modelId/deployment/_stats Get trained model deployment stats + * @apiName GetTrainedModelDeploymentStats + * @apiDescription Gets trained model deployment stats. + */ + router.get( + { + path: '/api/ml/trained_models/{modelId}/deployment/_stats', + validate: { + params: modelIdSchema, + }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { + try { + const { modelId } = request.params; + const { body } = await mlClient.getTrainedModelDeploymentStats({ + model_id: modelId, + }); + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); } diff --git a/x-pack/plugins/ml/server/shared_services/providers/system.ts b/x-pack/plugins/ml/server/shared_services/providers/system.ts index 85cd73ba010af..b198e5d8345f0 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/system.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/system.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; import { MlLicense } from '../../../common/license'; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx index c51027636b287..1982b7de87cae 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx @@ -87,7 +87,13 @@ export const ElasticsearchIndexAdvancedPage: React.FC = ({ clust }, [clusterUuid, services.data?.query.timefilter.timefilter, services.http, index]); return ( - + ( diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx index 1f56ea22839e2..cf9b5628222f4 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx @@ -46,7 +46,7 @@ export const LogStashPipelinePage: React.FC = ({ clusters }) => cluster_uuid: clusterUuid, }) as any; const [data, setData] = useState({} as any); - const [detailVertexId, setDetailVertexId] = useState(null); + const [detailVertexId, setDetailVertexId] = useState(undefined); const { updateTotalItemCount } = useTable('logstash.pipelines'); const title = i18n.translate('xpack.monitoring.logstash.pipeline.routeTitle', { @@ -128,18 +128,19 @@ export const LogStashPipelinePage: React.FC = ({ clusters }) => const timeseriesTooltipXValueFormatter = (xValue: any) => moment(xValue).format(dateFormat); const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); - const onVertexChange = useCallback( - (vertex: any) => { - if (!vertex) { - setDetailVertexId(null); - } else { - setDetailVertexId(vertex.id); - } + const onVertexChange = useCallback((vertex: any) => { + if (!vertex) { + setDetailVertexId(null); + } else { + setDetailVertexId(vertex.id); + } + }, []); + useEffect(() => { + if (detailVertexId !== undefined) { getPageData(); - }, - [getPageData] - ); + } + }, [detailVertexId, getPageData]); const onChangePipelineHash = useCallback(() => { window.location.hash = getSafeForExternalLink( diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap index faaf0762dbc7a..3647945c094cb 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap @@ -136,6 +136,8 @@ exports[`CcrShard that it renders normally 1`] = ` } + buttonElement="button" + element="div" id="ccrLatestStat" initialIsOpen={false} isLoading={false} diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_es_usage.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_es_usage.ts index 1fb2ba70f2ab1..884b4e6466e60 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_es_usage.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_es_usage.ts @@ -7,7 +7,7 @@ import { ElasticsearchClient } from 'src/core/server'; import { get } from 'lodash'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { StackProductUsage } from '../types'; interface ESIndicesBucket { diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_license_type.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_license_type.ts index f42623ff851ce..0f0d75546d28d 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_license_type.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_license_type.ts @@ -7,7 +7,7 @@ import { get } from 'lodash'; import { ElasticsearchClient } from 'src/core/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../common/constants'; import { getCcsIndexPattern } from '../../../lib/alerts/get_ccs_index_pattern'; diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts index 0d3aab8283688..bcb872912394c 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts @@ -7,7 +7,7 @@ import { get } from 'lodash'; import { ElasticsearchClient } from 'src/core/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { MonitoringConfig } from '../../../config'; // @ts-ignore import { prefixIndexPattern } from '../../../../common/ccs_utils'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts index ca8270590da54..19d6168dbb5d0 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts index 08ecaef33085b..2739e23245bde 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchClusterHealth } from './fetch_cluster_health'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts index 75991e892d419..c46ec424b2cd3 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts index 8f0083f1f533f..a67a5e679cc33 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchCpuUsageNodeStats } from './fetch_cpu_usage_node_stats'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts index d105174853636..515fa3b2442d3 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts @@ -9,7 +9,7 @@ import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchElasticsearchVersions } from './fetch_elasticsearch_versions'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; describe('fetchElasticsearchVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts index 3c12c70bf1713..538e24a764276 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts @@ -8,7 +8,7 @@ import { fetchLicenses } from './fetch_licenses'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; describe('fetchLicenses', () => { const clusterName = 'MyCluster'; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.test.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.test.ts index 8b2ea8459e26c..985ad2357648a 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.test.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ClusterGetSettingsResponse } from '@elastic/elasticsearch/api/types'; +import { ClusterGetSettingsResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { checkClusterSettings } from '.'; import { LegacyRequest } from '../../types'; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.ts index 4f46f65591d62..b474cca59519e 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.ts @@ -6,7 +6,7 @@ */ import { get } from 'lodash'; -import { ClusterGetSettingsResponse } from '@elastic/elasticsearch/api/types'; +import { ClusterGetSettingsResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { findReason } from './find_reason'; import { ClusterSettingsReasonResponse, LegacyRequest } from '../../types'; diff --git a/x-pack/plugins/monitoring/server/lib/errors/auth_errors.test.ts b/x-pack/plugins/monitoring/server/lib/errors/auth_errors.test.ts index e9f3eb8efc4d7..06883a47f2ca3 100644 --- a/x-pack/plugins/monitoring/server/lib/errors/auth_errors.test.ts +++ b/x-pack/plugins/monitoring/server/lib/errors/auth_errors.test.ts @@ -6,7 +6,7 @@ */ import { forbidden, unauthorized } from '@hapi/boom'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { isAuthError, handleAuthError } from './auth_errors'; describe('Error handling for 401/403 errors', () => { @@ -59,7 +59,7 @@ describe('Error handling for 401/403 errors', () => { describe('Elasticsearch errors', () => { it('handles Forbidden error defined by ElasticsearchJS', () => { - const err = new ResponseError({ + const err = new errors.ResponseError({ statusCode: 401, body: { error: { @@ -91,7 +91,7 @@ describe('Error handling for 401/403 errors', () => { }); it('handles Unauthorized error defined by ElasticsearchJS', () => { - const err = new ResponseError({ + const err = new errors.ResponseError({ statusCode: 403, body: { error: { diff --git a/x-pack/plugins/monitoring/server/lib/errors/esclient_errors.ts b/x-pack/plugins/monitoring/server/lib/errors/esclient_errors.ts index 5994c3048dae8..1b83b8e4e7eb6 100644 --- a/x-pack/plugins/monitoring/server/lib/errors/esclient_errors.ts +++ b/x-pack/plugins/monitoring/server/lib/errors/esclient_errors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClientError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { boomify } from '@hapi/boom'; import { i18n } from '@kbn/i18n'; import { ErrorTypes } from '../../types'; @@ -38,12 +38,12 @@ const mapTypeMessage: { [key: string]: string } = { }; export function isESClientError(err: ErrorTypes) { - if (err instanceof ElasticsearchClientError === false) return false; + if (err instanceof errors.ElasticsearchClientError === false) return false; const knownTypes = Object.keys(mapTypeMessage); return knownTypes.includes(err.constructor.name); } -export function handleESClientError(err: ElasticsearchClientError) { +export function handleESClientError(err: errors.ElasticsearchClientError) { err.message = mapTypeMessage[err.constructor.name]; return boomify(err, { statusCode: 503 }); } diff --git a/x-pack/plugins/monitoring/server/lib/errors/handle_error.ts b/x-pack/plugins/monitoring/server/lib/errors/handle_error.ts index 3fe3b28034b2c..cc5fde228120e 100644 --- a/x-pack/plugins/monitoring/server/lib/errors/handle_error.ts +++ b/x-pack/plugins/monitoring/server/lib/errors/handle_error.ts @@ -6,7 +6,7 @@ */ import { boomify, isBoom } from '@hapi/boom'; -import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { isCustomError, handleCustomError } from './custom_errors'; import { isAuthError, handleAuthError } from './auth_errors'; import { ErrorTypes, LegacyRequest } from '../../types'; @@ -15,7 +15,7 @@ import { handleESClientError, isESClientError } from './esclient_errors'; export const getStatusCode = (err: ErrorTypes) => { return isBoom(err) ? err.output.statusCode - : err instanceof ResponseError + : err instanceof errors.ResponseError ? err.statusCode : undefined; }; diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 25fffd94d86a4..557a9b5e2a3d2 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -104,7 +104,7 @@ export class MonitoringPlugin kibanaStats: { uuid: this.initializerContext.env.instanceUuid, name: serverInfo.name, - index: this.legacyConfig.kibana.index, + index: coreSetup.savedObjects.getKibanaIndex(), host: serverInfo.hostname, locale: i18n.getLocale(), port: serverInfo.port.toString(), diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts index 3cd2b8b73b315..eee6ba98e62c7 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { RequestHandlerContext } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { INDEX_PATTERN_ELASTICSEARCH, INDEX_PATTERN_KIBANA, diff --git a/x-pack/plugins/monitoring/server/static_globals.ts b/x-pack/plugins/monitoring/server/static_globals.ts index fc4ece3231486..ac0cab7a68388 100644 --- a/x-pack/plugins/monitoring/server/static_globals.ts +++ b/x-pack/plugins/monitoring/server/static_globals.ts @@ -13,7 +13,7 @@ import { PluginInitializerContext, } from 'kibana/server'; import url from 'url'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { MonitoringConfig } from './config'; import { PluginsSetup } from './types'; import { mbSafeQuery } from './lib/mb_safe_query'; diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts index 00dba8b727883..8da551a923f04 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts @@ -7,7 +7,7 @@ import { get } from 'lodash'; import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createQuery } from './create_query'; import { INDEX_PATTERN_BEATS } from '../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts index 7cf4ca2b94ce0..eda038ac19395 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts @@ -8,7 +8,7 @@ import { get } from 'lodash'; import moment from 'moment'; import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createQuery } from './create_query'; import { INDEX_PATTERN_ELASTICSEARCH, diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts index 92aa48cbe90ef..8155c0080e44e 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; /** diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts index 5f14ebb815bab..79c38c4d15a87 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts @@ -7,7 +7,7 @@ import { get } from 'lodash'; import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createQuery } from './create_query'; import { INDEX_PATTERN_KIBANA, diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts index cd037fa062ed8..5474880986238 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getUsageStats, combineStats, diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts index 8313bcc9f5464..df8354716a0c8 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts @@ -7,7 +7,7 @@ import moment from 'moment'; import { isEmpty } from 'lodash'; -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from 'kibana/server'; import { KIBANA_SYSTEM_ID, TELEMETRY_COLLECTION_INTERVAL } from '../../common/constants'; import { diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts index 514b04bf1a0e7..d70bfdfd70ad6 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ESLicense } from '../../../telemetry_collection_xpack/server'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_logstash_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_logstash_stats.ts index 306c9b6201557..736c61130bc67 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_logstash_stats.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_logstash_stats.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from 'kibana/server'; -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createQuery } from './create_query'; import { mapToList } from './get_high_level_stats'; import { incrementByKey } from './get_high_level_stats'; diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 416d1ac7c3d86..14071aafaea12 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -14,7 +14,7 @@ import type { ElasticsearchClient, } from 'kibana/server'; import type Boom from '@hapi/boom'; -import { ElasticsearchClientError, ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { LicenseFeature, ILicense } from '../../licensing/server'; import type { @@ -180,7 +180,7 @@ export interface ClusterSettingsReasonResponse { }; } -export type ErrorTypes = Error | Boom.Boom | ResponseError | ElasticsearchClientError; +export type ErrorTypes = Error | Boom.Boom | errors.ResponseError | errors.ElasticsearchClientError; export type Pipeline = { id: string; diff --git a/x-pack/plugins/observability/common/utils/unwrap_es_response.ts b/x-pack/plugins/observability/common/utils/unwrap_es_response.ts index 81f8be4e0f696..d2c97eb0ba25a 100644 --- a/x-pack/plugins/observability/common/utils/unwrap_es_response.ts +++ b/x-pack/plugins/observability/common/utils/unwrap_es_response.ts @@ -4,20 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ElasticsearchClientError, ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { errors } from '@elastic/elasticsearch'; import type { UnwrapPromise } from '@kbn/utility-types'; import { inspect } from 'util'; export class WrappedElasticsearchClientError extends Error { - originalError: ElasticsearchClientError; - constructor(originalError: ElasticsearchClientError) { + originalError: errors.ElasticsearchClientError; + constructor(originalError: errors.ElasticsearchClientError) { super(originalError.message); const stack = this.stack; this.originalError = originalError; - if (originalError instanceof ResponseError) { + if (originalError instanceof errors.ResponseError) { // make sure ES response body is visible when logged to the console // @ts-expect-error this.stack = { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx index 03fd23631f755..097ea89826c38 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx @@ -12,7 +12,8 @@ import { FilterLabel } from './filter_label'; import * as useSeriesHook from '../hooks/use_series_filters'; import { buildFilterLabel } from '../../filter_value_label/filter_value_label'; -describe('FilterLabel', function () { +// FLAKY: https://github.com/elastic/kibana/issues/115324 +describe.skip('FilterLabel', function () { mockAppIndexPattern(); const invertFilter = jest.fn(); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/use_filter_values.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/use_filter_values.ts index e84f79f88298c..d27e3ec98287e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/use_filter_values.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/use_filter_values.ts @@ -5,7 +5,7 @@ * 2.0. */ import { ExistsFilter, isExistsFilter } from '@kbn/es-query'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useValuesList } from '../../../../hooks/use_values_list'; import { FilterProps } from './columns/filter_expanded'; import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; @@ -25,7 +25,7 @@ export function useFilterValues( queryFilters.push(qFilter.query); } if (isExistsFilter(qFilter)) { - queryFilters.push({ exists: qFilter.query.exists } as QueryDslQueryContainer); + queryFilters.push({ exists: qFilter.query.exists } as estypes.QueryDslQueryContainer); } }); diff --git a/x-pack/plugins/observability/public/hooks/use_es_search.ts b/x-pack/plugins/observability/public/hooks/use_es_search.ts index bf96cf2c1f2c5..94126d6c1540e 100644 --- a/x-pack/plugins/observability/public/hooks/use_es_search.ts +++ b/x-pack/plugins/observability/public/hooks/use_es_search.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { ESSearchResponse } from '../../../../../src/core/types/elasticsearch'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx new file mode 100644 index 0000000000000..6a57b08bf8d38 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLink, EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export function AlertsDisclaimer() { + return ( + + + {i18n.translate('xpack.observability.alertsDisclaimerLinkText', { + defaultMessage: 'feedback', + })} + + ), + }} + /> + + ); +} diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx index 7171daa4a56e3..034b7522b9136 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx @@ -46,6 +46,7 @@ import { asDuration } from '../../../../common/utils/formatters'; import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; import { parseAlert } from '../parse_alert'; import { AlertStatusIndicator } from '../../../components/shared/alert_status_indicator'; +import { ExperimentalBadge } from '../../../components/shared/experimental_badge'; type AlertsFlyoutProps = { alert?: TopAlert; @@ -137,6 +138,8 @@ export function AlertsFlyout({ return ( + +

{alertData.fields[ALERT_RULE_NAME]}

diff --git a/x-pack/plugins/observability/public/pages/alerts/index.tsx b/x-pack/plugins/observability/public/pages/alerts/index.tsx index e8b550ac353a6..a3c060f5dc5df 100644 --- a/x-pack/plugins/observability/public/pages/alerts/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/index.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import { EuiButtonEmpty, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + import { IndexPatternBase } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import React, { useCallback, useRef } from 'react'; @@ -26,6 +27,7 @@ import { AlertsTableTGrid } from './alerts_table_t_grid'; import { Provider, alertsPageStateContainer, useAlertsPageStateContainer } from './state_container'; import './styles.scss'; import { WorkflowStatusFilter } from './workflow_status_filter'; +import { AlertsDisclaimer } from './alerts_disclaimer'; export interface TopAlert { fields: ParsedTechnicalFields; @@ -177,25 +179,7 @@ function AlertsPage() { > - -

- {i18n.translate('xpack.observability.alertsDisclaimerText', { - defaultMessage: - 'This page shows an experimental list of alerts. The data might not be accurate. All alerts are available in the ', - })} - - {i18n.translate('xpack.observability.alertsDisclaimerLinkText', { - defaultMessage: 'Rules and Connectors settings.', - })} - -

-
+
= ({ policyId } const { application: { getUrlForApp, navigateToApp }, } = useKibana().services; - const { data } = useAgentPolicy({ policyId }); const href = useMemo( () => getUrlForApp(PLUGIN_ID, { - path: `#` + pagePathGetters.policy_details({ policyId })[1], + path: pagePathGetters.policy_details({ policyId })[1], }), [getUrlForApp, policyId] ); @@ -45,7 +44,7 @@ const AgentsPolicyLinkComponent: React.FC = ({ policyId } event.preventDefault(); return navigateToApp(PLUGIN_ID, { - path: `#` + pagePathGetters.policy_details({ policyId })[1], + path: pagePathGetters.policy_details({ policyId })[1], }); } }, diff --git a/x-pack/plugins/osquery/public/agents/agent_id_to_name.tsx b/x-pack/plugins/osquery/public/agents/agent_id_to_name.tsx index e46d233244059..9c6d2c4947ea6 100644 --- a/x-pack/plugins/osquery/public/agents/agent_id_to_name.tsx +++ b/x-pack/plugins/osquery/public/agents/agent_id_to_name.tsx @@ -25,7 +25,7 @@ const AgentIdToNameComponent: React.FC = ({ agentId }) => { diff --git a/x-pack/plugins/osquery/public/agents/agents_table.tsx b/x-pack/plugins/osquery/public/agents/agents_table.tsx index c99d5a0454f82..a4fee25dfcd9a 100644 --- a/x-pack/plugins/osquery/public/agents/agents_table.tsx +++ b/x-pack/plugins/osquery/public/agents/agents_table.tsx @@ -43,7 +43,7 @@ interface AgentsTableProps { } const perPage = 10; -const DEBOUNCE_DELAY = 100; // ms +const DEBOUNCE_DELAY = 300; // ms const AgentsTableComponent: React.FC = ({ agentSelection, onChange }) => { // search related diff --git a/x-pack/plugins/osquery/public/agents/helpers.ts b/x-pack/plugins/osquery/public/agents/helpers.ts index 1b9ac9cedcee2..1b0ae182070de 100644 --- a/x-pack/plugins/osquery/public/agents/helpers.ts +++ b/x-pack/plugins/osquery/public/agents/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { euiPaletteColorBlindBehindText } from '@elastic/eui'; import { PaginationInputPaginated, diff --git a/x-pack/plugins/osquery/public/agents/types.ts b/x-pack/plugins/osquery/public/agents/types.ts index bfe59c91d007d..9a4d4c7ff18cc 100644 --- a/x-pack/plugins/osquery/public/agents/types.ts +++ b/x-pack/plugins/osquery/public/agents/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiComboBoxOptionOption } from '@elastic/eui'; import { Agent } from '../../common/shared_imports'; diff --git a/x-pack/plugins/osquery/public/agents/use_agent_policies.ts b/x-pack/plugins/osquery/public/agents/use_agent_policies.ts index e8d6fe7eb97ac..cdccd3aa21af8 100644 --- a/x-pack/plugins/osquery/public/agents/use_agent_policies.ts +++ b/x-pack/plugins/osquery/public/agents/use_agent_policies.ts @@ -22,8 +22,8 @@ export const useAgentPolicies = (policyIds: string[] = []) => { queryFn: () => http.get(`/internal/osquery/fleet_wrapper/agent_policies/${policyId}`), enabled: policyIds.length > 0, onSuccess: () => setErrorToast(), - onError: (error) => - setErrorToast(error as Error, { + onError: (error: Error) => + setErrorToast(error, { title: i18n.translate('xpack.osquery.action_policy_details.fetchError', { defaultMessage: 'Error while fetching policy details', }), diff --git a/x-pack/plugins/osquery/public/agents/use_all_agents.ts b/x-pack/plugins/osquery/public/agents/use_all_agents.ts index 42e4954989c66..03660a970aeef 100644 --- a/x-pack/plugins/osquery/public/agents/use_all_agents.ts +++ b/x-pack/plugins/osquery/public/agents/use_all_agents.ts @@ -35,7 +35,7 @@ export const useAllAgents = ( return useQuery( ['agents', osqueryPolicies, searchValue, perPage], () => { - let kuery = `${osqueryPolicies.map((p) => `policy_id:${p}`).join(' or ')}`; + let kuery = `(${osqueryPolicies.map((p) => `policy_id:${p}`).join(' or ')})`; if (searchValue) { kuery += ` and (local_metadata.host.hostname:*${searchValue}* or local_metadata.elastic.agent.id:*${searchValue}*)`; @@ -54,10 +54,13 @@ export const useAllAgents = ( enabled: !osqueryPoliciesLoading && osqueryPolicies.length > 0, onSuccess: () => setErrorToast(), onError: (error) => - setErrorToast(error as Error, { + // @ts-expect-error update types + setErrorToast(error?.body, { title: i18n.translate('xpack.osquery.agents.fetchError', { defaultMessage: 'Error while fetching agents', }), + // @ts-expect-error update types + toastMessage: error?.body?.error, }), } ); diff --git a/x-pack/plugins/osquery/public/common/schemas/osquery/v5.0.1.json b/x-pack/plugins/osquery/public/common/schemas/osquery/v5.0.1.json index e995062462022..ef44a10db9dff 100644 --- a/x-pack/plugins/osquery/public/common/schemas/osquery/v5.0.1.json +++ b/x-pack/plugins/osquery/public/common/schemas/osquery/v5.0.1.json @@ -1 +1 @@ -[{"name":"account_policy_data","description":"Additional OS X user account data from the AccountPolicy section of OpenDirectory.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the account was first created","type":"double","hidden":false,"required":false,"index":false},{"name":"failed_login_count","description":"The number of failed login attempts using an incorrect password. Count resets after a correct password is entered.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"failed_login_timestamp","description":"The time of the last failed login attempt. Resets after a correct password is entered","type":"double","hidden":false,"required":false,"index":false},{"name":"password_last_set_time","description":"The time the password was last changed","type":"double","hidden":false,"required":false,"index":false}]},{"name":"acpi_tables","description":"Firmware ACPI functional table common metadata and content.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"ACPI table name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of compiled table data","type":"integer","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table content","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ad_config","description":"OS X Active Directory configuration.","platforms":["darwin"],"columns":[{"name":"name","description":"The OS X-specific configuration name","type":"text","hidden":false,"required":false,"index":false},{"name":"domain","description":"Active Directory trust domain","type":"text","hidden":false,"required":false,"index":false},{"name":"option","description":"Canonical name of option","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Variable typed option value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"alf","description":"OS X application layer firewall (ALF) service details.","platforms":["darwin"],"columns":[{"name":"allow_signed_enabled","description":"1 If allow signed mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"firewall_unload","description":"1 If firewall unloading enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"global_state","description":"1 If the firewall is enabled with exceptions, 2 if the firewall is configured to block all incoming connections, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_enabled","description":"1 If logging mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_option","description":"Firewall logging option","type":"integer","hidden":false,"required":false,"index":false},{"name":"stealth_enabled","description":"1 If stealth mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Application Layer Firewall version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"alf_exceptions","description":"OS X application layer firewall (ALF) service exceptions.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to the executable that is excepted","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Firewall exception state","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"alf_explicit_auths","description":"ALF services explicitly allowed to perform networking.","platforms":["darwin"],"columns":[{"name":"process","description":"Process name explicitly allowed","type":"text","hidden":false,"required":false,"index":false}]},{"name":"app_schemes","description":"OS X application schemes and handlers (e.g., http, file, mailto).","platforms":["darwin"],"columns":[{"name":"scheme","description":"Name of the scheme/protocol","type":"text","hidden":false,"required":false,"index":false},{"name":"handler","description":"Application label for the handler","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this handler is the OS default, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"external","description":"1 if this handler does NOT exist on OS X by default, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"protected","description":"1 if this handler is protected (reserved) by OS X, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"apparmor_events","description":"Track AppArmor events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Raw audit message","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"apparmor","description":"Apparmor Status like ALLOWED, DENIED etc.","type":"text","hidden":false,"required":false,"index":false},{"name":"operation","description":"Permission requested by the process","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process PID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"profile","description":"Apparmor profile name","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"denied_mask","description":"Denied permissions for the process","type":"text","hidden":false,"required":false,"index":false},{"name":"capname","description":"Capability requested by the process","type":"text","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"ouid","description":"Object owner's user ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"capability","description":"Capability number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"requested_mask","description":"Requested access mask","type":"text","hidden":false,"required":false,"index":false},{"name":"info","description":"Additional information","type":"text","hidden":false,"required":false,"index":false},{"name":"error","description":"Error information","type":"text","hidden":false,"required":false,"index":false},{"name":"namespace","description":"AppArmor namespace","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"AppArmor label","type":"text","hidden":false,"required":false,"index":false}]},{"name":"apparmor_profiles","description":"Track active AppArmor profiles.","platforms":["linux"],"columns":[{"name":"path","description":"Unique, aa-status compatible, policy identifier.","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy name.","type":"text","hidden":false,"required":false,"index":false},{"name":"attach","description":"Which executable(s) a profile will attach to.","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"How the policy is applied.","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"A unique hash that identifies this policy.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"appcompat_shims","description":"Application Compatibility shims are a way to persist malware. This table presents the AppCompat Shim information from the registry in a nice format. See http://files.brucon.org/2015/Tomczak_and_Ballenthin_Shims_for_the_Win.pdf for more details.","platforms":["windows"],"columns":[{"name":"executable","description":"Name of the executable that is being shimmed. This is pulled from the registry.","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the SDB database.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the SDB.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Install time of the SDB","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the SDB database.","type":"text","hidden":false,"required":false,"index":false},{"name":"sdb_id","description":"Unique GUID of the SDB.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"apps","description":"OS X applications installed in known search paths (e.g., /Applications).","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the Name.app folder","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute and full Name.app path","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_executable","description":"Info properties CFBundleExecutable label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"Info properties CFBundleIdentifier label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_name","description":"Info properties CFBundleName label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_short_version","description":"Info properties CFBundleShortVersionString label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_version","description":"Info properties CFBundleVersion label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_package_type","description":"Info properties CFBundlePackageType label","type":"text","hidden":false,"required":false,"index":false},{"name":"environment","description":"Application-set environment variables","type":"text","hidden":false,"required":false,"index":false},{"name":"element","description":"Does the app identify as a background agent","type":"text","hidden":false,"required":false,"index":false},{"name":"compiler","description":"Info properties DTCompiler label","type":"text","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Info properties CFBundleDevelopmentRegion label","type":"text","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Info properties CFBundleDisplayName label","type":"text","hidden":false,"required":false,"index":false},{"name":"info_string","description":"Info properties CFBundleGetInfoString label","type":"text","hidden":false,"required":false,"index":false},{"name":"minimum_system_version","description":"Minimum version of OS X required for the app to run","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The UTI that categorizes the app for the App Store","type":"text","hidden":false,"required":false,"index":false},{"name":"applescript_enabled","description":"Info properties NSAppleScriptEnabled label","type":"text","hidden":false,"required":false,"index":false},{"name":"copyright","description":"Info properties NSHumanReadableCopyright label","type":"text","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"The time that the app was last used","type":"double","hidden":false,"required":false,"index":false}]},{"name":"apt_sources","description":"Current list of APT repositories or software channels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Repository name","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source file","type":"text","hidden":false,"required":false,"index":false},{"name":"base_uri","description":"Repository base URI","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"Release name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Repository source version","type":"text","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Repository maintainer","type":"text","hidden":false,"required":false,"index":false},{"name":"components","description":"Repository components","type":"text","hidden":false,"required":false,"index":false},{"name":"architectures","description":"Repository architectures","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"arp_cache","description":"Address resolution cache, both static and dynamic (from ARP, NDP).","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"address","description":"IPv4 address target","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address of broadcasted address","type":"text","hidden":false,"required":false,"index":false},{"name":"interface","description":"Interface of the network for the MAC","type":"text","hidden":false,"required":false,"index":false},{"name":"permanent","description":"1 for true, 0 for false","type":"text","hidden":false,"required":false,"index":false}]},{"name":"asl","description":"Queries the Apple System Log data structure for system events.","platforms":["darwin"],"columns":[{"name":"time","description":"Unix timestamp. Set automatically","type":"integer","hidden":false,"required":false,"index":false},{"name":"time_nano_sec","description":"Nanosecond time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"host","description":"Sender's address (set by the server).","type":"text","hidden":false,"required":false,"index":false},{"name":"sender","description":"Sender's identification string. Default is process name.","type":"text","hidden":false,"required":false,"index":false},{"name":"facility","description":"Sender's facility. Default is 'user'.","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Sending process ID encoded as a string. Set automatically.","type":"integer","hidden":false,"required":false,"index":false},{"name":"gid","description":"GID that sent the log message (set by the server).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"UID that sent the log message (set by the server).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"level","description":"Log level number. See levels in asl.h.","type":"integer","hidden":false,"required":false,"index":false},{"name":"message","description":"Message text.","type":"text","hidden":false,"required":false,"index":false},{"name":"ref_pid","description":"Reference PID for messages proxied by launchd","type":"integer","hidden":false,"required":false,"index":false},{"name":"ref_proc","description":"Reference process for messages proxied by launchd","type":"text","hidden":false,"required":false,"index":false},{"name":"extra","description":"Extra columns, in JSON format. Queries against this column are performed entirely in SQLite, so do not benefit from efficient querying via asl.h.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"atom_packages","description":"Lists all atom packages in a directory or globally installed in a system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Package's package.json path","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the plugin","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"augeas","description":"Configuration files parsed by augeas.","platforms":["darwin","linux"],"columns":[{"name":"node","description":"The node path of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"The label of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path to the configuration file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authenticode","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"original_program_name","description":"The original program name that the publisher has signed","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_name","description":"The certificate issuer name","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_name","description":"The certificate subject name","type":"text","hidden":false,"required":false,"index":false},{"name":"result","description":"The signature check result","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorization_mechanisms","description":"OS X Authorization mechanisms database.","platforms":["darwin"],"columns":[{"name":"label","description":"Label of the authorization right","type":"text","hidden":false,"required":false,"index":false},{"name":"plugin","description":"Authorization plugin name","type":"text","hidden":false,"required":false,"index":false},{"name":"mechanism","description":"Name of the mechanism that will be called","type":"text","hidden":false,"required":false,"index":false},{"name":"privileged","description":"If privileged it will run as root, else as an anonymous user","type":"text","hidden":false,"required":false,"index":false},{"name":"entry","description":"The whole string entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorizations","description":"OS X Authorization rights database.","platforms":["darwin"],"columns":[{"name":"label","description":"Item name, usually in reverse domain format","type":"text","hidden":false,"required":false,"index":false},{"name":"modified","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"allow_root","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"timeout","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"tries","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"authenticate_user","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"shared","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"session_owner","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorized_keys","description":"A line-delimited authorized_keys table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local owner of authorized_keys file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"algorithm","description":"algorithm of key","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"parsed authorized keys line","type":"text","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to the authorized_keys file","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"autoexec","description":"Aggregate of executables that will automatically execute on the target machine. This is an amalgamation of other tables like services, scheduled_tasks, startup_items and more.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the executable","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the program","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source table of the autoexec item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_metadata","description":"Azure instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"location","description":"Azure Region the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"offer","description":"Offer information for the VM image (Azure image gallery VMs only)","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Publisher of the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"sku","description":"SKU for the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Linux or Windows","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_update_domain","description":"Update domain the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_fault_domain","description":"Fault domain the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_size","description":"VM size","type":"text","hidden":false,"required":false,"index":false},{"name":"subscription_id","description":"Azure subscription for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"resource_group_name","description":"Resource group for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"placement_group_id","description":"Placement group for the VM scale set","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_scale_set_name","description":"VM scale set name","type":"text","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_tags","description":"Azure instance tags.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"vm_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"The tag key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The tag value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"background_activities_moderator","description":"Background Activities Moderator (BAM) tracks application execution.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"battery","description":"Provides information about the internal battery of a Macbook.","platforms":["darwin"],"columns":[{"name":"manufacturer","description":"The battery manufacturer's name","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacture_date","description":"The date the battery was manufactured UNIX Epoch","type":"integer","hidden":false,"required":false,"index":false},{"name":"model","description":"The battery's model number","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The battery's unique serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"cycle_count","description":"The number of charge/discharge cycles","type":"integer","hidden":false,"required":false,"index":false},{"name":"health","description":"One of the following: \"Good\" describes a well-performing battery, \"Fair\" describes a functional battery with limited capacity, or \"Poor\" describes a battery that's not capable of providing power","type":"text","hidden":false,"required":false,"index":false},{"name":"condition","description":"One of the following: \"Normal\" indicates the condition of the battery is within normal tolerances, \"Service Needed\" indicates that the battery should be checked out by a licensed Mac repair service, \"Permanent Failure\" indicates the battery needs replacement","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"One of the following: \"AC Power\" indicates the battery is connected to an external power source, \"Battery Power\" indicates that the battery is drawing internal power, \"Off Line\" indicates the battery is off-line or no longer connected","type":"text","hidden":false,"required":false,"index":false},{"name":"charging","description":"1 if the battery is currently being charged by a power source. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"charged","description":"1 if the battery is currently completely charged. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"designed_capacity","description":"The battery's designed capacity in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"The battery's actual capacity when it is fully charged in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"current_capacity","description":"The battery's current charged capacity in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"percent_remaining","description":"The percentage of battery remaining before it is drained","type":"integer","hidden":false,"required":false,"index":false},{"name":"amperage","description":"The battery's current amperage in mA","type":"integer","hidden":false,"required":false,"index":false},{"name":"voltage","description":"The battery's current voltage in mV","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes_until_empty","description":"The number of minutes until the battery is fully depleted. This value is -1 if this time is still being calculated","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes_to_full_charge","description":"The number of minutes until the battery is fully charged. This value is -1 if this time is still being calculated","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"bitlocker_info","description":"Retrieve bitlocker status of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"ID of the encrypted drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"Drive letter of the encrypted drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"persistent_volume_id","description":"Persistent ID of the drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"conversion_status","description":"The bitlocker conversion status of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"protection_status","description":"The bitlocker protection status of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"encryption_method","description":"The encryption type of the device.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The FVE metadata version of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"percentage_encrypted","description":"The percentage of the drive that is encrypted.","type":"integer","hidden":false,"required":false,"index":false},{"name":"lock_status","description":"The accessibility status of the drive from Windows.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"block_devices","description":"Block (buffered access) device file nodes: disks, ramdisks, and DMG containers.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Block device name","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Block device parent name","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Block device vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"Block device model string identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Block device size in blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Block device Universally Unique Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Block device type string","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"Block device label string","type":"text","hidden":false,"required":false,"index":false}]},{"name":"bpf_process_events","description":"Track time/action process executions.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Binary path","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","hidden":false,"required":false,"index":false},{"name":"json_cmdline","description":"Command line arguments, in JSON format","type":"text","hidden":true,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"bpf_socket_events","description":"Track network socket opens and closes.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"The socket type","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","hidden":false,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"browser_plugins","description":"All C/NPAPI browser plugin details for all users.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the plugin","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Plugin display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Plugin identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Plugin short version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Build SDK used to compile plugin","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Plugin description text","type":"text","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Plugin language-localization","type":"text","hidden":false,"required":false,"index":false},{"name":"native","description":"Plugin requires native execution","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Is the plugin disabled. 1 = Disabled","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"carbon_black_info","description":"Returns info about a Carbon Black sensor install.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"sensor_id","description":"Sensor ID of the Carbon Black sensor","type":"integer","hidden":false,"required":false,"index":false},{"name":"config_name","description":"Sensor group","type":"text","hidden":false,"required":false,"index":false},{"name":"collect_store_files","description":"If the sensor is configured to send back binaries to the Carbon Black server","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_module_loads","description":"If the sensor is configured to capture module loads","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_module_info","description":"If the sensor is configured to collect metadata of binaries","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_file_mods","description":"If the sensor is configured to collect file modification events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_reg_mods","description":"If the sensor is configured to collect registry modification events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_net_conns","description":"If the sensor is configured to collect network connections","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_processes","description":"If the sensor is configured to process events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_cross_processes","description":"If the sensor is configured to cross process events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_emet_events","description":"If the sensor is configured to EMET events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_data_file_writes","description":"If the sensor is configured to collect non binary file writes","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_process_user_context","description":"If the sensor is configured to collect the user running a process","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_sensor_operations","description":"Unknown","type":"integer","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_mb","description":"Event file disk quota in MB","type":"integer","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_percentage","description":"Event file disk quota in a percentage","type":"integer","hidden":false,"required":false,"index":false},{"name":"protection_disabled","description":"If the sensor is configured to report tamper events","type":"integer","hidden":false,"required":false,"index":false},{"name":"sensor_ip_addr","description":"IP address of the sensor","type":"text","hidden":false,"required":false,"index":false},{"name":"sensor_backend_server","description":"Carbon Black server","type":"text","hidden":false,"required":false,"index":false},{"name":"event_queue","description":"Size in bytes of Carbon Black event files on disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"binary_queue","description":"Size in bytes of binaries waiting to be sent to Carbon Black server","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"carves","description":"List the set of completed and in-progress carves. If carve=1 then the query is treated as a new carve request.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"time","description":"Time at which the carve was kicked off","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha256","description":"A SHA256 sum of the carved archive","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the carved archive","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the requested carve","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the carve, can be STARTING, PENDING, SUCCESS, or FAILED","type":"text","hidden":false,"required":false,"index":false},{"name":"carve_guid","description":"Identifying value of the carve session","type":"text","hidden":false,"required":false,"index":false},{"name":"request_id","description":"Identifying value of the carve request (e.g., scheduled query name, distributed request, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"carve","description":"Set this value to '1' to start a file carve","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"certificates","description":"Certificate Authorities installed in Keychains/ca-bundles.","platforms":["darwin","windows"],"columns":[{"name":"common_name","description":"Certificate CommonName","type":"text","hidden":false,"required":false,"index":false},{"name":"subject","description":"Certificate distinguished name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer","description":"Certificate issuer distinguished name","type":"text","hidden":false,"required":false,"index":false},{"name":"ca","description":"1 if CA: true (certificate is an authority) else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"self_signed","description":"1 if self-signed, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"not_valid_before","description":"Lower bound of valid date","type":"text","hidden":false,"required":false,"index":false},{"name":"not_valid_after","description":"Certificate expiration data","type":"text","hidden":false,"required":false,"index":false},{"name":"signing_algorithm","description":"Signing algorithm used","type":"text","hidden":false,"required":false,"index":false},{"name":"key_algorithm","description":"Key algorithm used","type":"text","hidden":false,"required":false,"index":false},{"name":"key_strength","description":"Key size used for RSA/DSA, or curve name","type":"text","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Certificate key usage and extended key usage","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_key_id","description":"SKID an optionally included SHA1","type":"text","hidden":false,"required":false,"index":false},{"name":"authority_key_id","description":"AKID an optionally included SHA1","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the raw certificate contents","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Keychain or PEM bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"Certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"sid","description":"SID","type":"text","hidden":true,"required":false,"index":false},{"name":"store_location","description":"Certificate system store location","type":"text","hidden":true,"required":false,"index":false},{"name":"store","description":"Certificate system store","type":"text","hidden":true,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":true,"required":false,"index":false},{"name":"store_id","description":"Exists for service/user stores. Contains raw store id provided by WinAPI.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"chassis_info","description":"Display information pertaining to the chassis and its security status.","platforms":["windows"],"columns":[{"name":"audible_alarm","description":"If TRUE, the frame is equipped with an audible alarm.","type":"text","hidden":false,"required":false,"index":false},{"name":"breach_description","description":"If provided, gives a more detailed description of a detected security breach.","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_types","description":"A comma-separated list of chassis types, such as Desktop or Laptop.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"An extended description of the chassis if available.","type":"text","hidden":false,"required":false,"index":false},{"name":"lock","description":"If TRUE, the frame is equipped with a lock.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"security_breach","description":"The physical status of the chassis such as Breach Successful, Breach Attempted, etc.","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"smbios_tag","description":"The assigned asset tag number of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"sku","description":"The Stock Keeping Unit number if available.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"If available, gives various operational or nonoperational statuses such as OK, Degraded, and Pred Fail.","type":"text","hidden":false,"required":false,"index":false},{"name":"visible_alarm","description":"If TRUE, the frame is equipped with a visual alarm.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"chocolatey_packages","description":"Chocolatey packages installed in a system.","platforms":["windows"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this package resides","type":"text","hidden":false,"required":false,"index":false}]},{"name":"chrome_extension_content_scripts","description":"Chrome browser extension content scripts.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave)","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"script","description":"The content script used by the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"match","description":"The pattern that the script is matched against","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"chrome_extensions","description":"Chrome-based browser extensions.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave, edge, edge_beta)","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"profile","description":"The name of the Chrome profile that contains this extension","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced_identifier","description":"Extension identifier, as specified by the preferences file. Empty if the extension is not in the profile.","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier, computed from its manifest. Empty in case of error.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Extension-optional description","type":"text","hidden":false,"required":false,"index":false},{"name":"default_locale","description":"Default locale supported by extension","type":"text","hidden":false,"required":false,"index":false},{"name":"current_locale","description":"Current locale supported by extension","type":"text","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","hidden":false,"required":false,"index":false},{"name":"persistent","description":"1 If extension is persistent across all tabs else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"The permissions required by the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions_json","description":"The JSON-encoded permissions required by the extension","type":"text","hidden":true,"required":false,"index":false},{"name":"optional_permissions","description":"The permissions optionally required by the extensions","type":"text","hidden":false,"required":false,"index":false},{"name":"optional_permissions_json","description":"The JSON-encoded permissions optionally required by the extensions","type":"text","hidden":true,"required":false,"index":false},{"name":"manifest_hash","description":"The SHA256 hash of the manifest.json file","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","hidden":false,"required":false,"index":false},{"name":"from_webstore","description":"True if this extension was installed from the web store","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"1 if this extension is enabled","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Extension install time, in its original Webkit format","type":"text","hidden":false,"required":false,"index":false},{"name":"install_timestamp","description":"Extension install time, converted to unix time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"manifest_json","description":"The manifest file of the extension","type":"text","hidden":true,"required":false,"index":false},{"name":"key","description":"The extension key, from the manifest file","type":"text","hidden":true,"required":false,"index":false}]},{"name":"connectivity","description":"Provides the overall system's network state.","platforms":["windows"],"columns":[{"name":"disconnected","description":"True if the all interfaces are not connected to any network","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_no_traffic","description":"True if any interface is connected via IPv4, but has seen no traffic","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_no_traffic","description":"True if any interface is connected via IPv6, but has seen no traffic","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_subnet","description":"True if any interface is connected to the local subnet via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_local_network","description":"True if any interface is connected to a routed network via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_internet","description":"True if any interface is connected to the Internet via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_subnet","description":"True if any interface is connected to the local subnet via IPv6","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_local_network","description":"True if any interface is connected to a routed network via IPv6","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_internet","description":"True if any interface is connected to the Internet via IPv6","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"cpu_info","description":"Retrieve cpu hardware info of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"The DeviceID of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"processor_type","description":"The processor type, such as Central, Math, or Video.","type":"text","hidden":false,"required":false,"index":false},{"name":"availability","description":"The availability and status of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_status","description":"The current operating status of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"number_of_cores","description":"The number of cores of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"logical_processors","description":"The number of logical processors of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"address_width","description":"The width of the CPU address bus.","type":"text","hidden":false,"required":false,"index":false},{"name":"current_clock_speed","description":"The current frequency of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_clock_speed","description":"The maximum possible frequency of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"socket_designation","description":"The assigned socket on the board for the given CPU.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"cpu_time","description":"Displays information from /proc/stat file about the time the cpu cores spent in different parts of the system.","platforms":["darwin","linux"],"columns":[{"name":"core","description":"Name of the cpu (core)","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"Time spent in user mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"nice","description":"Time spent in user mode with low priority (nice)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system","description":"Time spent in system mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"idle","description":"Time spent in the idle task","type":"bigint","hidden":false,"required":false,"index":false},{"name":"iowait","description":"Time spent waiting for I/O to complete","type":"bigint","hidden":false,"required":false,"index":false},{"name":"irq","description":"Time spent servicing interrupts","type":"bigint","hidden":false,"required":false,"index":false},{"name":"softirq","description":"Time spent servicing softirqs","type":"bigint","hidden":false,"required":false,"index":false},{"name":"steal","description":"Time spent in other operating systems when running in a virtualized environment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"guest","description":"Time spent running a virtual CPU for a guest OS under the control of the Linux kernel","type":"bigint","hidden":false,"required":false,"index":false},{"name":"guest_nice","description":"Time spent running a niced guest ","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"cpuid","description":"Useful CPU features from the cpuid ASM call.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"feature","description":"Present feature flags","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Bit value or string","type":"text","hidden":false,"required":false,"index":false},{"name":"output_register","description":"Register used to for feature value","type":"text","hidden":false,"required":false,"index":false},{"name":"output_bit","description":"Bit in register value for feature value","type":"integer","hidden":false,"required":false,"index":false},{"name":"input_eax","description":"Value of EAX used","type":"text","hidden":false,"required":false,"index":false}]},{"name":"crashes","description":"Application, System, and Mobile App crash logs.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of crash log","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Location of log file","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version info of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent PID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"responsible","description":"Process responsible for the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the crashed process","type":"integer","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Date/Time at which the crash occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"crashed_thread","description":"Thread ID which crashed","type":"bigint","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Most recent frame from the stack trace","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_type","description":"Exception type of the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_codes","description":"Exception codes from the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_notes","description":"Exception notes from the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"The value of the system registers","type":"text","hidden":false,"required":false,"index":false}]},{"name":"crontab","description":"Line parsed values from system and user cron/tab.","platforms":["darwin","linux"],"columns":[{"name":"event","description":"The job @event name (rare)","type":"text","hidden":false,"required":false,"index":false},{"name":"minute","description":"The exact minute for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"hour","description":"The hour of the day for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"day_of_month","description":"The day of the month for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"month","description":"The month of the year for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"day_of_week","description":"The day of the week for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"command","description":"Raw command string","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File parsed","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"cups_destinations","description":"Returns all configured printers.","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the printer","type":"text","hidden":false,"required":false,"index":false},{"name":"option_name","description":"Option name","type":"text","hidden":false,"required":false,"index":false},{"name":"option_value","description":"Option value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"cups_jobs","description":"Returns all completed print jobs from cups.","platforms":["darwin"],"columns":[{"name":"title","description":"Title of the printed job","type":"text","hidden":false,"required":false,"index":false},{"name":"destination","description":"The printer the job was sent to","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"The user who printed the job","type":"text","hidden":false,"required":false,"index":false},{"name":"format","description":"The format of the print job","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the print job","type":"integer","hidden":false,"required":false,"index":false},{"name":"completed_time","description":"When the job completed printing","type":"integer","hidden":false,"required":false,"index":false},{"name":"processing_time","description":"How long the job took to process","type":"integer","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the print request was initiated","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"curl","description":"Perform an http request and return stats about it.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"url","description":"The url for the request","type":"text","hidden":false,"required":true,"index":false},{"name":"method","description":"The HTTP method for the request","type":"text","hidden":false,"required":false,"index":false},{"name":"user_agent","description":"The user-agent string to use for the request","type":"text","hidden":false,"required":false,"index":false},{"name":"response_code","description":"The HTTP status code for the response","type":"integer","hidden":false,"required":false,"index":false},{"name":"round_trip_time","description":"Time taken to complete the request","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of bytes in the response","type":"bigint","hidden":false,"required":false,"index":false},{"name":"result","description":"The HTTP response body","type":"text","hidden":false,"required":false,"index":false}]},{"name":"curl_certificate","description":"Inspect TLS certificates by connecting to input hostnames.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"hostname","description":"Hostname (domain[:port]) to CURL","type":"text","hidden":false,"required":true,"index":false},{"name":"common_name","description":"Common name of company issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"organization","description":"Organization issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"organization_unit","description":"Organization unit issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_common_name","description":"Issuer common name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_organization","description":"Issuer organization","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_organization_unit","description":"Issuer organization unit","type":"text","hidden":false,"required":false,"index":false},{"name":"valid_from","description":"Period of validity start date","type":"text","hidden":false,"required":false,"index":false},{"name":"valid_to","description":"Period of validity end date","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256_fingerprint","description":"SHA-256 fingerprint","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1_fingerprint","description":"SHA1 fingerprint","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version Number","type":"integer","hidden":false,"required":false,"index":false},{"name":"signature_algorithm","description":"Signature Algorithm","type":"text","hidden":false,"required":false,"index":false},{"name":"signature","description":"Signature","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_key_identifier","description":"Subject Key Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"authority_key_identifier","description":"Authority Key Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Usage of key in certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"extended_key_usage","description":"Extended usage of key in certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"policies","description":"Certificate Policies","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_alternative_names","description":"Subject Alternative Name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_alternative_names","description":"Issuer Alternative Name","type":"text","hidden":false,"required":false,"index":false},{"name":"info_access","description":"Authority Information Access","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_info_access","description":"Subject Information Access","type":"text","hidden":false,"required":false,"index":false},{"name":"policy_mappings","description":"Policy Mappings","type":"text","hidden":false,"required":false,"index":false},{"name":"has_expired","description":"1 if the certificate has expired, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"basic_constraint","description":"Basic Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"name_constraints","description":"Name Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"policy_constraints","description":"Policy Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"dump_certificate","description":"Set this value to '1' to dump certificate","type":"integer","hidden":true,"required":false,"index":false},{"name":"timeout","description":"Set this value to the timeout in seconds to complete the TLS handshake (default 4s, use 0 for no timeout)","type":"integer","hidden":true,"required":false,"index":false},{"name":"pem","description":"Certificate PEM format","type":"text","hidden":false,"required":false,"index":false}]},{"name":"deb_packages","description":"The installed DEB package database.","platforms":["linux"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Package source","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Package architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"Package revision","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Package status","type":"text","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Package maintainer","type":"text","hidden":false,"required":false,"index":false},{"name":"section","description":"Package section","type":"text","hidden":false,"required":false,"index":false},{"name":"priority","description":"Package priority","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"default_environment","description":"Default environment variables and values.","platforms":["windows"],"columns":[{"name":"variable","description":"Name of the environment variable","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the environment variable","type":"text","hidden":false,"required":false,"index":false},{"name":"expand","description":"1 if the variable needs expanding, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"device_file","description":"Similar to the file table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","hidden":false,"required":true,"index":false},{"name":"path","description":"A logical path within the device node","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Creation time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_firmware","description":"A best-effort list of discovered firmware versions.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of device","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"The device name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Firmware version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_hash","description":"Similar to the hash table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","hidden":false,"required":true,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_partitions","description":"Use TSK to enumerate details about partitions on a disk device.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number or description","type":"integer","hidden":false,"required":false,"index":false},{"name":"label","description":"","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Byte size of each block","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Number of blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Number of meta nodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"disk_encryption","description":"Disk encryption status and information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Disk name","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Disk Universally Unique Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 If encrypted: true (disk is encrypted), else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Description of cipher type and mode if available","type":"text","hidden":false,"required":false,"index":false},{"name":"encryption_status","description":"Disk encryption status with one of following values: encrypted | not encrypted | undefined","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Currently authenticated user if available","type":"text","hidden":false,"required":false,"index":false},{"name":"user_uuid","description":"UUID of authenticated user if available","type":"text","hidden":false,"required":false,"index":false},{"name":"filevault_status","description":"FileVault status with one of following values: on | off | unknown","type":"text","hidden":false,"required":false,"index":false}]},{"name":"disk_events","description":"Track DMG disk image events (appearance/disappearance) when opened.","platforms":["darwin"],"columns":[{"name":"action","description":"Appear or disappear","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the DMG file accessed","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Disk event name","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Disk event BSD name","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"UUID of the volume inside DMG if available","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of partition in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ejectable","description":"1 if ejectable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"mountable","description":"1 if mountable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"writable","description":"1 if writable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"content","description":"Disk event content","type":"text","hidden":false,"required":false,"index":false},{"name":"media_name","description":"Disk event media name string","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Disk event vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"filesystem","description":"Filesystem if available","type":"text","hidden":false,"required":false,"index":false},{"name":"checksum","description":"UDIF Master checksum if available (CRC32)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of appearance/disappearance in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"disk_info","description":"Retrieve basic information about the physical disks of a system.","platforms":["windows"],"columns":[{"name":"partitions","description":"Number of detected partitions on disk.","type":"integer","hidden":false,"required":false,"index":false},{"name":"disk_index","description":"Physical drive number of the disk.","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"The interface type of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"The unique identifier of the drive on the system.","type":"text","hidden":false,"required":false,"index":false},{"name":"pnp_device_id","description":"The unique identifier of the drive on the system.","type":"text","hidden":false,"required":false,"index":false},{"name":"disk_size","description":"Size of the disk.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hard drive model.","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"The label of the disk object.","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The OS's description of the disk.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"dns_cache","description":"Enumerate the DNS cache using the undocumented DnsGetCacheDataTable function in dnsapi.dll.","platforms":["windows"],"columns":[{"name":"name","description":"DNS record name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"DNS record type","type":"text","hidden":false,"required":false,"index":false},{"name":"flags","description":"DNS record flags","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"dns_resolvers","description":"Resolvers used by this host.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Address type index or order","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Address type: sortlist, nameserver, search","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Resolver IP/IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Address (sortlist) netmask length","type":"text","hidden":false,"required":false,"index":false},{"name":"options","description":"Resolver options","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"docker_container_fs_changes","description":"Changes to files or directories on container's filesystem.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"path","description":"FIle or directory path relative to rootfs","type":"text","hidden":false,"required":false,"index":false},{"name":"change_type","description":"Type of change: C:Modified, A:Added, D:Deleted","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_labels","description":"Docker container labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_mounts","description":"Docker container mounts.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of mount (bind, volume)","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Optional mount name","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source path on host","type":"text","hidden":false,"required":false,"index":false},{"name":"destination","description":"Destination path inside container","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver providing the mount","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"Mount options (rw, ro)","type":"text","hidden":false,"required":false,"index":false},{"name":"rw","description":"1 if read/write. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"propagation","description":"Mount propagation","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_networks","description":"Docker container networks.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Network name","type":"text","hidden":false,"required":false,"index":false},{"name":"network_id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"endpoint_id","description":"Endpoint ID","type":"text","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"ip_address","description":"IP address","type":"text","hidden":false,"required":false,"index":false},{"name":"ip_prefix_len","description":"IP subnet prefix length","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_gateway","description":"IPv6 gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_prefix_len","description":"IPv6 subnet prefix length","type":"integer","hidden":false,"required":false,"index":false},{"name":"mac_address","description":"MAC address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_ports","description":"Docker container ports.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Protocol (tcp, udp)","type":"text","hidden":false,"required":false,"index":false},{"name":"port","description":"Port inside the container","type":"integer","hidden":false,"required":false,"index":false},{"name":"host_ip","description":"Host IP address on which public port is listening","type":"text","hidden":false,"required":false,"index":false},{"name":"host_port","description":"Host port","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"docker_container_processes","description":"Docker container processes.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start in seconds since boot (non-sleeping)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"User name","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Cumulative CPU time. [DD-]HH:MM:SS format","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu","description":"CPU utilization as percentage","type":"double","hidden":false,"required":false,"index":false},{"name":"mem","description":"Memory utilization as percentage","type":"double","hidden":false,"required":false,"index":false}]},{"name":"docker_container_stats","description":"Docker container statistics. Queries on this table take at least one second.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"name","description":"Container name","type":"text","hidden":false,"required":false,"index":false},{"name":"pids","description":"Number of processes","type":"integer","hidden":false,"required":false,"index":false},{"name":"read","description":"UNIX time when stats were read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"preread","description":"UNIX time when stats were last read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"interval","description":"Difference between read and preread in nano-seconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_read","description":"Total disk read bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_write","description":"Total disk write bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"num_procs","description":"Number of processors","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_total_usage","description":"Total CPU usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_kernelmode_usage","description":"CPU kernel mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_usermode_usage","description":"CPU user mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_cpu_usage","description":"CPU system usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"online_cpus","description":"Online CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"pre_cpu_total_usage","description":"Last read total CPU usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_cpu_kernelmode_usage","description":"Last read CPU kernel mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_cpu_usermode_usage","description":"Last read CPU user mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_system_cpu_usage","description":"Last read CPU system usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_online_cpus","description":"Last read online CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory_usage","description":"Memory usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_max_usage","description":"Memory maximum usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"Memory limit","type":"bigint","hidden":false,"required":false,"index":false},{"name":"network_rx_bytes","description":"Total network bytes read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"network_tx_bytes","description":"Total network bytes transmitted","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"docker_containers","description":"Docker containers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Container name","type":"text","hidden":false,"required":false,"index":false},{"name":"image","description":"Docker image (name) used to launch this container","type":"text","hidden":false,"required":false,"index":false},{"name":"image_id","description":"Docker image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"command","description":"Command with arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"state","description":"Container state (created, restarting, running, removing, paused, exited, dead)","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Container status information","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Identifier of the initial process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Container path","type":"text","hidden":false,"required":false,"index":false},{"name":"config_entrypoint","description":"Container entrypoint(s)","type":"text","hidden":false,"required":false,"index":false},{"name":"started_at","description":"Container start time as string","type":"text","hidden":false,"required":false,"index":false},{"name":"finished_at","description":"Container finish time as string","type":"text","hidden":false,"required":false,"index":false},{"name":"privileged","description":"Is the container privileged","type":"integer","hidden":false,"required":false,"index":false},{"name":"security_options","description":"List of container security options","type":"text","hidden":false,"required":false,"index":false},{"name":"env_variables","description":"Container environmental variables","type":"text","hidden":false,"required":false,"index":false},{"name":"readonly_rootfs","description":"Is the root filesystem mounted as read only","type":"integer","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"ipc_namespace","description":"IPC namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"mnt_namespace","description":"Mount namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"net_namespace","description":"Network namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"pid_namespace","description":"PID namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"user_namespace","description":"User namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"uts_namespace","description":"UTS namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"docker_image_history","description":"Docker image history information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of instruction in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"created_by","description":"Created by instruction","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of tags","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Instruction comment","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_image_labels","description":"Docker image labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_image_layers","description":"Docker image layers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"layer_id","description":"Layer ID","type":"text","hidden":false,"required":false,"index":false},{"name":"layer_order","description":"Layer Order (1 = base layer)","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"docker_images","description":"Docker images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size_bytes","description":"Size of image in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of repository tags","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_info","description":"Docker system information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Docker system ID","type":"text","hidden":false,"required":false,"index":false},{"name":"containers","description":"Total number of containers","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_running","description":"Number of containers currently running","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_paused","description":"Number of containers in paused state","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_stopped","description":"Number of containers in stopped state","type":"integer","hidden":false,"required":false,"index":false},{"name":"images","description":"Number of images","type":"integer","hidden":false,"required":false,"index":false},{"name":"storage_driver","description":"Storage driver","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"1 if memory limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"swap_limit","description":"1 if swap limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"kernel_memory","description":"1 if kernel memory limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_period","description":"1 if CPU Completely Fair Scheduler (CFS) period support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_quota","description":"1 if CPU Completely Fair Scheduler (CFS) quota support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_shares","description":"1 if CPU share weighting support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_set","description":"1 if CPU set selection support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_forwarding","description":"1 if IPv4 forwarding is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"bridge_nf_iptables","description":"1 if bridge netfilter iptables is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"bridge_nf_ip6tables","description":"1 if bridge netfilter ip6tables is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"oom_kill_disable","description":"1 if Out-of-memory kill is disabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_driver","description":"Logging driver","type":"text","hidden":false,"required":false,"index":false},{"name":"cgroup_driver","description":"Control groups driver","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Operating system type","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"cpus","description":"Number of CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory","description":"Total memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"http_proxy","description":"HTTP proxy","type":"text","hidden":false,"required":false,"index":false},{"name":"https_proxy","description":"HTTPS proxy","type":"text","hidden":false,"required":false,"index":false},{"name":"no_proxy","description":"Comma-separated list of domain extensions proxy should not be used for","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the docker host","type":"text","hidden":false,"required":false,"index":false},{"name":"server_version","description":"Server version","type":"text","hidden":false,"required":false,"index":false},{"name":"root_dir","description":"Docker root directory","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_network_labels","description":"Docker network labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_networks","description":"Docker networks information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Network name","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Network driver","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"enable_ipv6","description":"1 if IPv6 is enabled on this network. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"subnet","description":"Network subnet","type":"text","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Network gateway","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_version","description":"Docker version information.","platforms":["darwin","linux"],"columns":[{"name":"version","description":"Docker version","type":"text","hidden":false,"required":false,"index":false},{"name":"api_version","description":"API version","type":"text","hidden":false,"required":false,"index":false},{"name":"min_api_version","description":"Minimum API version supported","type":"text","hidden":false,"required":false,"index":false},{"name":"git_commit","description":"Docker build git commit","type":"text","hidden":false,"required":false,"index":false},{"name":"go_version","description":"Go version","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"Hardware architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Build time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_volume_labels","description":"Docker volume labels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_volumes","description":"Docker volumes information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Volume driver","type":"text","hidden":false,"required":false,"index":false},{"name":"mount_point","description":"Mount point","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Volume type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"drivers","description":"Details for in-use Windows device drivers. This does not display installed but unused drivers.","platforms":["windows"],"columns":[{"name":"device_id","description":"Device ID","type":"text","hidden":false,"required":false,"index":false},{"name":"device_name","description":"Device name","type":"text","hidden":false,"required":false,"index":false},{"name":"image","description":"Path to driver image file","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Driver description","type":"text","hidden":false,"required":false,"index":false},{"name":"service","description":"Driver service name, if one exists","type":"text","hidden":false,"required":false,"index":false},{"name":"service_key","description":"Driver service registry key","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Driver version","type":"text","hidden":false,"required":false,"index":false},{"name":"inf","description":"Associated inf file","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Device/driver class name","type":"text","hidden":false,"required":false,"index":false},{"name":"provider","description":"Driver provider","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Device manufacturer","type":"text","hidden":false,"required":false,"index":false},{"name":"driver_key","description":"Driver key","type":"text","hidden":false,"required":false,"index":false},{"name":"date","description":"Driver date","type":"bigint","hidden":false,"required":false,"index":false},{"name":"signed","description":"Whether the driver is signed or not","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_metadata","description":"EC2 instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_type","description":"EC2 instance type","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture of this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"region","description":"AWS region in which this instance launched","type":"text","hidden":false,"required":false,"index":false},{"name":"availability_zone","description":"Availability zone in which this instance launched","type":"text","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Private IPv4 DNS hostname of the first interface of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"local_ipv4","description":"Private IPv4 address of the first interface of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address for the first network interface of this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"security_groups","description":"Comma separated list of security group names","type":"text","hidden":false,"required":false,"index":false},{"name":"iam_arn","description":"If there is an IAM role associated with the instance, contains instance profile ARN","type":"text","hidden":false,"required":false,"index":false},{"name":"ami_id","description":"AMI ID used to launch this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"reservation_id","description":"ID of the reservation","type":"text","hidden":false,"required":false,"index":false},{"name":"account_id","description":"AWS account ID which owns this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_tags","description":"EC2 instance tag key value pairs.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Tag key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"elf_dynamic","description":"ELF dynamic section information.","platforms":["linux"],"columns":[{"name":"tag","description":"Tag ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"integer","hidden":false,"required":false,"index":false},{"name":"class","description":"Class (32 or 64)","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_info","description":"ELF file information.","platforms":["linux"],"columns":[{"name":"class","description":"Class type, 32 or 64bit","type":"text","hidden":false,"required":false,"index":false},{"name":"abi","description":"Section type","type":"text","hidden":false,"required":false,"index":false},{"name":"abi_version","description":"Section virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Offset of section in file","type":"text","hidden":false,"required":false,"index":false},{"name":"machine","description":"Machine type","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Object file version","type":"integer","hidden":false,"required":false,"index":false},{"name":"entry","description":"Entry point address","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"ELF header flags","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_sections","description":"ELF section information.","platforms":["linux"],"columns":[{"name":"name","description":"Section name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Section type","type":"integer","hidden":false,"required":false,"index":false},{"name":"vaddr","description":"Section virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset of section in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of section","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Section attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"link","description":"Link to other section","type":"text","hidden":false,"required":false,"index":false},{"name":"align","description":"Segment alignment","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_segments","description":"ELF segment information.","platforms":["linux"],"columns":[{"name":"name","description":"Segment type/name","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Segment offset in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"vaddr","description":"Segment virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"psize","description":"Size of segment in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"msize","description":"Segment offset in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Segment attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"align","description":"Segment alignment","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_symbols","description":"ELF symbol list.","platforms":["linux"],"columns":[{"name":"name","description":"Symbol name","type":"text","hidden":false,"required":false,"index":false},{"name":"addr","description":"Symbol address (value)","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of object","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Symbol type","type":"text","hidden":false,"required":false,"index":false},{"name":"binding","description":"Binding type","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Section table index","type":"integer","hidden":false,"required":false,"index":false},{"name":"table","description":"Table name containing symbol","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"es_process_events","description":"Process execution events from EndpointSecurity.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"original_parent","description":"Original parent process ID in case of reparenting","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline_count","description":"Number of command line arguments","type":"bigint","hidden":false,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","hidden":false,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective User ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective Group ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false},{"name":"signing_id","description":"Signature identifier of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"team_id","description":"Team identifier of thd process","type":"text","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Codesigning hash of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_binary","description":"Indicates if the binary is Apple signed binary (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of a process in case of an exit event","type":"integer","hidden":false,"required":false,"index":false},{"name":"child_pid","description":"Process ID of a child process in case of a fork event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"etc_hosts","description":"Line-parsed /etc/hosts.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"address","description":"IP address mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"hostnames","description":"Raw hosts mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"etc_protocols","description":"Line-parsed /etc/protocols.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Protocol name","type":"text","hidden":false,"required":false,"index":false},{"name":"number","description":"Protocol number","type":"integer","hidden":false,"required":false,"index":false},{"name":"alias","description":"Protocol alias","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Comment with protocol description","type":"text","hidden":false,"required":false,"index":false}]},{"name":"etc_services","description":"Line-parsed /etc/services.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Service name","type":"text","hidden":false,"required":false,"index":false},{"name":"port","description":"Service port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"text","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Optional space separated list of other names for a service","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment for a service.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"event_taps","description":"Returns information about installed event taps.","platforms":["darwin"],"columns":[{"name":"enabled","description":"Is the Event Tap enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"event_tap_id","description":"Unique ID for the Tap","type":"integer","hidden":false,"required":false,"index":false},{"name":"event_tapped","description":"The mask that identifies the set of events to be observed.","type":"text","hidden":false,"required":false,"index":false},{"name":"process_being_tapped","description":"The process ID of the target application","type":"integer","hidden":false,"required":false,"index":false},{"name":"tapping_process","description":"The process ID of the application that created the event tap.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"example","description":"This is an example table spec.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Description for name column","type":"text","hidden":false,"required":false,"index":false},{"name":"points","description":"This is a signed SQLite int column","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"This is a signed SQLite bigint column","type":"bigint","hidden":false,"required":false,"index":false},{"name":"action","description":"Action performed in generation","type":"text","hidden":false,"required":true,"index":false},{"name":"id","description":"An index of some sort","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of example","type":"text","hidden":false,"required":false,"index":false}]},{"name":"extended_attributes","description":"Returns the extended attributes for files (similar to Windows ADS).","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute file path","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the value generated from the extended attribute","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The parsed information from the attribute","type":"text","hidden":false,"required":false,"index":false},{"name":"base64","description":"1 if the value is base64 encoded else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"fan_speed_sensors","description":"Fan speeds.","platforms":["darwin"],"columns":[{"name":"fan","description":"Fan number","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Fan name","type":"text","hidden":false,"required":false,"index":false},{"name":"actual","description":"Actual speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimum speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"target","description":"Target speed","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"fbsd_kmods","description":"Loaded FreeBSD kernel modules.","platforms":["freebsd"],"columns":[{"name":"name","description":"Module name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"integer","hidden":false,"required":false,"index":false},{"name":"refs","description":"Module reverse dependencies","type":"integer","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"file","description":"Interactive filesystem attributes and metadata.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"path","description":"Absolute file path","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","hidden":false,"required":true,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Device ID (optional)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"btime","description":"(B)irth or (cr)eate time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","hidden":false,"required":false,"index":false},{"name":"symlink","description":"1 if the path is a symlink, otherwise 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","hidden":false,"required":false,"index":false},{"name":"attributes","description":"File attrib string. See: https://ss64.com/nt/attrib.html","type":"text","hidden":true,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number","type":"text","hidden":true,"required":false,"index":false},{"name":"file_id","description":"file ID","type":"text","hidden":true,"required":false,"index":false},{"name":"file_version","description":"File version","type":"text","hidden":true,"required":false,"index":false},{"name":"product_version","description":"File product version","type":"text","hidden":true,"required":false,"index":false},{"name":"bsd_flags","description":"The BSD file flags (chflags). Possible values: NODUMP, UF_IMMUTABLE, UF_APPEND, OPAQUE, HIDDEN, ARCHIVED, SF_IMMUTABLE, SF_APPEND","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"file_events","description":"Track time/action changes to files specified in configuration data.","platforms":["darwin","linux"],"columns":[{"name":"target_path","description":"The path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file defined in the config","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"md5","description":"The MD5 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"The SHA1 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"The SHA256 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"hashed","description":"1 if the file was hashed, 0 if not, -1 if hashing failed","type":"integer","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"firefox_addons","description":"Firefox browser extensions, webapps, and addons.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local user that owns the addon","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Addon display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Addon identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"creator","description":"Addon-supported creator string","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Extension, addon, webapp","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Addon-supplied version string","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Addon-supplied description string","type":"text","hidden":false,"required":false,"index":false},{"name":"source_url","description":"URL that installed the addon","type":"text","hidden":false,"required":false,"index":false},{"name":"visible","description":"1 If the addon is shown in browser else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If the addon is active else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 If the addon is application-disabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"1 If the addon applies background updates else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"native","description":"1 If the addon includes binary components else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"location","description":"Global, profile location","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper","description":"OS X Gatekeeper Details.","platforms":["darwin"],"columns":[{"name":"assessments_enabled","description":"1 If a Gatekeeper is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"dev_id_enabled","description":"1 If a Gatekeeper allows execution from identified developers else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of Gatekeeper's gke.bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"opaque_version","description":"Version of Gatekeeper's gkopaque.bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper_approved_apps","description":"Gatekeeper apps a user has allowed to run.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of executable allowed to run","type":"text","hidden":false,"required":false,"index":false},{"name":"requirement","description":"Code signing requirement language","type":"text","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last change time","type":"double","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"double","hidden":false,"required":false,"index":false}]},{"name":"groups","description":"Local system groups.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","hidden":true,"required":false,"index":false},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"hardware_events","description":"Hardware (PCI/USB/HID) events from UDEV or IOKit.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"Remove, insert, change properties, etc","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Local device path assigned (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of hardware and hardware event","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver claiming the device","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Hardware device vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded Hardware vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"Hardware device model","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded Hardware model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"Device serial (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"Device revision (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of hardware event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"hash","description":"Filesystem hash data.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"ssdeep","description":"ssdeep hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"homebrew_packages","description":"The installed homebrew package database.","platforms":["darwin"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Package install path","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Current 'linked' version","type":"text","hidden":false,"required":false,"index":false},{"name":"prefix","description":"Homebrew install prefix","type":"text","hidden":true,"required":false,"index":false}]},{"name":"hvci_status","description":"Retrieve HVCI info of the machine.","platforms":["windows"],"columns":[{"name":"version","description":"The version number of the Device Guard build.","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_identifier","description":"The instance ID of Device Guard.","type":"text","hidden":false,"required":false,"index":false},{"name":"vbs_status","description":"The status of the virtualization based security settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false},{"name":"code_integrity_policy_enforcement_status","description":"The status of the code integrity policy enforcement settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false},{"name":"umci_policy_status","description":"The status of the User Mode Code Integrity security settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ibridge_info","description":"Information about the Apple iBridge hardware controller.","platforms":["darwin"],"columns":[{"name":"boot_uuid","description":"Boot UUID of the iBridge controller","type":"text","hidden":false,"required":false,"index":false},{"name":"coprocessor_version","description":"The manufacturer and chip version","type":"text","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"The build version of the firmware","type":"text","hidden":false,"required":false,"index":false},{"name":"unique_chip_id","description":"Unique id of the iBridge controller","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ie_extensions","description":"Internet Explorer browser extensions.","platforms":["windows"],"columns":[{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"registry_path","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the executable","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executable","type":"text","hidden":false,"required":false,"index":false}]},{"name":"intel_me_info","description":"Intel ME/CSE Info.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"version","description":"Intel ME version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"interface_addresses","description":"Network interfaces and relevant metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for interface","type":"text","hidden":false,"required":false,"index":false},{"name":"mask","description":"Interface netmask","type":"text","hidden":false,"required":false,"index":false},{"name":"broadcast","description":"Broadcast address for the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"point_to_point","description":"PtP address for the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of address. One of dhcp, manual, auto, other, unknown","type":"text","hidden":false,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"interface_details","description":"Detailed information and stats of network interfaces.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC of interface (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Interface type (includes virtual)","type":"integer","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Network MTU","type":"integer","hidden":false,"required":false,"index":false},{"name":"metric","description":"Metric based on the speed of the interface","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags (netdevice) for the device","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipackets","description":"Input packets","type":"bigint","hidden":false,"required":false,"index":false},{"name":"opackets","description":"Output packets","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ibytes","description":"Input bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"obytes","description":"Output bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ierrors","description":"Input errors","type":"bigint","hidden":false,"required":false,"index":false},{"name":"oerrors","description":"Output errors","type":"bigint","hidden":false,"required":false,"index":false},{"name":"idrops","description":"Input drops","type":"bigint","hidden":false,"required":false,"index":false},{"name":"odrops","description":"Output drops","type":"bigint","hidden":false,"required":false,"index":false},{"name":"collisions","description":"Packet Collisions detected","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Time of last device modification (optional)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"link_speed","description":"Interface speed in Mb/s","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pci_slot","description":"PCI slot number","type":"text","hidden":true,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","hidden":true,"required":false,"index":false},{"name":"description","description":"Short description of the object a one-line string.","type":"text","hidden":true,"required":false,"index":false},{"name":"manufacturer","description":"Name of the network adapter's manufacturer.","type":"text","hidden":true,"required":false,"index":false},{"name":"connection_id","description":"Name of the network connection as it appears in the Network Connections Control Panel program.","type":"text","hidden":true,"required":false,"index":false},{"name":"connection_status","description":"State of the network adapter connection to the network.","type":"text","hidden":true,"required":false,"index":false},{"name":"enabled","description":"Indicates whether the adapter is enabled or not.","type":"integer","hidden":true,"required":false,"index":false},{"name":"physical_adapter","description":"Indicates whether the adapter is a physical or a logical adapter.","type":"integer","hidden":true,"required":false,"index":false},{"name":"speed","description":"Estimate of the current bandwidth in bits per second.","type":"integer","hidden":true,"required":false,"index":false},{"name":"service","description":"The name of the service the network adapter uses.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_enabled","description":"If TRUE, the dynamic host configuration protocol (DHCP) server automatically assigns an IP address to the computer system when establishing a network connection.","type":"integer","hidden":true,"required":false,"index":false},{"name":"dhcp_lease_expires","description":"Expiration date and time for a leased IP address that was assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_lease_obtained","description":"Date and time the lease was obtained for the IP address assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_server","description":"IP address of the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_domain","description":"Organization name followed by a period and an extension that indicates the type of organization, such as 'microsoft.com'.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_domain_suffix_search_order","description":"Array of DNS domain suffixes to be appended to the end of host names during name resolution.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_host_name","description":"Host name used to identify the local computer for authentication by some utilities.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_server_search_order","description":"Array of server IP addresses to be used in querying for DNS servers.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"interface_ipv6","description":"IPv6 configuration and stats of network interfaces.","platforms":["darwin","linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"hop_limit","description":"Current Hop Limit","type":"integer","hidden":false,"required":false,"index":false},{"name":"forwarding_enabled","description":"Enable IP forwarding","type":"integer","hidden":false,"required":false,"index":false},{"name":"redirect_accept","description":"Accept ICMP redirect messages","type":"integer","hidden":false,"required":false,"index":false},{"name":"rtadv_accept","description":"Accept ICMP Router Advertisement","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iokit_devicetree","description":"The IOKit registry matching the DeviceTree plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Device node name","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent device registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"device_path","description":"Device tree path","type":"text","hidden":false,"required":false,"index":false},{"name":"service","description":"1 if the device conforms to IOService else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the device is in a busy state else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The device reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"depth","description":"Device nested depth","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iokit_registry","description":"The full IOKit registry without selecting a plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Default name of the node","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the node is in a busy state else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The node reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"depth","description":"Node nested depth","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iptables","description":"Linux IP packet filtering and NAT tool.","platforms":["linux"],"columns":[{"name":"filter_name","description":"Packet matching filter table name.","type":"text","hidden":false,"required":false,"index":false},{"name":"chain","description":"Size of module content.","type":"text","hidden":false,"required":false,"index":false},{"name":"policy","description":"Policy that applies for this rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"target","description":"Target that applies for this rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Protocol number identification.","type":"integer","hidden":false,"required":false,"index":false},{"name":"src_port","description":"Protocol source port(s).","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_port","description":"Protocol destination port(s).","type":"text","hidden":false,"required":false,"index":false},{"name":"src_ip","description":"Source IP address.","type":"text","hidden":false,"required":false,"index":false},{"name":"src_mask","description":"Source IP address mask.","type":"text","hidden":false,"required":false,"index":false},{"name":"iniface","description":"Input interface for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"iniface_mask","description":"Input interface mask for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_ip","description":"Destination IP address.","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_mask","description":"Destination IP address mask.","type":"text","hidden":false,"required":false,"index":false},{"name":"outiface","description":"Output interface for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"outiface_mask","description":"Output interface mask for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"match","description":"Matching rule that applies.","type":"text","hidden":false,"required":false,"index":false},{"name":"packets","description":"Number of matching packets for this rule.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of matching bytes for this rule.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"kernel_extensions","description":"OS X's kernel extensions, both loaded and within the load search path.","platforms":["darwin"],"columns":[{"name":"idx","description":"Extension load tag or index","type":"integer","hidden":false,"required":false,"index":false},{"name":"refs","description":"Reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Bytes of wired memory used by extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension label","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension version","type":"text","hidden":false,"required":false,"index":false},{"name":"linked_against","description":"Indexes of extensions this extension is linked against","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Optional path to extension bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_info","description":"Basic active kernel information.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"arguments","description":"Kernel arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Kernel path","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Kernel device identifier","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_modules","description":"Linux kernel modules both loaded and within the load search path.","platforms":["linux"],"columns":[{"name":"name","description":"Module name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"bigint","hidden":false,"required":false,"index":false},{"name":"used_by","description":"Module reverse dependencies","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Kernel module status","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_panics","description":"System kernel panic logs.","platforms":["darwin"],"columns":[{"name":"path","description":"Location of log file","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Formatted time of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"A space delimited line of register:value pairs","type":"text","hidden":false,"required":false,"index":false},{"name":"frame_backtrace","description":"Backtrace of the crashed module","type":"text","hidden":false,"required":false,"index":false},{"name":"module_backtrace","description":"Modules appearing in the crashed module's backtrace","type":"text","hidden":false,"required":false,"index":false},{"name":"dependencies","description":"Module dependencies existing in crashed module's backtrace","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name corresponding to crashed thread","type":"text","hidden":false,"required":false,"index":false},{"name":"os_version","description":"Version of the operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Version of the system kernel","type":"text","hidden":false,"required":false,"index":false},{"name":"system_model","description":"Physical system model, for example 'MacBookPro12,1 (Mac-E43C1C25D4880AD6)'","type":"text","hidden":false,"required":false,"index":false},{"name":"uptime","description":"System uptime at kernel panic in nanoseconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_loaded","description":"Last loaded module before panic","type":"text","hidden":false,"required":false,"index":false},{"name":"last_unloaded","description":"Last unloaded module before panic","type":"text","hidden":false,"required":false,"index":false}]},{"name":"keychain_acls","description":"Applications that have ACL entries in the keychain.","platforms":["darwin"],"columns":[{"name":"keychain_path","description":"The path of the keychain","type":"text","hidden":false,"required":false,"index":false},{"name":"authorizations","description":"A space delimited set of authorization attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the authorized application","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The description included with the ACL entry","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"An optional label tag that may be included with the keychain entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"keychain_items","description":"Generic details about keychain items.","platforms":["darwin"],"columns":[{"name":"label","description":"Generic item name","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional item description","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional keychain comment","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Data item was created","type":"text","hidden":false,"required":false,"index":false},{"name":"modified","description":"Date of last modification","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Keychain item type (class)","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to keychain containing item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"known_hosts","description":"A line-delimited known_hosts table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local user that owns the known_hosts file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"key","description":"parsed authorized keys line","type":"text","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to known_hosts file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kva_speculative_info","description":"Display kernel virtual address and speculative execution information for the system.","platforms":["windows"],"columns":[{"name":"kva_shadow_enabled","description":"Kernel Virtual Address shadowing is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_user_global","description":"User pages are marked as global.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_pcid","description":"Kernel VA PCID flushing optimization is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_inv_pcid","description":"Kernel VA INVPCID is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_mitigations","description":"Branch Prediction mitigations are enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_system_pol_disabled","description":"Branch Predictions are disabled via system policy.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_microcode_disabled","description":"Branch Predictions are disabled due to lack of microcode update.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_spec_ctrl_supported","description":"SPEC_CTRL MSR supported by CPU Microcode.","type":"integer","hidden":false,"required":false,"index":false},{"name":"ibrs_support_enabled","description":"Windows uses IBRS.","type":"integer","hidden":false,"required":false,"index":false},{"name":"stibp_support_enabled","description":"Windows uses STIBP.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_pred_cmd_supported","description":"PRED_CMD MSR supported by CPU Microcode.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"last","description":"System logins and logouts.","platforms":["darwin","linux"],"columns":[{"name":"username","description":"Entry username","type":"text","hidden":false,"required":false,"index":false},{"name":"tty","description":"Entry terminal","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Entry type, according to ut_type types (utmp.h)","type":"integer","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Entry type name, according to ut_type types (utmp.h)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp","type":"integer","hidden":false,"required":false,"index":false},{"name":"host","description":"Entry hostname","type":"text","hidden":false,"required":false,"index":false}]},{"name":"launchd","description":"LaunchAgents and LaunchDaemons from default search paths.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to daemon or agent plist","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"File name of plist (used by launchd)","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"Daemon or agent service name","type":"text","hidden":false,"required":false,"index":false},{"name":"program","description":"Path to target program","type":"text","hidden":false,"required":false,"index":false},{"name":"run_at_load","description":"Should the program run on launch load","type":"text","hidden":false,"required":false,"index":false},{"name":"keep_alive","description":"Should the process be restarted if killed","type":"text","hidden":false,"required":false,"index":false},{"name":"on_demand","description":"Deprecated key, replaced by keep_alive","type":"text","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Skip loading this daemon or agent on boot","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Run this daemon or agent as this username","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Run this daemon or agent as this group","type":"text","hidden":false,"required":false,"index":false},{"name":"stdout_path","description":"Pipe stdout to a target path","type":"text","hidden":false,"required":false,"index":false},{"name":"stderr_path","description":"Pipe stderr to a target path","type":"text","hidden":false,"required":false,"index":false},{"name":"start_interval","description":"Frequency to run in seconds","type":"text","hidden":false,"required":false,"index":false},{"name":"program_arguments","description":"Command line arguments passed to program","type":"text","hidden":false,"required":false,"index":false},{"name":"watch_paths","description":"Key that launches daemon or agent if path is modified","type":"text","hidden":false,"required":false,"index":false},{"name":"queue_directories","description":"Similar to watch_paths but only with non-empty directories","type":"text","hidden":false,"required":false,"index":false},{"name":"inetd_compatibility","description":"Run this daemon or agent as it was launched from inetd","type":"text","hidden":false,"required":false,"index":false},{"name":"start_on_mount","description":"Run daemon or agent every time a filesystem is mounted","type":"text","hidden":false,"required":false,"index":false},{"name":"root_directory","description":"Key used to specify a directory to chroot to before launch","type":"text","hidden":false,"required":false,"index":false},{"name":"working_directory","description":"Key used to specify a directory to chdir to before launch","type":"text","hidden":false,"required":false,"index":false},{"name":"process_type","description":"Key describes the intended purpose of the job","type":"text","hidden":false,"required":false,"index":false}]},{"name":"launchd_overrides","description":"Override keys, per user, for LaunchDaemons and Agents.","platforms":["darwin"],"columns":[{"name":"label","description":"Daemon or agent service name","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Name of the override key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Overridden value","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID applied to the override, 0 applies to all","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to daemon or agent plist","type":"text","hidden":false,"required":false,"index":false}]},{"name":"listening_ports","description":"Processes with listening (bound) network sockets/ports.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"port","description":"Transport layer port","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for bind","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path for UNIX domain sockets","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"lldp_neighbors","description":"LLDP neighbors of interfaces.","platforms":["linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"rid","description":"Neighbor chassis index","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_id_type","description":"Neighbor chassis ID type","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_id","description":"Neighbor chassis ID value","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_sysname","description":"CPU brand string, contains vendor and model","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_sys_description","description":"Max number of CPU physical cores","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_bridge_capability_available","description":"Chassis bridge capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_bridge_capability_enabled","description":"Is chassis bridge capability enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_router_capability_available","description":"Chassis router capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_router_capability_enabled","description":"Chassis router capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_repeater_capability_available","description":"Chassis repeater capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_repeater_capability_enabled","description":"Chassis repeater capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_wlan_capability_available","description":"Chassis wlan capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_wlan_capability_enabled","description":"Chassis wlan capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_tel_capability_available","description":"Chassis telephone capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_tel_capability_enabled","description":"Chassis telephone capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_docsis_capability_available","description":"Chassis DOCSIS capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_docsis_capability_enabled","description":"Chassis DOCSIS capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_station_capability_available","description":"Chassis station capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_station_capability_enabled","description":"Chassis station capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_other_capability_available","description":"Chassis other capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_other_capability_enabled","description":"Chassis other capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_mgmt_ips","description":"Comma delimited list of chassis management IPS","type":"text","hidden":false,"required":false,"index":false},{"name":"port_id_type","description":"Port ID type","type":"text","hidden":false,"required":false,"index":false},{"name":"port_id","description":"Port ID value","type":"text","hidden":false,"required":false,"index":false},{"name":"port_description","description":"Port description","type":"text","hidden":false,"required":false,"index":false},{"name":"port_ttl","description":"Age of neighbor port","type":"bigint","hidden":false,"required":false,"index":false},{"name":"port_mfs","description":"Port max frame size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"port_aggregation_id","description":"Port aggregation ID","type":"text","hidden":false,"required":false,"index":false},{"name":"port_autoneg_supported","description":"Auto negotiation supported","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_enabled","description":"Is auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_mau_type","description":"MAU type","type":"text","hidden":false,"required":false,"index":false},{"name":"port_autoneg_10baset_hd_enabled","description":"10Base-T HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_10baset_fd_enabled","description":"10Base-T FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100basetx_hd_enabled","description":"100Base-TX HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100basetx_fd_enabled","description":"100Base-TX FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset2_hd_enabled","description":"100Base-T2 HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset2_fd_enabled","description":"100Base-T2 FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset4_hd_enabled","description":"100Base-T4 HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset4_fd_enabled","description":"100Base-T4 FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000basex_hd_enabled","description":"1000Base-X HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000basex_fd_enabled","description":"1000Base-X FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000baset_hd_enabled","description":"1000Base-T HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000baset_fd_enabled","description":"1000Base-T FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_device_type","description":"Dot3 power device type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_mdi_supported","description":"MDI power supported","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_mdi_enabled","description":"Is MDI power enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_paircontrol_enabled","description":"Is power pair control enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_pairs","description":"Dot3 power pairs","type":"text","hidden":false,"required":false,"index":false},{"name":"power_class","description":"Power class","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_enabled","description":"Is 802.3at enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_type","description":"802.3at power type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_source","description":"802.3at power source","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_priority","description":"802.3at power priority","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_allocated","description":"802.3at power allocated","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_requested","description":"802.3at power requested","type":"text","hidden":false,"required":false,"index":false},{"name":"med_device_type","description":"Chassis MED type","type":"text","hidden":false,"required":false,"index":false},{"name":"med_capability_capabilities","description":"Is MED capabilities enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_policy","description":"Is MED policy capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_location","description":"Is MED location capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_mdi_pse","description":"Is MED MDI PSE capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_mdi_pd","description":"Is MED MDI PD capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_inventory","description":"Is MED inventory capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_policies","description":"Comma delimited list of MED policies","type":"text","hidden":false,"required":false,"index":false},{"name":"vlans","description":"Comma delimited list of vlan ids","type":"text","hidden":false,"required":false,"index":false},{"name":"pvid","description":"Primary VLAN id","type":"text","hidden":false,"required":false,"index":false},{"name":"ppvids_supported","description":"Comma delimited list of supported PPVIDs","type":"text","hidden":false,"required":false,"index":false},{"name":"ppvids_enabled","description":"Comma delimited list of enabled PPVIDs","type":"text","hidden":false,"required":false,"index":false},{"name":"pids","description":"Comma delimited list of PIDs","type":"text","hidden":false,"required":false,"index":false}]},{"name":"load_average","description":"Displays information about the system wide load averages.","platforms":["darwin","linux"],"columns":[{"name":"period","description":"Period over which the average is calculated.","type":"text","hidden":false,"required":false,"index":false},{"name":"average","description":"Load average over the specified period.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"location_services","description":"Reports the status of the Location Services feature of the OS.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 if Location Services are enabled, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"logged_in_users","description":"Users with an active shell on the system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"type","description":"Login type","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"User login name","type":"text","hidden":false,"required":false,"index":false},{"name":"tty","description":"Device name","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"Remote hostname","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time entry was made","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"sid","description":"The user's unique security identifier","type":"text","hidden":true,"required":false,"index":false},{"name":"registry_hive","description":"HKEY_USERS registry hive","type":"text","hidden":true,"required":false,"index":false}]},{"name":"logical_drives","description":"Details for logical drives on the system. A logical drive generally represents a single partition.","platforms":["windows"],"columns":[{"name":"device_id","description":"The drive id, usually the drive name, e.g., 'C:'.","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Deprecated (always 'Unknown').","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The canonical description of the drive, e.g. 'Logical Fixed Disk', 'CD-ROM Disk'.","type":"text","hidden":false,"required":false,"index":false},{"name":"free_space","description":"The amount of free space, in bytes, of the drive (-1 on failure).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"The total amount of space, in bytes, of the drive (-1 on failure).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"file_system","description":"The file system of the drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"boot_partition","description":"True if Windows booted from this drive.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"logon_sessions","description":"Windows Logon Session.","platforms":["windows"],"columns":[{"name":"logon_id","description":"A locally unique identifier (LUID) that identifies a logon session.","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"The account name of the security principal that owns the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_domain","description":"The name of the domain used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"authentication_package","description":"The authentication package used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_type","description":"The logon method.","type":"text","hidden":false,"required":false,"index":false},{"name":"session_id","description":"The Terminal Services session identifier.","type":"integer","hidden":false,"required":false,"index":false},{"name":"logon_sid","description":"The user's security identifier (SID).","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_time","description":"The time the session owner logged on.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"logon_server","description":"The name of the server used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"dns_domain_name","description":"The DNS name for the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"upn","description":"The user principal name (UPN) for the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_script","description":"The script used for logging on.","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The home directory for the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"home_directory","description":"The home directory for the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"home_directory_drive","description":"The drive location of the home directory of the logon session.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_certificates","description":"LXD certificates information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"fingerprint","description":"SHA256 hash of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"certificate","description":"Certificate content","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster","description":"LXD cluster information.","platforms":["darwin","linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether clustering enabled (1) or not (0) on this node","type":"integer","hidden":false,"required":false,"index":false},{"name":"member_config_entity","description":"Type of configuration parameter for this node","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_name","description":"Name of configuration parameter","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_key","description":"Config key","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_value","description":"Config value","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_description","description":"Config description","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster_members","description":"LXD cluster members information.","platforms":["darwin","linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","hidden":false,"required":false,"index":false},{"name":"url","description":"URL of the node","type":"text","hidden":false,"required":false,"index":false},{"name":"database","description":"Whether the server is a database node (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the node (Online/Offline)","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the node (Online/Offline)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_images","description":"LXD images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Target architecture for the image","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"OS on which image is based","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"OS release version on which the image is based","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Image description","type":"text","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Comma-separated list of image aliases","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Filename of the image file","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of image in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auto_update","description":"Whether the image auto-updates (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"cached","description":"Whether image is cached (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"public","description":"Whether image is public (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of image creation","type":"text","hidden":false,"required":false,"index":false},{"name":"expires_at","description":"ISO time of image expiration","type":"text","hidden":false,"required":false,"index":false},{"name":"uploaded_at","description":"ISO time of image upload","type":"text","hidden":false,"required":false,"index":false},{"name":"last_used_at","description":"ISO time for the most recent use of this image in terms of container spawn","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_server","description":"Server for image update","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_protocol","description":"Protocol used for image information update and image import from source server","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_certificate","description":"Certificate for update source server","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_alias","description":"Alias of image at update source server","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_config","description":"LXD instance configuration information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Configuration parameter name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Configuration parameter value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_devices","description":"LXD instance devices information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":true,"index":false},{"name":"device","description":"Name of the device","type":"text","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device type","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Device info param name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Device info param value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instances","description":"LXD instances information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Instance state (running, stopped, etc.)","type":"text","hidden":false,"required":false,"index":false},{"name":"stateful","description":"Whether the instance is stateful(1) or not(0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"ephemeral","description":"Whether the instance is ephemeral(1) or not(0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of creation","type":"text","hidden":false,"required":false,"index":false},{"name":"base_image","description":"ID of image used to launch this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Instance architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"The OS of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Instance description","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Instance's process ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"processes","description":"Number of processes running inside this instance","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"lxd_networks","description":"LXD network information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of network","type":"text","hidden":false,"required":false,"index":false},{"name":"managed","description":"1 if network created by LXD, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_address","description":"IPv4 address","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"used_by","description":"URLs for containers using this network","type":"text","hidden":false,"required":false,"index":false},{"name":"bytes_received","description":"Number of bytes received on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bytes_sent","description":"Number of bytes sent on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"packets_received","description":"Number of packets received on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"packets_sent","description":"Number of packets sent on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hwaddr","description":"Hardware address for this network","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Network status","type":"text","hidden":false,"required":false,"index":false},{"name":"mtu","description":"MTU size","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"lxd_storage_pools","description":"LXD storage pool information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the storage pool","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Storage driver","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Storage pool source","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the storage pool","type":"text","hidden":false,"required":false,"index":false},{"name":"space_used","description":"Storage space used in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"space_total","description":"Total available storage space in bytes for this storage pool","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_used","description":"Number of inodes used","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_total","description":"Total number of inodes available in this storage pool","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"magic","description":"Magic number recognition library table.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute path to target file","type":"text","hidden":false,"required":true,"index":false},{"name":"magic_db_files","description":"Colon(:) separated list of files where the magic db file can be found. By default one of the following is used: /usr/share/file/magic/magic, /usr/share/misc/magic or /usr/share/misc/magic.mgc","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Magic number data from libmagic","type":"text","hidden":false,"required":false,"index":false},{"name":"mime_type","description":"MIME type data from libmagic","type":"text","hidden":false,"required":false,"index":false},{"name":"mime_encoding","description":"MIME encoding data from libmagic","type":"text","hidden":false,"required":false,"index":false}]},{"name":"managed_policies","description":"The managed configuration policies from AD, MDM, MCX, etc.","platforms":["darwin"],"columns":[{"name":"domain","description":"System or manager-chosen domain key","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Optional UUID assigned to policy set","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy key name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Policy value","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Policy applies only this user","type":"text","hidden":false,"required":false,"index":false},{"name":"manual","description":"1 if policy was loaded manually, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"md_devices","description":"Software RAID array settings.","platforms":["linux"],"columns":[{"name":"device_name","description":"md device name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Current state of the array","type":"text","hidden":false,"required":false,"index":false},{"name":"raid_level","description":"Current raid level of the array","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"size of the array in blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"chunk_size","description":"chunk size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"raid_disks","description":"Number of configured RAID disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"nr_raid_disks","description":"Number of partitions or disk devices to comprise the array","type":"integer","hidden":false,"required":false,"index":false},{"name":"working_disks","description":"Number of working disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"active_disks","description":"Number of active disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"failed_disks","description":"Number of failed disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"spare_disks","description":"Number of idle disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"superblock_state","description":"State of the superblock","type":"text","hidden":false,"required":false,"index":false},{"name":"superblock_version","description":"Version of the superblock","type":"text","hidden":false,"required":false,"index":false},{"name":"superblock_update_time","description":"Unix timestamp of last update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bitmap_on_mem","description":"Pages allocated in in-memory bitmap, if enabled","type":"text","hidden":false,"required":false,"index":false},{"name":"bitmap_chunk_size","description":"Bitmap chunk size","type":"text","hidden":false,"required":false,"index":false},{"name":"bitmap_external_file","description":"External referenced bitmap file","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_progress","description":"Progress of the recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_finish","description":"Estimated duration of recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_speed","description":"Speed of recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_progress","description":"Progress of the resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_finish","description":"Estimated duration of resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_speed","description":"Speed of resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_progress","description":"Progress of the reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_finish","description":"Estimated duration of reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_speed","description":"Speed of reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_progress","description":"Progress of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_finish","description":"Estimated duration of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_speed","description":"Speed of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"unused_devices","description":"Unused devices","type":"text","hidden":false,"required":false,"index":false},{"name":"other","description":"Other information associated with array from /proc/mdstat","type":"text","hidden":false,"required":false,"index":false}]},{"name":"md_drives","description":"Drive devices used for Software RAID.","platforms":["linux"],"columns":[{"name":"md_device_name","description":"md device name","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_name","description":"Drive device name","type":"text","hidden":false,"required":false,"index":false},{"name":"slot","description":"Slot position of disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the drive","type":"text","hidden":false,"required":false,"index":false}]},{"name":"md_personalities","description":"Software RAID setting supported by the kernel.","platforms":["linux"],"columns":[{"name":"name","description":"Name of personality supported by kernel","type":"text","hidden":false,"required":false,"index":false}]},{"name":"mdfind","description":"Run searches against the spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file returned from spotlight","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"The query that was run to find the file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"mdls","description":"Query file metadata in the Spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the metadata key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value stored in the metadata key","type":"text","hidden":false,"required":false,"index":false},{"name":"valuetype","description":"CoreFoundation type of data stored in value","type":"text","hidden":true,"required":false,"index":false}]},{"name":"memory_array_mapped_addresses","description":"Data associated for address mapping of physical memory arrays.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_handle","description":"Handle of the memory array associated with this structure","type":"text","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"partition_width","description":"Number of memory devices that form a single row of memory for the address partition of this structure","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_arrays","description":"Data associated with collection of memory devices that operate to form a memory address.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the array","type":"text","hidden":false,"required":false,"index":false},{"name":"location","description":"Physical location of the memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"use","description":"Function for which the array is used","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_error_correction","description":"Primary hardware error correction or detection method supported","type":"text","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"Maximum capacity of array in gigabytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory_error_info_handle","description":"Handle, or instance number, associated with any error that was detected for the array","type":"text","hidden":false,"required":false,"index":false},{"name":"number_memory_devices","description":"Number of memory devices on array","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_device_mapped_addresses","description":"Data associated for address mapping of physical memory devices.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_device_handle","description":"Handle of the memory device structure associated with this structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_mapped_address_handle","description":"Handle of the memory array mapped address to which this device range is mapped to","type":"text","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"partition_row_position","description":"Identifies the position of the referenced memory device in a row of the address partition","type":"integer","hidden":false,"required":false,"index":false},{"name":"interleave_position","description":"The position of the device in a interleave, i.e. 0 indicates non-interleave, 1 indicates 1st interleave, 2 indicates 2nd interleave, etc.","type":"integer","hidden":false,"required":false,"index":false},{"name":"interleave_data_depth","description":"The max number of consecutive rows from memory device that are accessed in a single interleave transfer; 0 indicates device is non-interleave","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_devices","description":"Physical memory device (type 17) information retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure in SMBIOS","type":"text","hidden":false,"required":false,"index":false},{"name":"array_handle","description":"The memory array that the device is attached to","type":"text","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Implementation form factor for this memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"total_width","description":"Total width, in bits, of this memory device, including any check or error-correction bits","type":"integer","hidden":false,"required":false,"index":false},{"name":"data_width","description":"Data width, in bits, of this memory device","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of memory device in Megabyte","type":"integer","hidden":false,"required":false,"index":false},{"name":"set","description":"Identifies if memory device is one of a set of devices. A value of 0 indicates no set affiliation.","type":"integer","hidden":false,"required":false,"index":false},{"name":"device_locator","description":"String number of the string that identifies the physically-labeled socket or board position where the memory device is located","type":"text","hidden":false,"required":false,"index":false},{"name":"bank_locator","description":"String number of the string that identifies the physically-labeled bank where the memory device is located","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_type","description":"Type of memory used","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_type_details","description":"Additional details for memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"max_speed","description":"Max speed of memory device in megatransfers per second (MT/s)","type":"integer","hidden":false,"required":false,"index":false},{"name":"configured_clock_speed","description":"Configured speed of memory device in megatransfers per second (MT/s)","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Manufacturer ID string","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Serial number of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"asset_tag","description":"Manufacturer specific asset tag of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"part_number","description":"Manufacturer specific serial number of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"min_voltage","description":"Minimum operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_voltage","description":"Maximum operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false},{"name":"configured_voltage","description":"Configured operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_error_info","description":"Data associated with errors of a physical memory array.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"error_type","description":"type of error associated with current error status for array or device","type":"text","hidden":false,"required":false,"index":false},{"name":"error_granularity","description":"Granularity to which the error can be resolved","type":"text","hidden":false,"required":false,"index":false},{"name":"error_operation","description":"Memory access operation that caused the error","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_syndrome","description":"Vendor specific ECC syndrome or CRC data associated with the erroneous access","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_error_address","description":"32 bit physical address of the error based on the addressing of the bus to which the memory array is connected","type":"text","hidden":false,"required":false,"index":false},{"name":"device_error_address","description":"32 bit physical address of the error relative to the start of the failing memory address, in bytes","type":"text","hidden":false,"required":false,"index":false},{"name":"error_resolution","description":"Range, in bytes, within which this error can be determined, when an error address is given","type":"text","hidden":false,"required":false,"index":false}]},{"name":"memory_info","description":"Main memory information in bytes.","platforms":["linux"],"columns":[{"name":"memory_total","description":"Total amount of physical RAM, in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_free","description":"The amount of physical RAM, in bytes, left unused by the system","type":"bigint","hidden":false,"required":false,"index":false},{"name":"buffers","description":"The amount of physical RAM, in bytes, used for file buffers","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cached","description":"The amount of physical RAM, in bytes, used as cache memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_cached","description":"The amount of swap, in bytes, used as cache memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"active","description":"The total amount of buffer or page cache memory, in bytes, that is in active use","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"The total amount of buffer or page cache memory, in bytes, that are free and available","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_total","description":"The total amount of swap available, in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_free","description":"The total amount of swap free, in bytes","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"memory_map","description":"OS memory region map.","platforms":["linux"],"columns":[{"name":"name","description":"Region name","type":"text","hidden":false,"required":false,"index":false},{"name":"start","description":"Start address of memory region","type":"text","hidden":false,"required":false,"index":false},{"name":"end","description":"End address of memory region","type":"text","hidden":false,"required":false,"index":false}]},{"name":"mounts","description":"System mounted devices and filesystems (not process specific).","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Mounted device","type":"text","hidden":false,"required":false,"index":false},{"name":"device_alias","description":"Mounted device alias","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Mounted device path","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Mounted device type","type":"text","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Block size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Mounted device used blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_free","description":"Mounted device free blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_available","description":"Mounted device available blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Mounted device used inodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_free","description":"Mounted device free inodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"Mounted device flags","type":"text","hidden":false,"required":false,"index":false}]},{"name":"msr","description":"Various pieces of data stored in the model specific register per processor. NOTE: the msr kernel module must be enabled, and osquery must be run as root.","platforms":["linux"],"columns":[{"name":"processor_number","description":"The processor number as reported in /proc/cpuinfo","type":"bigint","hidden":false,"required":false,"index":false},{"name":"turbo_disabled","description":"Whether the turbo feature is disabled.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"turbo_ratio_limit","description":"The turbo feature ratio limit.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"platform_info","description":"Platform information.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"perf_ctl","description":"Performance setting for the processor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"perf_status","description":"Performance status for the processor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"feature_control","description":"Bitfield controlling enabled features.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_power_limit","description":"Run Time Average Power Limiting power limit.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_energy_status","description":"Run Time Average Power Limiting energy status.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_power_units","description":"Run Time Average Power Limiting power units.","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"nfs_shares","description":"NFS shares exported by the host.","platforms":["darwin"],"columns":[{"name":"share","description":"Filesystem path to the share","type":"text","hidden":false,"required":false,"index":false},{"name":"options","description":"Options string set on the export share","type":"text","hidden":false,"required":false,"index":false},{"name":"readonly","description":"1 if the share is exported readonly else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"npm_packages","description":"Lists all npm packages in a directory or globally installed in a system.","platforms":["linux"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Package author name","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Module's package.json path","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"Node module's directory where this package is located","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"ntdomains","description":"Display basic NT domain information of a Windows machine.","platforms":["windows"],"columns":[{"name":"name","description":"The label by which the object is known.","type":"text","hidden":false,"required":false,"index":false},{"name":"client_site_name","description":"The name of the site where the domain controller is configured.","type":"text","hidden":false,"required":false,"index":false},{"name":"dc_site_name","description":"The name of the site where the domain controller is located.","type":"text","hidden":false,"required":false,"index":false},{"name":"dns_forest_name","description":"The name of the root of the DNS tree.","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_controller_address","description":"The IP Address of the discovered domain controller..","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_controller_name","description":"The name of the discovered domain controller.","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_name","description":"The name of the domain.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"The current status of the domain object.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ntfs_acl_permissions","description":"Retrieve NTFS ACL permission information for files and directories.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the file or directory.","type":"text","hidden":false,"required":true,"index":false},{"name":"type","description":"Type of access mode for the access control entry.","type":"text","hidden":false,"required":false,"index":false},{"name":"principal","description":"User or group to which the ACE applies.","type":"text","hidden":false,"required":false,"index":false},{"name":"access","description":"Specific permissions that indicate the rights described by the ACE.","type":"text","hidden":false,"required":false,"index":false},{"name":"inherited_from","description":"The inheritance policy of the ACE.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ntfs_journal_events","description":"Track time/action changes to files specified in configuration data.","platforms":["windows"],"columns":[{"name":"action","description":"Change action (Write, Delete, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category that the event originated from","type":"text","hidden":false,"required":false,"index":false},{"name":"old_path","description":"Old path (renames only)","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path","type":"text","hidden":false,"required":false,"index":false},{"name":"record_timestamp","description":"Journal record timestamp","type":"text","hidden":false,"required":false,"index":false},{"name":"record_usn","description":"The update sequence number that identifies the journal record","type":"text","hidden":false,"required":false,"index":false},{"name":"node_ref_number","description":"The ordinal that associates a journal record with a filename","type":"text","hidden":false,"required":false,"index":false},{"name":"parent_ref_number","description":"The ordinal that associates a journal record with a filename's parent directory","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"The drive letter identifying the source journal","type":"text","hidden":false,"required":false,"index":false},{"name":"file_attributes","description":"File attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"partial","description":"Set to 1 if either path or old_path only contains the file or folder name","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"nvram","description":"Apple NVRAM variable listing.","platforms":["darwin"],"columns":[{"name":"name","description":"Variable name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type (CFData, CFString, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Raw variable data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"oem_strings","description":"OEM defined strings retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the Type 11 structure","type":"text","hidden":false,"required":false,"index":false},{"name":"number","description":"The string index of the structure","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the OEM string","type":"text","hidden":false,"required":false,"index":false}]},{"name":"office_mru","description":"View recently opened Office documents.","platforms":["windows"],"columns":[{"name":"application","description":"Associated Office application","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Office application version number","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File path","type":"text","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"Most recent opened time file was opened","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID","type":"text","hidden":false,"required":false,"index":false}]},{"name":"os_version","description":"A single row containing the operating system name and version.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Distribution or product name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Pretty, suitable for presentation, OS version","type":"text","hidden":false,"required":false,"index":false},{"name":"major","description":"Major release version","type":"integer","hidden":false,"required":false,"index":false},{"name":"minor","description":"Minor release version","type":"integer","hidden":false,"required":false,"index":false},{"name":"patch","description":"Optional patch release","type":"integer","hidden":false,"required":false,"index":false},{"name":"build","description":"Optional build-specific or variant string","type":"text","hidden":false,"required":false,"index":false},{"name":"platform","description":"OS Platform or ID","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_like","description":"Closely related platforms","type":"text","hidden":false,"required":false,"index":false},{"name":"codename","description":"OS version codename","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"OS Architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"The install date of the OS.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"osquery_events","description":"Information about the event publishers and subscribers.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"Event publisher or subscriber name","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the associated publisher","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Either publisher or subscriber","type":"text","hidden":false,"required":false,"index":false},{"name":"subscriptions","description":"Number of subscriptions the publisher received or subscriber used","type":"integer","hidden":false,"required":false,"index":false},{"name":"events","description":"Number of events emitted or received since osquery started","type":"integer","hidden":false,"required":false,"index":false},{"name":"refreshes","description":"Publisher only: number of runloop restarts","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 if the publisher or subscriber is active else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_extensions","description":"List of active osquery extensions.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"uuid","description":"The transient ID assigned for communication","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension's name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension's version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk_version","description":"osquery SDK version used to build the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the extension's Thrift connection or library path","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"SDK extension type: extension or module","type":"text","hidden":false,"required":false,"index":false}]},{"name":"osquery_flags","description":"Configurable flags that modify osquery's behavior.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"Flag name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Flag type","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Flag description","type":"text","hidden":false,"required":false,"index":false},{"name":"default_value","description":"Flag default value","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Flag value","type":"text","hidden":false,"required":false,"index":false},{"name":"shell_only","description":"Is the flag shell only?","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_info","description":"Top level information about the running version of osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"pid","description":"Process (or thread/handle) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_id","description":"Unique, long-lived ID per instance of osquery","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"osquery toolkit version","type":"text","hidden":false,"required":false,"index":false},{"name":"config_hash","description":"Hash of the working configuration state","type":"text","hidden":false,"required":false,"index":false},{"name":"config_valid","description":"1 if the config was loaded and considered valid, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"extensions","description":"osquery extensions status","type":"text","hidden":false,"required":false,"index":false},{"name":"build_platform","description":"osquery toolkit build platform","type":"text","hidden":false,"required":false,"index":false},{"name":"build_distro","description":"osquery toolkit platform distribution name (os version)","type":"text","hidden":false,"required":false,"index":false},{"name":"start_time","description":"UNIX time in seconds when the process started","type":"integer","hidden":false,"required":false,"index":false},{"name":"watcher","description":"Process (or thread/handle) ID of optional watcher process","type":"integer","hidden":false,"required":false,"index":false},{"name":"platform_mask","description":"The osquery platform bitmask","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_packs","description":"Information about the current query packs that are loaded in osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"The given name for this query pack","type":"text","hidden":false,"required":false,"index":false},{"name":"platform","description":"Platforms this query is supported on","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Minimum osquery version that this query will run on","type":"text","hidden":false,"required":false,"index":false},{"name":"shard","description":"Shard restriction limit, 1-100, 0 meaning no restriction","type":"integer","hidden":false,"required":false,"index":false},{"name":"discovery_cache_hits","description":"The number of times that the discovery query used cached values since the last time the config was reloaded","type":"integer","hidden":false,"required":false,"index":false},{"name":"discovery_executions","description":"The number of times that the discovery queries have been executed since the last time the config was reloaded","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"Whether this pack is active (the version, platform and discovery queries match) yes=1, no=0.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_registry","description":"List the osquery registry plugins.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"registry","description":"Name of the osquery registry","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the plugin item","type":"text","hidden":false,"required":false,"index":false},{"name":"owner_uuid","description":"Extension route UUID (0 for core)","type":"integer","hidden":false,"required":false,"index":false},{"name":"internal","description":"1 If the plugin is internal else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If this plugin is active else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_schedule","description":"Information about the current queries that are scheduled in osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"The given name for this query","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"The exact query to run","type":"text","hidden":false,"required":false,"index":false},{"name":"interval","description":"The interval in seconds to run this query, not an exact interval","type":"integer","hidden":false,"required":false,"index":false},{"name":"executions","description":"Number of times the query was executed","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_executed","description":"UNIX time stamp in seconds of the last completed execution","type":"bigint","hidden":false,"required":false,"index":false},{"name":"denylisted","description":"1 if the query is denylisted else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"output_size","description":"Total number of bytes generated by the query","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wall_time","description":"Total wall time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"user_time","description":"Total user time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_time","description":"Total system time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"average_memory","description":"Average private memory left after executing","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"package_bom","description":"OS X package bill of materials (BOM) file list.","platforms":["darwin"],"columns":[{"name":"filepath","description":"Package file or directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Expected user of file or directory","type":"integer","hidden":false,"required":false,"index":false},{"name":"gid","description":"Expected group of file or directory","type":"integer","hidden":false,"required":false,"index":false},{"name":"mode","description":"Expected permissions","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Timestamp the file was installed","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of package bom","type":"text","hidden":false,"required":true,"index":false}]},{"name":"package_install_history","description":"OS X package install history.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Label packageIdentifiers","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Label date as UNIX timestamp","type":"integer","hidden":false,"required":false,"index":false},{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package display version","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Install source: usually the installer process name","type":"text","hidden":false,"required":false,"index":false},{"name":"content_type","description":"Package content_type (optional)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"package_receipts","description":"OS X package receipt details.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Package domain identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"package_filename","description":"Filename of original .pkg file","type":"text","hidden":true,"required":false,"index":false},{"name":"version","description":"Installed package version","type":"text","hidden":false,"required":false,"index":false},{"name":"location","description":"Optional relative install path on volume","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Timestamp of install time","type":"double","hidden":false,"required":false,"index":false},{"name":"installer_name","description":"Name of installer process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of receipt plist","type":"text","hidden":false,"required":false,"index":false}]},{"name":"patches","description":"Lists all the patches applied. Note: This does not include patches applied via MSI or downloaded from Windows Update (e.g. Service Packs).","platforms":["windows"],"columns":[{"name":"csname","description":"The name of the host the patch is installed on.","type":"text","hidden":false,"required":false,"index":false},{"name":"hotfix_id","description":"The KB ID of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"caption","description":"Short description of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Fuller description of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"fix_comments","description":"Additional comments about the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"installed_by","description":"The system context in which the patch as installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the patch was installed. Lack of a value does not indicate that the patch was not installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"installed_on","description":"The date when the patch was installed.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"pci_devices","description":"PCI devices active on the host system.","platforms":["darwin","linux"],"columns":[{"name":"pci_slot","description":"PCI Device used slot","type":"text","hidden":false,"required":false,"index":false},{"name":"pci_class","description":"PCI Device class","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"PCI Device used driver","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"PCI Device vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded PCI Device vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"PCI Device model","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded PCI Device model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"pci_class_id","description":"PCI Device class ID in hex format","type":"text","hidden":true,"required":false,"index":false},{"name":"pci_subclass_id","description":"PCI Device subclass in hex format","type":"text","hidden":true,"required":false,"index":false},{"name":"pci_subclass","description":"PCI Device subclass","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_vendor_id","description":"Vendor ID of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_vendor","description":"Vendor of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_model_id","description":"Model ID of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_model","description":"Device description of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false}]},{"name":"physical_disk_performance","description":"Provides provides raw data from performance counters that monitor hard or fixed disk drives on the system.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the physical disk","type":"text","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_read","description":"Average number of bytes transferred from the disk during read operations","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_write","description":"Average number of bytes transferred to the disk during write operations","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_read_queue_length","description":"Average number of read requests that were queued for the selected disk during the sample interval","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_write_queue_length","description":"Average number of write requests that were queued for the selected disk during the sample interval","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_read","description":"Average time, in seconds, of a read operation of data from the disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_write","description":"Average time, in seconds, of a write operation of data to the disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"current_disk_queue_length","description":"Number of requests outstanding on the disk at the time the performance data is collected","type":"integer","hidden":false,"required":false,"index":false},{"name":"percent_disk_read_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_disk_write_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing write requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_disk_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read or write requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_idle_time","description":"Percentage of time during the sample interval that the disk was idle","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"pipes","description":"Named and Anonymous pipes.","platforms":["windows"],"columns":[{"name":"pid","description":"Process ID of the process to which the pipe belongs","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the pipe","type":"text","hidden":false,"required":false,"index":false},{"name":"instances","description":"Number of instances of the named pipe","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_instances","description":"The maximum number of instances creatable for this pipe","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"The flags indicating whether this pipe connection is a server or client end, and if the pipe for sending messages or bytes","type":"text","hidden":false,"required":false,"index":false}]},{"name":"pkg_packages","description":"pkgng packages that are currently installed on the host system.","platforms":["freebsd"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"flatsize","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","hidden":false,"required":false,"index":false}]},{"name":"platform_info","description":"Information about EFI/UEFI/ROM and platform/boot.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"vendor","description":"Platform code vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Platform code version","type":"text","hidden":false,"required":false,"index":false},{"name":"date","description":"Self-reported platform code update date","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"BIOS major and minor revision","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Relative address of firmware mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes of firmware","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_size","description":"(Optional) size of firmware volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"extra","description":"Platform-specific additional information","type":"text","hidden":false,"required":false,"index":false}]},{"name":"plist","description":"Read and parse a plist file.","platforms":["darwin"],"columns":[{"name":"key","description":"Preference top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intermediate key path, includes lists/dicts","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"(required) read preferences from a plist","type":"text","hidden":false,"required":true,"index":false}]},{"name":"portage_keywords","description":"A summary about portage configurations like keywords, mask and unmask.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","hidden":false,"required":false,"index":false},{"name":"keyword","description":"The keyword applied to the package","type":"text","hidden":false,"required":false,"index":false},{"name":"mask","description":"If the package is masked","type":"integer","hidden":false,"required":false,"index":false},{"name":"unmask","description":"If the package is unmasked","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"portage_packages","description":"List of currently installed packages.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","hidden":false,"required":false,"index":false},{"name":"slot","description":"The slot used by package","type":"text","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Unix time when package was built","type":"bigint","hidden":false,"required":false,"index":false},{"name":"repository","description":"From which repository the ebuild was used","type":"text","hidden":false,"required":false,"index":false},{"name":"eapi","description":"The eapi for the ebuild","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the package","type":"bigint","hidden":false,"required":false,"index":false},{"name":"world","description":"If package is in the world file","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"portage_use","description":"List of enabled portage USE values for specific package.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version of the installed package","type":"text","hidden":false,"required":false,"index":false},{"name":"use","description":"USE flag which has been enabled for package","type":"text","hidden":false,"required":false,"index":false}]},{"name":"power_sensors","description":"Machine power (currents, voltages, wattages, etc) sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on OS X","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The sensor category: currents, voltage, wattage","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of power source","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Power in Watts","type":"text","hidden":false,"required":false,"index":false}]},{"name":"powershell_events","description":"Powershell script blocks reconstructed to their full script content, this table requires script block logging to be enabled.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received by the osquery event publisher","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the Powershell script event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"script_block_id","description":"The unique GUID of the powershell script to which this block belongs","type":"text","hidden":false,"required":false,"index":false},{"name":"script_block_count","description":"The total number of script blocks for this script","type":"integer","hidden":false,"required":false,"index":false},{"name":"script_text","description":"The text content of the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"script_name","description":"The name of the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"script_path","description":"The path for the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"cosine_similarity","description":"How similar the Powershell script is to a provided 'normal' character frequency","type":"double","hidden":false,"required":false,"index":false}]},{"name":"preferences","description":"OS X defaults and managed preferences.","platforms":["darwin"],"columns":[{"name":"domain","description":"Application ID usually in com.name.product format","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Preference top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intemediate key path, includes lists/dicts","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","hidden":false,"required":false,"index":false},{"name":"forced","description":"1 if the value is forced/managed, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"username","description":"(optional) read preferences for a specific user","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"'current' or 'any' host, where 'current' takes precedence","type":"text","hidden":false,"required":false,"index":false}]},{"name":"prefetch","description":"Prefetch files show metadata related to file execution.","platforms":["windows"],"columns":[{"name":"path","description":"Prefetch file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Executable filename.","type":"text","hidden":false,"required":false,"index":false},{"name":"hash","description":"Prefetch CRC hash.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Most recent time application was run.","type":"integer","hidden":false,"required":false,"index":false},{"name":"other_run_times","description":"Other execution times in prefetch file.","type":"text","hidden":false,"required":false,"index":false},{"name":"run_count","description":"Number of times the application has been run.","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Application file size.","type":"integer","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_creation","description":"Volume creation time.","type":"text","hidden":false,"required":false,"index":false},{"name":"accessed_files_count","description":"Number of files accessed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"accessed_directories_count","description":"Number of directories accessed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"accessed_files","description":"Files accessed by application within ten seconds of launch.","type":"text","hidden":false,"required":false,"index":false},{"name":"accessed_directories","description":"Directories accessed by application within ten seconds of launch.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_envs","description":"A key/value table of environment variables for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"key","description":"Environment variable name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_events","description":"Track time/action process executions.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"File mode permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline_size","description":"Actual size (bytes) of command line arguments","type":"bigint","hidden":true,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","hidden":true,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","hidden":true,"required":false,"index":false},{"name":"env_size","description":"Actual size (bytes) of environment list","type":"bigint","hidden":true,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"File owner user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"owner_gid","description":"File owner group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"File last access in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"File modification in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"File last metadata change in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"btime","description":"File creation in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"overflows","description":"List of structures that overflowed","type":"text","hidden":true,"required":false,"index":false},{"name":"parent","description":"Process parent's PID, or -1 if cannot be determined.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"status","description":"OpenBSM Attribute: Status of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"suid","description":"Saved user ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"sgid","description":"Saved group ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"syscall","description":"Syscall name: fork, vfork, clone, execve, execveat","type":"text","hidden":true,"required":false,"index":false}]},{"name":"process_file_events","description":"A File Integrity Monitor implementation using the audit service.","platforms":["linux"],"columns":[{"name":"operation","description":"Operation type","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ppid","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"executable","description":"The executable path","type":"text","hidden":false,"required":false,"index":false},{"name":"partial","description":"True if this is a partial event (i.e.: this process existed before we started osquery)","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The current working directory of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"dest_path","description":"The canonical path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The uid of the process performing the action","type":"text","hidden":false,"required":false,"index":false},{"name":"gid","description":"The gid of the process performing the action","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"process_memory_map","description":"Process memory mapped files and pseudo device/regions.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"start","description":"Virtual start address (hex)","type":"text","hidden":false,"required":false,"index":false},{"name":"end","description":"Virtual end address (hex)","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"r=read, w=write, x=execute, p=private (cow)","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset into mapped path","type":"bigint","hidden":false,"required":false,"index":false},{"name":"device","description":"MA:MI Major/minor device ID","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Mapped path inode, 0 means uninitialized (BSS)","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to mapped file or mapped type","type":"text","hidden":false,"required":false,"index":false},{"name":"pseudo","description":"1 If path is a pseudo path, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"process_namespaces","description":"Linux namespaces for processes running on the host system.","platforms":["linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"ipc_namespace","description":"ipc namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"mnt_namespace","description":"mnt namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"net namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_namespace","description":"pid namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"user_namespace","description":"user namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"uts_namespace","description":"uts namespace inode","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_files","description":"File descriptors for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fd","description":"Process-specific file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Filesystem path of descriptor","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_pipes","description":"Pipes and partner processes for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fd","description":"File descriptor","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Pipe open mode (r/w)","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Pipe inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"type","description":"Pipe Type: named vs unnamed/anonymous","type":"text","hidden":false,"required":false,"index":false},{"name":"partner_pid","description":"Process ID of partner process sharing a particular pipe","type":"bigint","hidden":false,"required":false,"index":false},{"name":"partner_fd","description":"File descriptor of shared pipe at partner's end","type":"bigint","hidden":false,"required":false,"index":false},{"name":"partner_mode","description":"Mode of shared pipe at partner's end","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_sockets","description":"Processes which have open network sockets on the system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Socket local address","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Socket remote address","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Socket local port","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Socket remote port","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"For UNIX sockets (family=AF_UNIX), the domain path","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"TCP socket state","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"protection_type","description":"The protection type of the process","type":"text","hidden":true,"required":false,"index":false},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"programs","description":"Represents products as they are installed by Windows Installer. A product generally correlates to one installation package on Windows. Some fields may be blank as Windows installation details are left to the discretion of the product author.","platforms":["windows"],"columns":[{"name":"name","description":"Commonly used product name.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Product version information.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_location","description":"The installation location directory of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_source","description":"The installation source of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"language","description":"The language of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the product supplier.","type":"text","hidden":false,"required":false,"index":false},{"name":"uninstall_string","description":"Path and filename of the uninstaller.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Date that this product was installed on the system. ","type":"text","hidden":false,"required":false,"index":false},{"name":"identifying_number","description":"Product identification such as a serial number on software, or a die number on a hardware chip.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"prometheus_metrics","description":"Retrieve metrics from a Prometheus server.","platforms":["darwin","linux"],"columns":[{"name":"target_name","description":"Address of prometheus target","type":"text","hidden":false,"required":false,"index":false},{"name":"metric_name","description":"Name of collected Prometheus metric","type":"text","hidden":false,"required":false,"index":false},{"name":"metric_value","description":"Value of collected Prometheus metric","type":"double","hidden":false,"required":false,"index":false},{"name":"timestamp_ms","description":"Unix timestamp of collected data in MS","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"python_packages","description":"Python packages installed in a system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where Python modules are located","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"quicklook_cache","description":"Files and thumbnails within OS X's Quicklook Cache.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of file","type":"text","hidden":false,"required":false,"index":false},{"name":"rowid","description":"Quicklook file rowid key","type":"integer","hidden":false,"required":false,"index":false},{"name":"fs_id","description":"Quicklook file fs_id key","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_id","description":"Parsed volume ID from fs_id","type":"integer","hidden":false,"required":false,"index":false},{"name":"inode","description":"Parsed file ID (inode) from fs_id","type":"integer","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Parsed version date field","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Parsed version size field","type":"bigint","hidden":false,"required":false,"index":false},{"name":"label","description":"Parsed version 'gen' field","type":"text","hidden":false,"required":false,"index":false},{"name":"last_hit_date","description":"Apple date format for last thumbnail cache hit","type":"integer","hidden":false,"required":false,"index":false},{"name":"hit_count","description":"Number of cache hits on thumbnail","type":"text","hidden":false,"required":false,"index":false},{"name":"icon_mode","description":"Thumbnail icon mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cache_path","description":"Path to cache data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"registry","description":"All of the Windows registry hives.","platforms":["windows"],"columns":[{"name":"key","description":"Name of the key to search for","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Full path to the value","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the registry value entry","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the registry value, or 'subkey' if item is a subkey","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data content of registry value","type":"text","hidden":false,"required":false,"index":false},{"name":"mtime","description":"timestamp of the most recent registry write","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"routes","description":"The active route table for the host system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"destination","description":"Destination IP address","type":"text","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Netmask length","type":"integer","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Route gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Route source","type":"text","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags to describe route","type":"integer","hidden":false,"required":false,"index":false},{"name":"interface","description":"Route local interface","type":"text","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Maximum Transmission Unit for the route","type":"integer","hidden":false,"required":false,"index":false},{"name":"metric","description":"Cost of route. Lowest is preferred","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of route","type":"text","hidden":false,"required":false,"index":false},{"name":"hopcount","description":"Max hops expected","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"rpm_package_files","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"package","description":"RPM package name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File path within the package","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"File default username from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"File default groupname from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"File permissions mode from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size in bytes from RPM info DB","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 file digest from RPM info DB","type":"text","hidden":false,"required":false,"index":false}]},{"name":"rpm_packages","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"name","description":"RPM package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"Package release","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source RPM package name (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the package contents","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","hidden":false,"required":false,"index":false},{"name":"epoch","description":"Package epoch value","type":"integer","hidden":false,"required":false,"index":false},{"name":"install_time","description":"When the package was installed","type":"integer","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Package vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"package_group","description":"Package group","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"running_apps","description":"macOS applications currently running on the host system.","platforms":["darwin"],"columns":[{"name":"pid","description":"The pid of the application","type":"integer","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"The bundle identifier of the application","type":"text","hidden":false,"required":false,"index":false},{"name":"is_active","description":"1 if the application is in focus, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"safari_extensions","description":"Safari browser extension details for all users.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension long version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Bundle SDK used to compile extension","type":"text","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Optional developer identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional extension description text","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension XAR bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sandboxes","description":"OS X application sandboxes container details.","platforms":["darwin"],"columns":[{"name":"label","description":"UTI-format bundle or label ID","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"Sandbox owner","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Application sandboxings enabled on container","type":"integer","hidden":false,"required":false,"index":false},{"name":"build_id","description":"Sandbox-specific identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"Application bundle used by the sandbox","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to sandbox container directory","type":"text","hidden":false,"required":false,"index":false}]},{"name":"scheduled_tasks","description":"Lists all of the tasks in the Windows task scheduler.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Actions executed by the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the executable to be run","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether or not the scheduled task is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"hidden","description":"Whether or not the task is visible in the UI","type":"integer","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Timestamp the task last ran","type":"bigint","hidden":false,"required":false,"index":false},{"name":"next_run_time","description":"Timestamp the task is scheduled to run next","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_run_message","description":"Exit status message of the last task run","type":"text","hidden":false,"required":false,"index":false},{"name":"last_run_code","description":"Exit status code of the last task run","type":"text","hidden":false,"required":false,"index":false}]},{"name":"screenlock","description":"macOS screenlock status for the current logged in user context.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 If a password is required after sleep or the screensaver begins; else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"grace_period","description":"The amount of time in seconds the screen must be asleep or the screensaver on before a password is required on-wake. 0 = immediately; -1 = no password is required on-wake","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"seccomp_events","description":"A virtual table that tracks seccomp events.","platforms":["linux"],"columns":[{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID (loginuid) of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"ses","description":"Session ID of the session from which the analyzed process was invoked","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"exe","description":"The path to the executable that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"sig","description":"Signal value sent to process by seccomp","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Information about the CPU architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"syscall","description":"Type of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"compat","description":"Is system call in compatibility mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ip","description":"Instruction pointer value","type":"text","hidden":false,"required":false,"index":false},{"name":"code","description":"The seccomp action","type":"text","hidden":false,"required":false,"index":false}]},{"name":"secureboot","description":"Secure Boot UEFI Settings.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"secure_boot","description":"Whether secure boot is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"setup_mode","description":"Whether setup mode is enabled","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"selinux_events","description":"Track SELinux events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Message","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"selinux_settings","description":"Track active SELinux settings.","platforms":["linux"],"columns":[{"name":"scope","description":"Where the key is located inside the SELinuxFS mount point.","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Key or class name.","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Active value.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"services","description":"Lists all installed Windows services and their relevant data.","platforms":["windows"],"columns":[{"name":"name","description":"Service name","type":"text","hidden":false,"required":false,"index":false},{"name":"service_type","description":"Service Type: OWN_PROCESS, SHARE_PROCESS and maybe Interactive (can interact with the desktop)","type":"text","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Service Display name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Service Current status: STOPPED, START_PENDING, STOP_PENDING, RUNNING, CONTINUE_PENDING, PAUSE_PENDING, PAUSED","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"the Process ID of the service","type":"integer","hidden":false,"required":false,"index":false},{"name":"start_type","description":"Service start type: BOOT_START, SYSTEM_START, AUTO_START, DEMAND_START, DISABLED","type":"text","hidden":false,"required":false,"index":false},{"name":"win32_exit_code","description":"The error code that the service uses to report an error that occurs when it is starting or stopping","type":"integer","hidden":false,"required":false,"index":false},{"name":"service_exit_code","description":"The service-specific error code that the service returns when an error occurs while the service is starting or stopping","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Service Executable","type":"text","hidden":false,"required":false,"index":false},{"name":"module_path","description":"Path to ServiceDll","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Service Description","type":"text","hidden":false,"required":false,"index":false},{"name":"user_account","description":"The name of the account that the service process will be logged on as when it runs. This name can be of the form Domain\\UserName. If the account belongs to the built-in domain, the name can be of the form .\\UserName.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shadow","description":"Local system users encrypted passwords and related information. Please note, that you usually need superuser rights to access `/etc/shadow`.","platforms":["linux"],"columns":[{"name":"password_status","description":"Password status","type":"text","hidden":false,"required":false,"index":false},{"name":"hash_alg","description":"Password hashing algorithm","type":"text","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Date of last password change (starting from UNIX epoch date)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimal number of days between password changes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum number of days between password changes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"warning","description":"Number of days before password expires to warn user about it","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Number of days after password expires until account is blocked","type":"bigint","hidden":false,"required":false,"index":false},{"name":"expire","description":"Number of days since UNIX epoch date until account is disabled","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flag","description":"Reserved","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shared_folders","description":"Folders available to others via SMB or AFP.","platforms":["darwin"],"columns":[{"name":"name","description":"The shared name of the folder as it appears to other users","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute path of shared folder on the local system","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shared_memory","description":"OS shared memory regions.","platforms":["linux"],"columns":[{"name":"shmid","description":"Shared memory segment ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"User ID of owning process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creator_uid","description":"User ID of creator process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID to last use the segment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creator_pid","description":"Process ID that created the segment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"Attached time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"dtime","description":"Detached time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Changed time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Memory segment permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"attached","description":"Number of attached processes","type":"integer","hidden":false,"required":false,"index":false},{"name":"status","description":"Destination/attach status","type":"text","hidden":false,"required":false,"index":false},{"name":"locked","description":"1 if segment is locked else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shared_resources","description":"Displays shared resources on a computer system running Windows. This may be a disk drive, printer, interprocess communication, or other sharable device.","platforms":["windows"],"columns":[{"name":"description","description":"A textual description of the object","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the object was installed. Lack of a value does not indicate that the object is not installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"String that indicates the current status of the object.","type":"text","hidden":false,"required":false,"index":false},{"name":"allow_maximum","description":"Number of concurrent users for this resource has been limited. If True, the value in the MaximumAllowed property is ignored.","type":"integer","hidden":false,"required":false,"index":false},{"name":"maximum_allowed","description":"Limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum property is set to FALSE.","type":"integer","hidden":false,"required":false,"index":false},{"name":"name","description":"Alias given to a path set up as a share on a computer system running Windows.","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Local path of the Windows share.","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of resource being shared. Types include: disk drives, print queues, interprocess communications (IPC), and general devices.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"sharing_preferences","description":"OS X Sharing preferences.","platforms":["darwin"],"columns":[{"name":"screen_sharing","description":"1 If screen sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"file_sharing","description":"1 If file sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"printer_sharing","description":"1 If printer sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_login","description":"1 If remote login is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_management","description":"1 If remote management is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_apple_events","description":"1 If remote apple events are enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"internet_sharing","description":"1 If internet sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"bluetooth_sharing","description":"1 If bluetooth sharing is enabled for any user else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"disc_sharing","description":"1 If CD or DVD sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"content_caching","description":"1 If content caching is enabled else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shell_history","description":"A line-delimited (command) table of per-user .*_history data.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"Shell history owner","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp. It could be absent, default value is 0.","type":"integer","hidden":false,"required":false,"index":false},{"name":"command","description":"Unparsed date/line/command history line","type":"text","hidden":false,"required":false,"index":false},{"name":"history_file","description":"Path to the .*_history for this user","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shellbags","description":"Shows directories accessed via Windows Explorer.","platforms":["windows"],"columns":[{"name":"sid","description":"User SID","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Shellbags source Registry file","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Directory name.","type":"text","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Directory Modified time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"created_time","description":"Directory Created time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"accessed_time","description":"Directory Accessed time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Directory master file table entry.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Directory master file table sequence.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shimcache","description":"Application Compatibility Cache, contains artifacts of execution.","platforms":["windows"],"columns":[{"name":"entry","description":"Execution order.","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the executed file.","type":"text","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"File Modified time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"execution_flag","description":"Boolean Execution flag, 1 for execution, 0 for no execution, -1 for missing (this flag does not exist on Windows 10 and higher).","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shortcut_files","description":"View data about Windows Shortcut files.","platforms":["windows"],"columns":[{"name":"path","description":"Directory name.","type":"text","hidden":false,"required":true,"index":false},{"name":"target_path","description":"Target file path","type":"text","hidden":false,"required":false,"index":false},{"name":"target_modified","description":"Target Modified time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_created","description":"Target Created time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_accessed","description":"Target Accessed time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_size","description":"Size of target file.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to target file from lnk file.","type":"text","hidden":false,"required":false,"index":false},{"name":"local_path","description":"Local system path to target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"working_path","description":"Target file directory.","type":"text","hidden":false,"required":false,"index":false},{"name":"icon_path","description":"Lnk file icon location.","type":"text","hidden":false,"required":false,"index":false},{"name":"common_path","description":"Common system path to target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"command_args","description":"Command args passed to lnk file.","type":"text","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Optional hostname of the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"share_name","description":"Share name of the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device containing the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Target mft entry.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Target mft sequence.","type":"integer","hidden":false,"required":false,"index":false},{"name":"description","description":"Lnk file description.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"signature","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["darwin"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"hash_resources","description":"Set to 1 to also hash resources, or 0 otherwise. Default is 1","type":"integer","hidden":false,"required":false,"index":false},{"name":"arch","description":"If applicable, the arch of the signed code","type":"text","hidden":false,"required":false,"index":false},{"name":"signed","description":"1 If the file is signed else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"identifier","description":"The signing identifier sealed into the signature","type":"text","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Hash of the application Code Directory","type":"text","hidden":false,"required":false,"index":false},{"name":"team_identifier","description":"The team signing identifier sealed into the signature","type":"text","hidden":false,"required":false,"index":false},{"name":"authority","description":"Certificate Common Name","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sip_config","description":"Apple's System Integrity Protection (rootless) status.","platforms":["darwin"],"columns":[{"name":"config_flag","description":"The System Integrity Protection config flag","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this configuration is enabled, otherwise 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"enabled_nvram","description":"1 if this configuration is enabled, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"smart_drive_info","description":"Drive information read by SMART controller utilizing autodetect.","platforms":["darwin","linux"],"columns":[{"name":"device_name","description":"Name of block device","type":"text","hidden":false,"required":false,"index":false},{"name":"disk_id","description":"Physical slot number of device, only exists when hardware storage controller exists","type":"integer","hidden":false,"required":false,"index":false},{"name":"driver_type","description":"The explicit device type used to retrieve the SMART information","type":"text","hidden":false,"required":false,"index":false},{"name":"model_family","description":"Drive model family","type":"text","hidden":false,"required":false,"index":false},{"name":"device_model","description":"Device Model","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Device serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"lu_wwn_device_id","description":"Device Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"additional_product_id","description":"An additional drive identifier if any","type":"text","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"Drive firmware version","type":"text","hidden":false,"required":false,"index":false},{"name":"user_capacity","description":"Bytes of drive capacity","type":"text","hidden":false,"required":false,"index":false},{"name":"sector_sizes","description":"Bytes of drive sector sizes","type":"text","hidden":false,"required":false,"index":false},{"name":"rotation_rate","description":"Drive RPM","type":"text","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Form factor if reported","type":"text","hidden":false,"required":false,"index":false},{"name":"in_smartctl_db","description":"Boolean value for if drive is recognized","type":"integer","hidden":false,"required":false,"index":false},{"name":"ata_version","description":"ATA version of drive","type":"text","hidden":false,"required":false,"index":false},{"name":"transport_type","description":"Drive transport type","type":"text","hidden":false,"required":false,"index":false},{"name":"sata_version","description":"SATA version, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"read_device_identity_failure","description":"Error string for device id read, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"smart_supported","description":"SMART support status","type":"text","hidden":false,"required":false,"index":false},{"name":"smart_enabled","description":"SMART enabled status","type":"text","hidden":false,"required":false,"index":false},{"name":"packet_device_type","description":"Packet device type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_mode","description":"Device power mode","type":"text","hidden":false,"required":false,"index":false},{"name":"warnings","description":"Warning messages from SMART controller","type":"text","hidden":false,"required":false,"index":false}]},{"name":"smbios_tables","description":"BIOS (DMI) structure common details and content.","platforms":["darwin","linux"],"columns":[{"name":"number","description":"Table entry number","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Table entry type","type":"integer","hidden":false,"required":false,"index":false},{"name":"description","description":"Table entry description","type":"text","hidden":false,"required":false,"index":false},{"name":"handle","description":"Table entry handle","type":"integer","hidden":false,"required":false,"index":false},{"name":"header_size","description":"Header size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Table entry size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"smc_keys","description":"Apple's system management controller keys.","platforms":["darwin"],"columns":[{"name":"key","description":"4-character key","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"SMC-reported type literal type","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Reported size of data in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"A type-encoded representation of the key value","type":"text","hidden":false,"required":false,"index":false},{"name":"hidden","description":"1 if this key is normally hidden, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"socket_events","description":"Track network socket opens and closes.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"The socket action (bind, listen, close)","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"status","description":"Either 'succeeded', 'failed', 'in_progress' (connect() on non-blocking socket) or 'no_client' (null accept() on non-blocking socket)","type":"text","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","hidden":true,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"socket","description":"The local path (UNIX domain socket only)","type":"text","hidden":true,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"success","description":"Deprecated. Use the 'status' column instead","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"ssh_configs","description":"A table of parsed ssh_configs.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local owner of the ssh_config file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block","description":"The host or match block","type":"text","hidden":false,"required":false,"index":false},{"name":"option","description":"The option and value","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_config_file","description":"Path to the ssh_config file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"startup_items","description":"Applications and binaries set as user/login startup items.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Name of startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"args","description":"Arguments provided to startup executable","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Startup Item or Login Item","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Directory or plist containing startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Startup status; either enabled or disabled","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"The user associated with the startup item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sudoers","description":"Rules for running commands as other users via sudo.","platforms":["darwin","linux"],"columns":[{"name":"source","description":"Source file containing the given rule","type":"text","hidden":false,"required":false,"index":false},{"name":"header","description":"Symbol for given rule","type":"text","hidden":false,"required":false,"index":false},{"name":"rule_details","description":"Rule definition","type":"text","hidden":false,"required":false,"index":false}]},{"name":"suid_bin","description":"suid binaries in common locations.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Binary path","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Binary owner username","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Binary owner group","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Binary permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"syslog_events","description":"","platforms":["linux"],"columns":[{"name":"time","description":"Current unix epoch time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Time known to syslog","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"Hostname configured for syslog","type":"text","hidden":false,"required":false,"index":false},{"name":"severity","description":"Syslog severity","type":"integer","hidden":false,"required":false,"index":false},{"name":"facility","description":"Syslog facility","type":"text","hidden":false,"required":false,"index":false},{"name":"tag","description":"The syslog tag","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"The syslog message","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"system_controls","description":"sysctl names, values, and settings information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Full sysctl MIB name","type":"text","hidden":false,"required":false,"index":false},{"name":"oid","description":"Control MIB","type":"text","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"Subsystem ID, control type","type":"text","hidden":false,"required":false,"index":false},{"name":"current_value","description":"Value of setting","type":"text","hidden":false,"required":false,"index":false},{"name":"config_value","description":"The MIB value set in /etc/sysctl.conf","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type","type":"text","hidden":false,"required":false,"index":false},{"name":"field_name","description":"Specific attribute of opaque type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"system_extensions","description":"macOS (>= 10.15) system extension table.","platforms":["darwin"],"columns":[{"name":"path","description":"Original path of system extension","type":"text","hidden":false,"required":false,"index":false},{"name":"UUID","description":"Extension unique id","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"System extension state","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"System extension version","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"System extension category","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"System extension bundle path","type":"text","hidden":false,"required":false,"index":false},{"name":"team","description":"Signing team ID","type":"text","hidden":false,"required":false,"index":false},{"name":"mdm_managed","description":"1 if managed by MDM system extension payload configuration, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"system_info","description":"System information for identification.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"hostname","description":"Network hostname including domain","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"CPU type","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"CPU subtype","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_brand","description":"CPU brand string, contains vendor and model","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_physical_cores","description":"Number of physical CPU cores in to the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_logical_cores","description":"Number of logical CPU cores available to the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_microcode","description":"Microcode version","type":"text","hidden":false,"required":false,"index":false},{"name":"physical_memory","description":"Total physical memory in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hardware_vendor","description":"Hardware vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hardware model","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_version","description":"Hardware version","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_serial","description":"Device serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"board_vendor","description":"Board vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"board_model","description":"Board model","type":"text","hidden":false,"required":false,"index":false},{"name":"board_version","description":"Board version","type":"text","hidden":false,"required":false,"index":false},{"name":"board_serial","description":"Board serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Friendly computer name (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Local hostname (optional)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"systemd_units","description":"Track systemd units.","platforms":["linux"],"columns":[{"name":"id","description":"Unique unit identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Unit description","type":"text","hidden":false,"required":false,"index":false},{"name":"load_state","description":"Reflects whether the unit definition was properly loaded","type":"text","hidden":false,"required":false,"index":false},{"name":"active_state","description":"The high-level unit activation state, i.e. generalization of SUB","type":"text","hidden":false,"required":false,"index":false},{"name":"sub_state","description":"The low-level unit activation state, values depend on unit type","type":"text","hidden":false,"required":false,"index":false},{"name":"following","description":"The name of another unit that this unit follows in state","type":"text","hidden":false,"required":false,"index":false},{"name":"object_path","description":"The object path for this unit","type":"text","hidden":false,"required":false,"index":false},{"name":"job_id","description":"Next queued job id","type":"bigint","hidden":false,"required":false,"index":false},{"name":"job_type","description":"Job type","type":"text","hidden":false,"required":false,"index":false},{"name":"job_path","description":"The object path for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"fragment_path","description":"The unit file path this unit was read from, if there is any","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"The configured user, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"source_path","description":"Path to the (possibly generated) unit configuration file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"temperature_sensors","description":"Machine's temperature sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on OS X","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of temperature source","type":"text","hidden":false,"required":false,"index":false},{"name":"celsius","description":"Temperature in Celsius","type":"double","hidden":false,"required":false,"index":false},{"name":"fahrenheit","description":"Temperature in Fahrenheit","type":"double","hidden":false,"required":false,"index":false}]},{"name":"time","description":"Track current date and time in the system.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"weekday","description":"Current weekday in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"year","description":"Current year in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"month","description":"Current month in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"day","description":"Current day in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"hour","description":"Current hour in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Current minutes in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Current seconds in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"timezone","description":"Current timezone in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"local_time","description":"Current local UNIX time in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_timezone","description":"Current local timezone in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"unix_time","description":"Current UNIX time in the system, converted to UTC if --utc enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"timestamp","description":"Current timestamp (log format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Current date and time (ISO format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"iso_8601","description":"Current time (ISO format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"win_timestamp","description":"Timestamp value in 100 nanosecond units.","type":"bigint","hidden":true,"required":false,"index":false}]},{"name":"time_machine_backups","description":"Backups to drives using TimeMachine.","platforms":["darwin"],"columns":[{"name":"destination_id","description":"Time Machine destination ID","type":"text","hidden":false,"required":false,"index":false},{"name":"backup_date","description":"Backup Date","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"time_machine_destinations","description":"Locations backed up to using Time Machine.","platforms":["darwin"],"columns":[{"name":"alias","description":"Human readable name of drive","type":"text","hidden":false,"required":false,"index":false},{"name":"destination_id","description":"Time Machine destination ID","type":"text","hidden":false,"required":false,"index":false},{"name":"consistency_scan_date","description":"Consistency scan date","type":"integer","hidden":false,"required":false,"index":false},{"name":"root_volume_uuid","description":"Root UUID of backup volume","type":"text","hidden":false,"required":false,"index":false},{"name":"bytes_available","description":"Bytes available on volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"bytes_used","description":"Bytes used on volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"encryption","description":"Last known encrypted state","type":"text","hidden":false,"required":false,"index":false}]},{"name":"tpm_info","description":"A table that lists the TPM related information.","platforms":["windows"],"columns":[{"name":"activated","description":"TPM is activated","type":"integer","hidden":false,"required":false,"index":false},{"name":"enabled","description":"TPM is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"owned","description":"TPM is ownned","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer_version","description":"TPM version","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer_id","description":"TPM manufacturers ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer_name","description":"TPM manufacturers name","type":"text","hidden":false,"required":false,"index":false},{"name":"product_name","description":"Product name of the TPM","type":"text","hidden":false,"required":false,"index":false},{"name":"physical_presence_version","description":"Version of the Physical Presence Interface","type":"text","hidden":false,"required":false,"index":false},{"name":"spec_version","description":"Trusted Computing Group specification that the TPM supports","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ulimit_info","description":"System resource usage limits.","platforms":["darwin","linux"],"columns":[{"name":"type","description":"System resource to be limited","type":"text","hidden":false,"required":false,"index":false},{"name":"soft_limit","description":"Current limit value","type":"text","hidden":false,"required":false,"index":false},{"name":"hard_limit","description":"Maximum limit value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"uptime","description":"Track time passed since last boot. Some systems track this as calendar time, some as runtime.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"days","description":"Days of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"hours","description":"Hours of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Minutes of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Seconds of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"total_seconds","description":"Total uptime seconds","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"usb_devices","description":"USB devices that are actively plugged into the host system.","platforms":["darwin","linux"],"columns":[{"name":"usb_address","description":"USB Device used address","type":"integer","hidden":false,"required":false,"index":false},{"name":"usb_port","description":"USB Device used port","type":"integer","hidden":false,"required":false,"index":false},{"name":"vendor","description":"USB Device vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded USB Device vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"USB Device version number","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"USB Device model string","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded USB Device model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"USB Device serial connection","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"USB Device class","type":"text","hidden":false,"required":false,"index":false},{"name":"subclass","description":"USB Device subclass","type":"text","hidden":false,"required":false,"index":false},{"name":"protocol","description":"USB Device protocol","type":"text","hidden":false,"required":false,"index":false},{"name":"removable","description":"1 If USB device is removable else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"user_events","description":"Track user events from the audit framework.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the event","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"The file description for the process socket","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Supplied path from event","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"The Internet protocol address or family ID","type":"text","hidden":false,"required":false,"index":false},{"name":"terminal","description":"The network protocol ID","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"user_groups","description":"Local system user group relationships.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"user_interaction_events","description":"Track user interaction events from macOS' event tapping framework.","platforms":["darwin"],"columns":[{"name":"time","description":"Time","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"user_ssh_keys","description":"Returns the private keys in the users ~/.ssh directory and whether or not they are encrypted.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local user that owns the key file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to key file","type":"text","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 if key is encrypted, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"key_type","description":"The type of the private key. One of [rsa, dsa, dh, ec, hmac, cmac], or the empty string.","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"userassist","description":"UserAssist Registry Key tracks when a user executes an application from Windows Explorer.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of times the application has been executed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"video_info","description":"Retrieve video card information of the machine.","platforms":["windows"],"columns":[{"name":"color_depth","description":"The amount of bits per pixel to represent color.","type":"integer","hidden":false,"required":false,"index":false},{"name":"driver","description":"The driver of the device.","type":"text","hidden":false,"required":false,"index":false},{"name":"driver_date","description":"The date listed on the installed driver.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"driver_version","description":"The version of the installed driver.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"series","description":"The series of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"video_mode","description":"The current resolution of the display.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"virtual_memory_info","description":"Darwin Virtual Memory statistics.","platforms":["darwin"],"columns":[{"name":"free","description":"Total number of free pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"active","description":"Total number of active pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Total number of inactive pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"speculative","description":"Total number of speculative pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"throttled","description":"Total number of throttled pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wired","description":"Total number of wired down pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"purgeable","description":"Total number of purgeable pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"faults","description":"Total number of calls to vm_faults.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"copy","description":"Total number of copy-on-write pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"zero_fill","description":"Total number of zero filled pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"reactivated","description":"Total number of reactivated pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"purged","description":"Total number of purged pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"file_backed","description":"Total number of file backed pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"anonymous","description":"Total number of anonymous pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uncompressed","description":"Total number of uncompressed pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"compressor","description":"The number of pages used to store compressed VM pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"decompressed","description":"The total number of pages that have been decompressed by the VM compressor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"compressed","description":"The total number of pages that have been compressed by the VM compressor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"page_ins","description":"The total number of requests for pages from a pager.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"page_outs","description":"Total number of pages paged out.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_ins","description":"The total number of compressed pages that have been swapped out to disk.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_outs","description":"The total number of compressed pages that have been swapped back in from disk.","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"wifi_networks","description":"OS X known/remembered Wi-Fi networks list.","platforms":["darwin"],"columns":[{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","hidden":false,"required":false,"index":false},{"name":"last_connected","description":"Last time this netword was connected to as a unix_time","type":"integer","hidden":false,"required":false,"index":false},{"name":"passpoint","description":"1 if Passpoint is supported, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"possibly_hidden","description":"1 if network is possibly a hidden network, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"roaming","description":"1 if roaming is supported, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"roaming_profile","description":"Describe the roaming profile, usually one of Single, Dual or Multi","type":"text","hidden":false,"required":false,"index":false},{"name":"captive_portal","description":"1 if this network has a captive portal, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"auto_login","description":"1 if auto login is enabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"temporarily_disabled","description":"1 if this network is temporarily disabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 if this network is disabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"wifi_status","description":"OS X current WiFi status.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","hidden":false,"required":false,"index":false},{"name":"transmit_rate","description":"The current transmit rate","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"The current operating mode for the Wi-Fi interface","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wifi_survey","description":"Scan for nearby WiFi networks.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"winbaseobj","description":"Lists named Windows objects in the default object directories, across all terminal services sessions. Example Windows ojbect types include Mutexes, Events, Jobs and Semaphors.","platforms":["windows"],"columns":[{"name":"session_id","description":"Terminal Services Session Id","type":"integer","hidden":false,"required":false,"index":false},{"name":"object_name","description":"Object Name","type":"text","hidden":false,"required":false,"index":false},{"name":"object_type","description":"Object Type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_crashes","description":"Extracted information from Windows crash logs (Minidumps).","platforms":["windows"],"columns":[{"name":"datetime","description":"Timestamp (log format) of the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"module","description":"Path of the crashed module within the process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the executable file for the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID of the crashed thread","type":"bigint","hidden":false,"required":false,"index":false},{"name":"version","description":"File version info of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"process_uptime","description":"Uptime of the process in seconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Multiple stack frames from the stack trace","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_code","description":"The Windows exception code","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_message","description":"The NTSTATUS error message associated with the exception code","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_address","description":"Address (in hex) where the exception occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"The values of the system registers","type":"text","hidden":false,"required":false,"index":false},{"name":"command_line","description":"Command-line string passed to the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"current_directory","description":"Current working directory of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Username of the user who ran the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"machine_name","description":"Name of the machine where the crash happened","type":"text","hidden":false,"required":false,"index":false},{"name":"major_version","description":"Windows major version of the machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"minor_version","description":"Windows minor version of the machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"build_number","description":"Windows build number of the crashing machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of crash log","type":"text","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Path of the log file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_eventlog","description":"Table for querying all recorded Windows event logs.","platforms":["windows"],"columns":[{"name":"channel","description":"Source or channel of the event","type":"text","hidden":false,"required":true,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"level","description":"Severity level associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID which emitted the event record","type":"integer","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID which emitted the event record","type":"integer","hidden":false,"required":false,"index":false},{"name":"time_range","description":"System time to selectively filter the events","type":"text","hidden":true,"required":false,"index":false},{"name":"timestamp","description":"Timestamp to selectively filter the events","type":"text","hidden":true,"required":false,"index":false},{"name":"xpath","description":"The custom query to filter events","type":"text","hidden":true,"required":true,"index":false}]},{"name":"windows_events","description":"Windows Event logs.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source or channel of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"level","description":"The severity level associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"windows_optional_features","description":"Lists names and installation states of windows features. Maps to Win32_OptionalFeature WMI class.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the feature","type":"text","hidden":false,"required":false,"index":false},{"name":"caption","description":"Caption of feature in settings UI","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Installation state value. 1 == Enabled, 2 == Disabled, 3 == Absent","type":"integer","hidden":false,"required":false,"index":false},{"name":"statename","description":"Installation state name. 'Enabled','Disabled','Absent'","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_security_center","description":"The health status of Window Security features. Health values can be \"Good\", \"Poor\". \"Snoozed\", \"Not Monitored\", and \"Error\".","platforms":["windows"],"columns":[{"name":"firewall","description":"The health of the monitored Firewall (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"The health of the Windows Autoupdate feature","type":"text","hidden":false,"required":false,"index":false},{"name":"antivirus","description":"The health of the monitored Antivirus solution (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"antispyware","description":"The health of the monitored Antispyware solution (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"internet_settings","description":"The health of the Internet Settings","type":"text","hidden":false,"required":false,"index":false},{"name":"windows_security_center_service","description":"The health of the Windows Security Center Service","type":"text","hidden":false,"required":false,"index":false},{"name":"user_account_control","description":"The health of the User Account Control (UAC) capability in Windows","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_security_products","description":"Enumeration of registered Windows security products.","platforms":["windows"],"columns":[{"name":"type","description":"Type of security product","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of product","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"State of protection","type":"text","hidden":false,"required":false,"index":false},{"name":"state_timestamp","description":"Timestamp for the product state","type":"text","hidden":false,"required":false,"index":false},{"name":"remediation_path","description":"Remediation path","type":"text","hidden":false,"required":false,"index":false},{"name":"signatures_up_to_date","description":"1 if product signatures are up to date, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"wmi_bios_info","description":"Lists important information from the system bios.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the Bios setting","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the Bios setting","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_cli_event_consumers","description":"WMI CommandLineEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique name of a consumer.","type":"text","hidden":false,"required":false,"index":false},{"name":"command_line_template","description":"Standard string template that specifies the process to be started. This property can be NULL, and the ExecutablePath property is used as the command line.","type":"text","hidden":false,"required":false,"index":false},{"name":"executable_path","description":"Module to execute. The string can specify the full path and file name of the module to execute, or it can specify a partial name. If a partial name is specified, the current drive and current directory are assumed.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_event_filters","description":"Lists WMI event filters.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier of an event filter.","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"Windows Management Instrumentation Query Language (WQL) event query that specifies the set of events for consumer notification, and the specific conditions for notification.","type":"text","hidden":false,"required":false,"index":false},{"name":"query_language","description":"Query language that the query is written in.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_filter_consumer_binding","description":"Lists the relationship between event consumers and filters.","platforms":["windows"],"columns":[{"name":"consumer","description":"Reference to an instance of __EventConsumer that represents the object path to a logical consumer, the recipient of an event.","type":"text","hidden":false,"required":false,"index":false},{"name":"filter","description":"Reference to an instance of __EventFilter that represents the object path to an event filter which is a query that specifies the type of event to be received.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_script_event_consumers","description":"WMI ActiveScriptEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier for the event consumer. ","type":"text","hidden":false,"required":false,"index":false},{"name":"scripting_engine","description":"Name of the scripting engine to use, for example, 'VBScript'. This property cannot be NULL.","type":"text","hidden":false,"required":false,"index":false},{"name":"script_file_name","description":"Name of the file from which the script text is read, intended as an alternative to specifying the text of the script in the ScriptText property.","type":"text","hidden":false,"required":false,"index":false},{"name":"script_text","description":"Text of the script that is expressed in a language known to the scripting engine. This property must be NULL if the ScriptFileName property is not NULL.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"xprotect_entries","description":"Database of the machine's XProtect signatures.","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","hidden":false,"required":false,"index":false},{"name":"launch_type","description":"Launch services content type","type":"text","hidden":false,"required":false,"index":false},{"name":"identity","description":"XProtect identity (SHA1) of content","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Use this file name to match","type":"text","hidden":false,"required":false,"index":false},{"name":"filetype","description":"Use this file type to match","type":"text","hidden":false,"required":false,"index":false},{"name":"optional","description":"Match any of the identities/patterns for this XProtect name","type":"integer","hidden":false,"required":false,"index":false},{"name":"uses_pattern","description":"Uses a match pattern instead of identity","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"xprotect_meta","description":"Database of the machine's XProtect browser-related signatures.","platforms":["darwin"],"columns":[{"name":"identifier","description":"Browser plugin or extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Either plugin or extension","type":"text","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Developer identity (SHA1) of extension","type":"text","hidden":false,"required":false,"index":false},{"name":"min_version","description":"The minimum allowed plugin version.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"xprotect_reports","description":"Database of XProtect matches (if user generated/sent an XProtect report).","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","hidden":false,"required":false,"index":false},{"name":"user_action","description":"Action taken by user after prompted","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Quarantine alert time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"yara","description":"Track YARA matches for files or PIDs.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"The path scanned","type":"text","hidden":false,"required":true,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","hidden":false,"required":false,"index":false},{"name":"sig_group","description":"Signature group used","type":"text","hidden":false,"required":false,"index":false},{"name":"sigfile","description":"Signature file used","type":"text","hidden":false,"required":false,"index":false},{"name":"sigrule","description":"Signature strings used","type":"text","hidden":true,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","hidden":false,"required":false,"index":false},{"name":"sigurl","description":"Signature url","type":"text","hidden":true,"required":false,"index":false}]},{"name":"yara_events","description":"Track YARA matches for files specified in configuration data.","platforms":["darwin","linux","windows"],"columns":[{"name":"target_path","description":"The path scanned","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","hidden":false,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of the scan","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"ycloud_instance_metadata","description":"Yandex.Cloud instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"folder_id","description":"Folder identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Hostname of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_port_enabled","description":"Indicates if serial port is enabled for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"metadata_endpoint","description":"Endpoint used to fetch VM metadata","type":"text","hidden":false,"required":false,"index":false}]},{"name":"yum_sources","description":"Current list of Yum repositories or software channels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Repository name","type":"text","hidden":false,"required":false,"index":false},{"name":"baseurl","description":"Repository base URL","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether the repository is used","type":"text","hidden":false,"required":false,"index":false},{"name":"gpgcheck","description":"Whether packages are GPG checked","type":"text","hidden":false,"required":false,"index":false},{"name":"gpgkey","description":"URL to GPG key","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]}] \ No newline at end of file +[{"name":"account_policy_data","description":"Additional OS X user account data from the AccountPolicy section of OpenDirectory.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the account was first created","type":"double","hidden":false,"required":false,"index":false},{"name":"failed_login_count","description":"The number of failed login attempts using an incorrect password. Count resets after a correct password is entered.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"failed_login_timestamp","description":"The time of the last failed login attempt. Resets after a correct password is entered","type":"double","hidden":false,"required":false,"index":false},{"name":"password_last_set_time","description":"The time the password was last changed","type":"double","hidden":false,"required":false,"index":false}]},{"name":"acpi_tables","description":"Firmware ACPI functional table common metadata and content.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"ACPI table name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of compiled table data","type":"integer","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table content","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ad_config","description":"OS X Active Directory configuration.","platforms":["darwin"],"columns":[{"name":"name","description":"The OS X-specific configuration name","type":"text","hidden":false,"required":false,"index":false},{"name":"domain","description":"Active Directory trust domain","type":"text","hidden":false,"required":false,"index":false},{"name":"option","description":"Canonical name of option","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Variable typed option value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"alf","description":"OS X application layer firewall (ALF) service details.","platforms":["darwin"],"columns":[{"name":"allow_signed_enabled","description":"1 If allow signed mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"firewall_unload","description":"1 If firewall unloading enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"global_state","description":"1 If the firewall is enabled with exceptions, 2 if the firewall is configured to block all incoming connections, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_enabled","description":"1 If logging mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_option","description":"Firewall logging option","type":"integer","hidden":false,"required":false,"index":false},{"name":"stealth_enabled","description":"1 If stealth mode is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Application Layer Firewall version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"alf_exceptions","description":"OS X application layer firewall (ALF) service exceptions.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to the executable that is excepted","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Firewall exception state","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"alf_explicit_auths","description":"ALF services explicitly allowed to perform networking.","platforms":["darwin"],"columns":[{"name":"process","description":"Process name explicitly allowed","type":"text","hidden":false,"required":false,"index":false}]},{"name":"app_schemes","description":"OS X application schemes and handlers (e.g., http, file, mailto).","platforms":["darwin"],"columns":[{"name":"scheme","description":"Name of the scheme/protocol","type":"text","hidden":false,"required":false,"index":false},{"name":"handler","description":"Application label for the handler","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this handler is the OS default, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"external","description":"1 if this handler does NOT exist on OS X by default, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"protected","description":"1 if this handler is protected (reserved) by OS X, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"apparmor_events","description":"Track AppArmor events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Raw audit message","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"apparmor","description":"Apparmor Status like ALLOWED, DENIED etc.","type":"text","hidden":false,"required":false,"index":false},{"name":"operation","description":"Permission requested by the process","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process PID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"profile","description":"Apparmor profile name","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"denied_mask","description":"Denied permissions for the process","type":"text","hidden":false,"required":false,"index":false},{"name":"capname","description":"Capability requested by the process","type":"text","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"ouid","description":"Object owner's user ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"capability","description":"Capability number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"requested_mask","description":"Requested access mask","type":"text","hidden":false,"required":false,"index":false},{"name":"info","description":"Additional information","type":"text","hidden":false,"required":false,"index":false},{"name":"error","description":"Error information","type":"text","hidden":false,"required":false,"index":false},{"name":"namespace","description":"AppArmor namespace","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"AppArmor label","type":"text","hidden":false,"required":false,"index":false}]},{"name":"apparmor_profiles","description":"Track active AppArmor profiles.","platforms":["linux"],"columns":[{"name":"path","description":"Unique, aa-status compatible, policy identifier.","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy name.","type":"text","hidden":false,"required":false,"index":false},{"name":"attach","description":"Which executable(s) a profile will attach to.","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"How the policy is applied.","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"A unique hash that identifies this policy.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"appcompat_shims","description":"Application Compatibility shims are a way to persist malware. This table presents the AppCompat Shim information from the registry in a nice format. See http://files.brucon.org/2015/Tomczak_and_Ballenthin_Shims_for_the_Win.pdf for more details.","platforms":["windows"],"columns":[{"name":"executable","description":"Name of the executable that is being shimmed. This is pulled from the registry.","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the SDB database.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the SDB.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Install time of the SDB","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the SDB database.","type":"text","hidden":false,"required":false,"index":false},{"name":"sdb_id","description":"Unique GUID of the SDB.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"apps","description":"OS X applications installed in known search paths (e.g., /Applications).","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the Name.app folder","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute and full Name.app path","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_executable","description":"Info properties CFBundleExecutable label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"Info properties CFBundleIdentifier label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_name","description":"Info properties CFBundleName label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_short_version","description":"Info properties CFBundleShortVersionString label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_version","description":"Info properties CFBundleVersion label","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_package_type","description":"Info properties CFBundlePackageType label","type":"text","hidden":false,"required":false,"index":false},{"name":"environment","description":"Application-set environment variables","type":"text","hidden":false,"required":false,"index":false},{"name":"element","description":"Does the app identify as a background agent","type":"text","hidden":false,"required":false,"index":false},{"name":"compiler","description":"Info properties DTCompiler label","type":"text","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Info properties CFBundleDevelopmentRegion label","type":"text","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Info properties CFBundleDisplayName label","type":"text","hidden":false,"required":false,"index":false},{"name":"info_string","description":"Info properties CFBundleGetInfoString label","type":"text","hidden":false,"required":false,"index":false},{"name":"minimum_system_version","description":"Minimum version of OS X required for the app to run","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The UTI that categorizes the app for the App Store","type":"text","hidden":false,"required":false,"index":false},{"name":"applescript_enabled","description":"Info properties NSAppleScriptEnabled label","type":"text","hidden":false,"required":false,"index":false},{"name":"copyright","description":"Info properties NSHumanReadableCopyright label","type":"text","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"The time that the app was last used","type":"double","hidden":false,"required":false,"index":false}]},{"name":"apt_sources","description":"Current list of APT repositories or software channels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Repository name","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source file","type":"text","hidden":false,"required":false,"index":false},{"name":"base_uri","description":"Repository base URI","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"Release name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Repository source version","type":"text","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Repository maintainer","type":"text","hidden":false,"required":false,"index":false},{"name":"components","description":"Repository components","type":"text","hidden":false,"required":false,"index":false},{"name":"architectures","description":"Repository architectures","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"arp_cache","description":"Address resolution cache, both static and dynamic (from ARP, NDP).","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"address","description":"IPv4 address target","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address of broadcasted address","type":"text","hidden":false,"required":false,"index":false},{"name":"interface","description":"Interface of the network for the MAC","type":"text","hidden":false,"required":false,"index":false},{"name":"permanent","description":"1 for true, 0 for false","type":"text","hidden":false,"required":false,"index":false}]},{"name":"asl","description":"Queries the Apple System Log data structure for system events.","platforms":["darwin"],"columns":[{"name":"time","description":"Unix timestamp. Set automatically","type":"integer","hidden":false,"required":false,"index":false},{"name":"time_nano_sec","description":"Nanosecond time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"host","description":"Sender's address (set by the server).","type":"text","hidden":false,"required":false,"index":false},{"name":"sender","description":"Sender's identification string. Default is process name.","type":"text","hidden":false,"required":false,"index":false},{"name":"facility","description":"Sender's facility. Default is 'user'.","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Sending process ID encoded as a string. Set automatically.","type":"integer","hidden":false,"required":false,"index":false},{"name":"gid","description":"GID that sent the log message (set by the server).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"UID that sent the log message (set by the server).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"level","description":"Log level number. See levels in asl.h.","type":"integer","hidden":false,"required":false,"index":false},{"name":"message","description":"Message text.","type":"text","hidden":false,"required":false,"index":false},{"name":"ref_pid","description":"Reference PID for messages proxied by launchd","type":"integer","hidden":false,"required":false,"index":false},{"name":"ref_proc","description":"Reference process for messages proxied by launchd","type":"text","hidden":false,"required":false,"index":false},{"name":"extra","description":"Extra columns, in JSON format. Queries against this column are performed entirely in SQLite, so do not benefit from efficient querying via asl.h.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"atom_packages","description":"Lists all atom packages in a directory or globally installed in a system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Package's package.json path","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the plugin","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"augeas","description":"Configuration files parsed by augeas.","platforms":["darwin","linux"],"columns":[{"name":"node","description":"The node path of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"The label of the configuration item","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path to the configuration file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authenticode","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"original_program_name","description":"The original program name that the publisher has signed","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_name","description":"The certificate issuer name","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_name","description":"The certificate subject name","type":"text","hidden":false,"required":false,"index":false},{"name":"result","description":"The signature check result","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorization_mechanisms","description":"OS X Authorization mechanisms database.","platforms":["darwin"],"columns":[{"name":"label","description":"Label of the authorization right","type":"text","hidden":false,"required":false,"index":false},{"name":"plugin","description":"Authorization plugin name","type":"text","hidden":false,"required":false,"index":false},{"name":"mechanism","description":"Name of the mechanism that will be called","type":"text","hidden":false,"required":false,"index":false},{"name":"privileged","description":"If privileged it will run as root, else as an anonymous user","type":"text","hidden":false,"required":false,"index":false},{"name":"entry","description":"The whole string entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorizations","description":"OS X Authorization rights database.","platforms":["darwin"],"columns":[{"name":"label","description":"Item name, usually in reverse domain format","type":"text","hidden":false,"required":false,"index":false},{"name":"modified","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"allow_root","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"timeout","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"tries","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"authenticate_user","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"shared","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"session_owner","description":"Label top-level key","type":"text","hidden":false,"required":false,"index":false}]},{"name":"authorized_keys","description":"A line-delimited authorized_keys table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local owner of authorized_keys file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"algorithm","description":"algorithm of key","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"parsed authorized keys line","type":"text","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to the authorized_keys file","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"autoexec","description":"Aggregate of executables that will automatically execute on the target machine. This is an amalgamation of other tables like services, scheduled_tasks, startup_items and more.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the executable","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the program","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source table of the autoexec item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_metadata","description":"Azure instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"location","description":"Azure Region the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"offer","description":"Offer information for the VM image (Azure image gallery VMs only)","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Publisher of the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"sku","description":"SKU for the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the VM image","type":"text","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Linux or Windows","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_update_domain","description":"Update domain the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_fault_domain","description":"Fault domain the VM is running in","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_size","description":"VM size","type":"text","hidden":false,"required":false,"index":false},{"name":"subscription_id","description":"Azure subscription for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"resource_group_name","description":"Resource group for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"placement_group_id","description":"Placement group for the VM scale set","type":"text","hidden":false,"required":false,"index":false},{"name":"vm_scale_set_name","description":"VM scale set name","type":"text","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_tags","description":"Azure instance tags.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"vm_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"The tag key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The tag value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"background_activities_moderator","description":"Background Activities Moderator (BAM) tracks application execution.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"battery","description":"Provides information about the internal battery of a Macbook.","platforms":["darwin"],"columns":[{"name":"manufacturer","description":"The battery manufacturer's name","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacture_date","description":"The date the battery was manufactured UNIX Epoch","type":"integer","hidden":false,"required":false,"index":false},{"name":"model","description":"The battery's model number","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The battery's unique serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"cycle_count","description":"The number of charge/discharge cycles","type":"integer","hidden":false,"required":false,"index":false},{"name":"health","description":"One of the following: \"Good\" describes a well-performing battery, \"Fair\" describes a functional battery with limited capacity, or \"Poor\" describes a battery that's not capable of providing power","type":"text","hidden":false,"required":false,"index":false},{"name":"condition","description":"One of the following: \"Normal\" indicates the condition of the battery is within normal tolerances, \"Service Needed\" indicates that the battery should be checked out by a licensed Mac repair service, \"Permanent Failure\" indicates the battery needs replacement","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"One of the following: \"AC Power\" indicates the battery is connected to an external power source, \"Battery Power\" indicates that the battery is drawing internal power, \"Off Line\" indicates the battery is off-line or no longer connected","type":"text","hidden":false,"required":false,"index":false},{"name":"charging","description":"1 if the battery is currently being charged by a power source. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"charged","description":"1 if the battery is currently completely charged. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"designed_capacity","description":"The battery's designed capacity in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"The battery's actual capacity when it is fully charged in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"current_capacity","description":"The battery's current charged capacity in mAh","type":"integer","hidden":false,"required":false,"index":false},{"name":"percent_remaining","description":"The percentage of battery remaining before it is drained","type":"integer","hidden":false,"required":false,"index":false},{"name":"amperage","description":"The battery's current amperage in mA","type":"integer","hidden":false,"required":false,"index":false},{"name":"voltage","description":"The battery's current voltage in mV","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes_until_empty","description":"The number of minutes until the battery is fully depleted. This value is -1 if this time is still being calculated","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes_to_full_charge","description":"The number of minutes until the battery is fully charged. This value is -1 if this time is still being calculated","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"bitlocker_info","description":"Retrieve bitlocker status of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"ID of the encrypted drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"Drive letter of the encrypted drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"persistent_volume_id","description":"Persistent ID of the drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"conversion_status","description":"The bitlocker conversion status of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"protection_status","description":"The bitlocker protection status of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"encryption_method","description":"The encryption type of the device.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The FVE metadata version of the drive.","type":"integer","hidden":false,"required":false,"index":false},{"name":"percentage_encrypted","description":"The percentage of the drive that is encrypted.","type":"integer","hidden":false,"required":false,"index":false},{"name":"lock_status","description":"The accessibility status of the drive from Windows.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"block_devices","description":"Block (buffered access) device file nodes: disks, ramdisks, and DMG containers.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Block device name","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Block device parent name","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Block device vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"Block device model string identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Block device size in blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Block device Universally Unique Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Block device type string","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"Block device label string","type":"text","hidden":false,"required":false,"index":false}]},{"name":"bpf_process_events","description":"Track time/action process executions.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Binary path","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","hidden":false,"required":false,"index":false},{"name":"json_cmdline","description":"Command line arguments, in JSON format","type":"text","hidden":true,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"bpf_socket_events","description":"Track network socket opens and closes.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"The socket type","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","hidden":false,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"browser_plugins","description":"All C/NPAPI browser plugin details for all users.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the plugin","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Plugin display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Plugin identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Plugin short version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Build SDK used to compile plugin","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Plugin description text","type":"text","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Plugin language-localization","type":"text","hidden":false,"required":false,"index":false},{"name":"native","description":"Plugin requires native execution","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Is the plugin disabled. 1 = Disabled","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"carbon_black_info","description":"Returns info about a Carbon Black sensor install.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"sensor_id","description":"Sensor ID of the Carbon Black sensor","type":"integer","hidden":false,"required":false,"index":false},{"name":"config_name","description":"Sensor group","type":"text","hidden":false,"required":false,"index":false},{"name":"collect_store_files","description":"If the sensor is configured to send back binaries to the Carbon Black server","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_module_loads","description":"If the sensor is configured to capture module loads","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_module_info","description":"If the sensor is configured to collect metadata of binaries","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_file_mods","description":"If the sensor is configured to collect file modification events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_reg_mods","description":"If the sensor is configured to collect registry modification events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_net_conns","description":"If the sensor is configured to collect network connections","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_processes","description":"If the sensor is configured to process events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_cross_processes","description":"If the sensor is configured to cross process events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_emet_events","description":"If the sensor is configured to EMET events","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_data_file_writes","description":"If the sensor is configured to collect non binary file writes","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_process_user_context","description":"If the sensor is configured to collect the user running a process","type":"integer","hidden":false,"required":false,"index":false},{"name":"collect_sensor_operations","description":"Unknown","type":"integer","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_mb","description":"Event file disk quota in MB","type":"integer","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_percentage","description":"Event file disk quota in a percentage","type":"integer","hidden":false,"required":false,"index":false},{"name":"protection_disabled","description":"If the sensor is configured to report tamper events","type":"integer","hidden":false,"required":false,"index":false},{"name":"sensor_ip_addr","description":"IP address of the sensor","type":"text","hidden":false,"required":false,"index":false},{"name":"sensor_backend_server","description":"Carbon Black server","type":"text","hidden":false,"required":false,"index":false},{"name":"event_queue","description":"Size in bytes of Carbon Black event files on disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"binary_queue","description":"Size in bytes of binaries waiting to be sent to Carbon Black server","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"carves","description":"List the set of completed and in-progress carves. If carve=1 then the query is treated as a new carve request.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"time","description":"Time at which the carve was kicked off","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha256","description":"A SHA256 sum of the carved archive","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the carved archive","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the requested carve","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the carve, can be STARTING, PENDING, SUCCESS, or FAILED","type":"text","hidden":false,"required":false,"index":false},{"name":"carve_guid","description":"Identifying value of the carve session","type":"text","hidden":false,"required":false,"index":false},{"name":"request_id","description":"Identifying value of the carve request (e.g., scheduled query name, distributed request, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"carve","description":"Set this value to '1' to start a file carve","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"certificates","description":"Certificate Authorities installed in Keychains/ca-bundles.","platforms":["darwin","windows"],"columns":[{"name":"common_name","description":"Certificate CommonName","type":"text","hidden":false,"required":false,"index":false},{"name":"subject","description":"Certificate distinguished name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer","description":"Certificate issuer distinguished name","type":"text","hidden":false,"required":false,"index":false},{"name":"ca","description":"1 if CA: true (certificate is an authority) else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"self_signed","description":"1 if self-signed, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"not_valid_before","description":"Lower bound of valid date","type":"text","hidden":false,"required":false,"index":false},{"name":"not_valid_after","description":"Certificate expiration data","type":"text","hidden":false,"required":false,"index":false},{"name":"signing_algorithm","description":"Signing algorithm used","type":"text","hidden":false,"required":false,"index":false},{"name":"key_algorithm","description":"Key algorithm used","type":"text","hidden":false,"required":false,"index":false},{"name":"key_strength","description":"Key size used for RSA/DSA, or curve name","type":"text","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Certificate key usage and extended key usage","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_key_id","description":"SKID an optionally included SHA1","type":"text","hidden":false,"required":false,"index":false},{"name":"authority_key_id","description":"AKID an optionally included SHA1","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the raw certificate contents","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Keychain or PEM bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"Certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"sid","description":"SID","type":"text","hidden":true,"required":false,"index":false},{"name":"store_location","description":"Certificate system store location","type":"text","hidden":true,"required":false,"index":false},{"name":"store","description":"Certificate system store","type":"text","hidden":true,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":true,"required":false,"index":false},{"name":"store_id","description":"Exists for service/user stores. Contains raw store id provided by WinAPI.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"chassis_info","description":"Display information pertaining to the chassis and its security status.","platforms":["windows"],"columns":[{"name":"audible_alarm","description":"If TRUE, the frame is equipped with an audible alarm.","type":"text","hidden":false,"required":false,"index":false},{"name":"breach_description","description":"If provided, gives a more detailed description of a detected security breach.","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_types","description":"A comma-separated list of chassis types, such as Desktop or Laptop.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"An extended description of the chassis if available.","type":"text","hidden":false,"required":false,"index":false},{"name":"lock","description":"If TRUE, the frame is equipped with a lock.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"security_breach","description":"The physical status of the chassis such as Breach Successful, Breach Attempted, etc.","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"smbios_tag","description":"The assigned asset tag number of the chassis.","type":"text","hidden":false,"required":false,"index":false},{"name":"sku","description":"The Stock Keeping Unit number if available.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"If available, gives various operational or nonoperational statuses such as OK, Degraded, and Pred Fail.","type":"text","hidden":false,"required":false,"index":false},{"name":"visible_alarm","description":"If TRUE, the frame is equipped with a visual alarm.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"chocolatey_packages","description":"Chocolatey packages installed in a system.","platforms":["windows"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this package resides","type":"text","hidden":false,"required":false,"index":false}]},{"name":"chrome_extension_content_scripts","description":"Chrome browser extension content scripts.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave)","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"script","description":"The content script used by the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"match","description":"The pattern that the script is matched against","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"chrome_extensions","description":"Chrome-based browser extensions.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave, edge, edge_beta)","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"profile","description":"The name of the Chrome profile that contains this extension","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced_identifier","description":"Extension identifier, as specified by the preferences file. Empty if the extension is not in the profile.","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier, computed from its manifest. Empty in case of error.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Extension-optional description","type":"text","hidden":false,"required":false,"index":false},{"name":"default_locale","description":"Default locale supported by extension","type":"text","hidden":false,"required":false,"index":false},{"name":"current_locale","description":"Current locale supported by extension","type":"text","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","hidden":false,"required":false,"index":false},{"name":"persistent","description":"1 If extension is persistent across all tabs else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"The permissions required by the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions_json","description":"The JSON-encoded permissions required by the extension","type":"text","hidden":true,"required":false,"index":false},{"name":"optional_permissions","description":"The permissions optionally required by the extensions","type":"text","hidden":false,"required":false,"index":false},{"name":"optional_permissions_json","description":"The JSON-encoded permissions optionally required by the extensions","type":"text","hidden":true,"required":false,"index":false},{"name":"manifest_hash","description":"The SHA256 hash of the manifest.json file","type":"text","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","hidden":false,"required":false,"index":false},{"name":"from_webstore","description":"True if this extension was installed from the web store","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"1 if this extension is enabled","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Extension install time, in its original Webkit format","type":"text","hidden":false,"required":false,"index":false},{"name":"install_timestamp","description":"Extension install time, converted to unix time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"manifest_json","description":"The manifest file of the extension","type":"text","hidden":true,"required":false,"index":false},{"name":"key","description":"The extension key, from the manifest file","type":"text","hidden":true,"required":false,"index":false}]},{"name":"connectivity","description":"Provides the overall system's network state.","platforms":["windows"],"columns":[{"name":"disconnected","description":"True if the all interfaces are not connected to any network","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_no_traffic","description":"True if any interface is connected via IPv4, but has seen no traffic","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_no_traffic","description":"True if any interface is connected via IPv6, but has seen no traffic","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_subnet","description":"True if any interface is connected to the local subnet via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_local_network","description":"True if any interface is connected to a routed network via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_internet","description":"True if any interface is connected to the Internet via IPv4","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_subnet","description":"True if any interface is connected to the local subnet via IPv6","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_local_network","description":"True if any interface is connected to a routed network via IPv6","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_internet","description":"True if any interface is connected to the Internet via IPv6","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"cpu_info","description":"Retrieve cpu hardware info of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"The DeviceID of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"processor_type","description":"The processor type, such as Central, Math, or Video.","type":"text","hidden":false,"required":false,"index":false},{"name":"availability","description":"The availability and status of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_status","description":"The current operating status of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"number_of_cores","description":"The number of cores of the CPU.","type":"text","hidden":false,"required":false,"index":false},{"name":"logical_processors","description":"The number of logical processors of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"address_width","description":"The width of the CPU address bus.","type":"text","hidden":false,"required":false,"index":false},{"name":"current_clock_speed","description":"The current frequency of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_clock_speed","description":"The maximum possible frequency of the CPU.","type":"integer","hidden":false,"required":false,"index":false},{"name":"socket_designation","description":"The assigned socket on the board for the given CPU.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"cpu_time","description":"Displays information from /proc/stat file about the time the cpu cores spent in different parts of the system.","platforms":["darwin","linux"],"columns":[{"name":"core","description":"Name of the cpu (core)","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"Time spent in user mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"nice","description":"Time spent in user mode with low priority (nice)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system","description":"Time spent in system mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"idle","description":"Time spent in the idle task","type":"bigint","hidden":false,"required":false,"index":false},{"name":"iowait","description":"Time spent waiting for I/O to complete","type":"bigint","hidden":false,"required":false,"index":false},{"name":"irq","description":"Time spent servicing interrupts","type":"bigint","hidden":false,"required":false,"index":false},{"name":"softirq","description":"Time spent servicing softirqs","type":"bigint","hidden":false,"required":false,"index":false},{"name":"steal","description":"Time spent in other operating systems when running in a virtualized environment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"guest","description":"Time spent running a virtual CPU for a guest OS under the control of the Linux kernel","type":"bigint","hidden":false,"required":false,"index":false},{"name":"guest_nice","description":"Time spent running a niced guest ","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"cpuid","description":"Useful CPU features from the cpuid ASM call.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"feature","description":"Present feature flags","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Bit value or string","type":"text","hidden":false,"required":false,"index":false},{"name":"output_register","description":"Register used to for feature value","type":"text","hidden":false,"required":false,"index":false},{"name":"output_bit","description":"Bit in register value for feature value","type":"integer","hidden":false,"required":false,"index":false},{"name":"input_eax","description":"Value of EAX used","type":"text","hidden":false,"required":false,"index":false}]},{"name":"crashes","description":"Application, System, and Mobile App crash logs.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of crash log","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Location of log file","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version info of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent PID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"responsible","description":"Process responsible for the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the crashed process","type":"integer","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Date/Time at which the crash occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"crashed_thread","description":"Thread ID which crashed","type":"bigint","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Most recent frame from the stack trace","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_type","description":"Exception type of the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_codes","description":"Exception codes from the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_notes","description":"Exception notes from the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"The value of the system registers","type":"text","hidden":false,"required":false,"index":false}]},{"name":"crontab","description":"Line parsed values from system and user cron/tab.","platforms":["darwin","linux"],"columns":[{"name":"event","description":"The job @event name (rare)","type":"text","hidden":false,"required":false,"index":false},{"name":"minute","description":"The exact minute for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"hour","description":"The hour of the day for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"day_of_month","description":"The day of the month for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"month","description":"The month of the year for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"day_of_week","description":"The day of the week for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"command","description":"Raw command string","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File parsed","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"cups_destinations","description":"Returns all configured printers.","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the printer","type":"text","hidden":false,"required":false,"index":false},{"name":"option_name","description":"Option name","type":"text","hidden":false,"required":false,"index":false},{"name":"option_value","description":"Option value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"cups_jobs","description":"Returns all completed print jobs from cups.","platforms":["darwin"],"columns":[{"name":"title","description":"Title of the printed job","type":"text","hidden":false,"required":false,"index":false},{"name":"destination","description":"The printer the job was sent to","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"The user who printed the job","type":"text","hidden":false,"required":false,"index":false},{"name":"format","description":"The format of the print job","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the print job","type":"integer","hidden":false,"required":false,"index":false},{"name":"completed_time","description":"When the job completed printing","type":"integer","hidden":false,"required":false,"index":false},{"name":"processing_time","description":"How long the job took to process","type":"integer","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the print request was initiated","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"curl","description":"Perform an http request and return stats about it.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"url","description":"The url for the request","type":"text","hidden":false,"required":true,"index":false},{"name":"method","description":"The HTTP method for the request","type":"text","hidden":false,"required":false,"index":false},{"name":"user_agent","description":"The user-agent string to use for the request","type":"text","hidden":false,"required":false,"index":false},{"name":"response_code","description":"The HTTP status code for the response","type":"integer","hidden":false,"required":false,"index":false},{"name":"round_trip_time","description":"Time taken to complete the request","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of bytes in the response","type":"bigint","hidden":false,"required":false,"index":false},{"name":"result","description":"The HTTP response body","type":"text","hidden":false,"required":false,"index":false}]},{"name":"curl_certificate","description":"Inspect TLS certificates by connecting to input hostnames.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"hostname","description":"Hostname (domain[:port]) to CURL","type":"text","hidden":false,"required":true,"index":false},{"name":"common_name","description":"Common name of company issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"organization","description":"Organization issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"organization_unit","description":"Organization unit issued to","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Certificate serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_common_name","description":"Issuer common name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_organization","description":"Issuer organization","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_organization_unit","description":"Issuer organization unit","type":"text","hidden":false,"required":false,"index":false},{"name":"valid_from","description":"Period of validity start date","type":"text","hidden":false,"required":false,"index":false},{"name":"valid_to","description":"Period of validity end date","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256_fingerprint","description":"SHA-256 fingerprint","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1_fingerprint","description":"SHA1 fingerprint","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version Number","type":"integer","hidden":false,"required":false,"index":false},{"name":"signature_algorithm","description":"Signature Algorithm","type":"text","hidden":false,"required":false,"index":false},{"name":"signature","description":"Signature","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_key_identifier","description":"Subject Key Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"authority_key_identifier","description":"Authority Key Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Usage of key in certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"extended_key_usage","description":"Extended usage of key in certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"policies","description":"Certificate Policies","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_alternative_names","description":"Subject Alternative Name","type":"text","hidden":false,"required":false,"index":false},{"name":"issuer_alternative_names","description":"Issuer Alternative Name","type":"text","hidden":false,"required":false,"index":false},{"name":"info_access","description":"Authority Information Access","type":"text","hidden":false,"required":false,"index":false},{"name":"subject_info_access","description":"Subject Information Access","type":"text","hidden":false,"required":false,"index":false},{"name":"policy_mappings","description":"Policy Mappings","type":"text","hidden":false,"required":false,"index":false},{"name":"has_expired","description":"1 if the certificate has expired, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"basic_constraint","description":"Basic Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"name_constraints","description":"Name Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"policy_constraints","description":"Policy Constraints","type":"text","hidden":false,"required":false,"index":false},{"name":"dump_certificate","description":"Set this value to '1' to dump certificate","type":"integer","hidden":true,"required":false,"index":false},{"name":"timeout","description":"Set this value to the timeout in seconds to complete the TLS handshake (default 4s, use 0 for no timeout)","type":"integer","hidden":true,"required":false,"index":false},{"name":"pem","description":"Certificate PEM format","type":"text","hidden":false,"required":false,"index":false}]},{"name":"deb_packages","description":"The installed DEB package database.","platforms":["linux"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Package source","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Package architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"Package revision","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Package status","type":"text","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Package maintainer","type":"text","hidden":false,"required":false,"index":false},{"name":"section","description":"Package section","type":"text","hidden":false,"required":false,"index":false},{"name":"priority","description":"Package priority","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"default_environment","description":"Default environment variables and values.","platforms":["windows"],"columns":[{"name":"variable","description":"Name of the environment variable","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the environment variable","type":"text","hidden":false,"required":false,"index":false},{"name":"expand","description":"1 if the variable needs expanding, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"device_file","description":"Similar to the file table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","hidden":false,"required":true,"index":false},{"name":"path","description":"A logical path within the device node","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Creation time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_firmware","description":"A best-effort list of discovered firmware versions.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of device","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"The device name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Firmware version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_hash","description":"Similar to the hash table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","hidden":false,"required":true,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided inode data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"device_partitions","description":"Use TSK to enumerate details about partitions on a disk device.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number or description","type":"integer","hidden":false,"required":false,"index":false},{"name":"label","description":"","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Byte size of each block","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Number of blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Number of meta nodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"disk_encryption","description":"Disk encryption status and information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Disk name","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Disk Universally Unique Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 If encrypted: true (disk is encrypted), else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Description of cipher type and mode if available","type":"text","hidden":false,"required":false,"index":false},{"name":"encryption_status","description":"Disk encryption status with one of following values: encrypted | not encrypted | undefined","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Currently authenticated user if available","type":"text","hidden":false,"required":false,"index":false},{"name":"user_uuid","description":"UUID of authenticated user if available","type":"text","hidden":false,"required":false,"index":false},{"name":"filevault_status","description":"FileVault status with one of following values: on | off | unknown","type":"text","hidden":false,"required":false,"index":false}]},{"name":"disk_events","description":"Track DMG disk image events (appearance/disappearance) when opened.","platforms":["darwin"],"columns":[{"name":"action","description":"Appear or disappear","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the DMG file accessed","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Disk event name","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Disk event BSD name","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"UUID of the volume inside DMG if available","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of partition in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ejectable","description":"1 if ejectable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"mountable","description":"1 if mountable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"writable","description":"1 if writable, 0 if not","type":"integer","hidden":false,"required":false,"index":false},{"name":"content","description":"Disk event content","type":"text","hidden":false,"required":false,"index":false},{"name":"media_name","description":"Disk event media name string","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Disk event vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"filesystem","description":"Filesystem if available","type":"text","hidden":false,"required":false,"index":false},{"name":"checksum","description":"UDIF Master checksum if available (CRC32)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of appearance/disappearance in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"disk_info","description":"Retrieve basic information about the physical disks of a system.","platforms":["windows"],"columns":[{"name":"partitions","description":"Number of detected partitions on disk.","type":"integer","hidden":false,"required":false,"index":false},{"name":"disk_index","description":"Physical drive number of the disk.","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"The interface type of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"The unique identifier of the drive on the system.","type":"text","hidden":false,"required":false,"index":false},{"name":"pnp_device_id","description":"The unique identifier of the drive on the system.","type":"text","hidden":false,"required":false,"index":false},{"name":"disk_size","description":"Size of the disk.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hard drive model.","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"The label of the disk object.","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the disk.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The OS's description of the disk.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"dns_cache","description":"Enumerate the DNS cache using the undocumented DnsGetCacheDataTable function in dnsapi.dll.","platforms":["windows"],"columns":[{"name":"name","description":"DNS record name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"DNS record type","type":"text","hidden":false,"required":false,"index":false},{"name":"flags","description":"DNS record flags","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"dns_resolvers","description":"Resolvers used by this host.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Address type index or order","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Address type: sortlist, nameserver, search","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Resolver IP/IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Address (sortlist) netmask length","type":"text","hidden":false,"required":false,"index":false},{"name":"options","description":"Resolver options","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"docker_container_fs_changes","description":"Changes to files or directories on container's filesystem.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"path","description":"FIle or directory path relative to rootfs","type":"text","hidden":false,"required":false,"index":false},{"name":"change_type","description":"Type of change: C:Modified, A:Added, D:Deleted","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_labels","description":"Docker container labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_mounts","description":"Docker container mounts.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of mount (bind, volume)","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Optional mount name","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source path on host","type":"text","hidden":false,"required":false,"index":false},{"name":"destination","description":"Destination path inside container","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver providing the mount","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"Mount options (rw, ro)","type":"text","hidden":false,"required":false,"index":false},{"name":"rw","description":"1 if read/write. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"propagation","description":"Mount propagation","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_networks","description":"Docker container networks.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Network name","type":"text","hidden":false,"required":false,"index":false},{"name":"network_id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"endpoint_id","description":"Endpoint ID","type":"text","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"ip_address","description":"IP address","type":"text","hidden":false,"required":false,"index":false},{"name":"ip_prefix_len","description":"IP subnet prefix length","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv6_gateway","description":"IPv6 gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_prefix_len","description":"IPv6 subnet prefix length","type":"integer","hidden":false,"required":false,"index":false},{"name":"mac_address","description":"MAC address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_container_ports","description":"Docker container ports.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Protocol (tcp, udp)","type":"text","hidden":false,"required":false,"index":false},{"name":"port","description":"Port inside the container","type":"integer","hidden":false,"required":false,"index":false},{"name":"host_ip","description":"Host IP address on which public port is listening","type":"text","hidden":false,"required":false,"index":false},{"name":"host_port","description":"Host port","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"docker_container_processes","description":"Docker container processes.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start in seconds since boot (non-sleeping)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"User name","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Cumulative CPU time. [DD-]HH:MM:SS format","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu","description":"CPU utilization as percentage","type":"double","hidden":false,"required":false,"index":false},{"name":"mem","description":"Memory utilization as percentage","type":"double","hidden":false,"required":false,"index":false}]},{"name":"docker_container_stats","description":"Docker container statistics. Queries on this table take at least one second.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":true,"index":false},{"name":"name","description":"Container name","type":"text","hidden":false,"required":false,"index":false},{"name":"pids","description":"Number of processes","type":"integer","hidden":false,"required":false,"index":false},{"name":"read","description":"UNIX time when stats were read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"preread","description":"UNIX time when stats were last read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"interval","description":"Difference between read and preread in nano-seconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_read","description":"Total disk read bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_write","description":"Total disk write bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"num_procs","description":"Number of processors","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_total_usage","description":"Total CPU usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_kernelmode_usage","description":"CPU kernel mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_usermode_usage","description":"CPU user mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_cpu_usage","description":"CPU system usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"online_cpus","description":"Online CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"pre_cpu_total_usage","description":"Last read total CPU usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_cpu_kernelmode_usage","description":"Last read CPU kernel mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_cpu_usermode_usage","description":"Last read CPU user mode usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_system_cpu_usage","description":"Last read CPU system usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pre_online_cpus","description":"Last read online CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory_usage","description":"Memory usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_max_usage","description":"Memory maximum usage","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"Memory limit","type":"bigint","hidden":false,"required":false,"index":false},{"name":"network_rx_bytes","description":"Total network bytes read","type":"bigint","hidden":false,"required":false,"index":false},{"name":"network_tx_bytes","description":"Total network bytes transmitted","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"docker_containers","description":"Docker containers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Container name","type":"text","hidden":false,"required":false,"index":false},{"name":"image","description":"Docker image (name) used to launch this container","type":"text","hidden":false,"required":false,"index":false},{"name":"image_id","description":"Docker image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"command","description":"Command with arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"state","description":"Container state (created, restarting, running, removing, paused, exited, dead)","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Container status information","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Identifier of the initial process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Container path","type":"text","hidden":false,"required":false,"index":false},{"name":"config_entrypoint","description":"Container entrypoint(s)","type":"text","hidden":false,"required":false,"index":false},{"name":"started_at","description":"Container start time as string","type":"text","hidden":false,"required":false,"index":false},{"name":"finished_at","description":"Container finish time as string","type":"text","hidden":false,"required":false,"index":false},{"name":"privileged","description":"Is the container privileged","type":"integer","hidden":false,"required":false,"index":false},{"name":"security_options","description":"List of container security options","type":"text","hidden":false,"required":false,"index":false},{"name":"env_variables","description":"Container environmental variables","type":"text","hidden":false,"required":false,"index":false},{"name":"readonly_rootfs","description":"Is the root filesystem mounted as read only","type":"integer","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"ipc_namespace","description":"IPC namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"mnt_namespace","description":"Mount namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"net_namespace","description":"Network namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"pid_namespace","description":"PID namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"user_namespace","description":"User namespace","type":"text","hidden":true,"required":false,"index":false},{"name":"uts_namespace","description":"UTS namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"docker_image_history","description":"Docker image history information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of instruction in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"created_by","description":"Created by instruction","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of tags","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Instruction comment","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_image_labels","description":"Docker image labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_image_layers","description":"Docker image layers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"layer_id","description":"Layer ID","type":"text","hidden":false,"required":false,"index":false},{"name":"layer_order","description":"Layer Order (1 = base layer)","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"docker_images","description":"Docker images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size_bytes","description":"Size of image in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of repository tags","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_info","description":"Docker system information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Docker system ID","type":"text","hidden":false,"required":false,"index":false},{"name":"containers","description":"Total number of containers","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_running","description":"Number of containers currently running","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_paused","description":"Number of containers in paused state","type":"integer","hidden":false,"required":false,"index":false},{"name":"containers_stopped","description":"Number of containers in stopped state","type":"integer","hidden":false,"required":false,"index":false},{"name":"images","description":"Number of images","type":"integer","hidden":false,"required":false,"index":false},{"name":"storage_driver","description":"Storage driver","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"1 if memory limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"swap_limit","description":"1 if swap limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"kernel_memory","description":"1 if kernel memory limit support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_period","description":"1 if CPU Completely Fair Scheduler (CFS) period support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_quota","description":"1 if CPU Completely Fair Scheduler (CFS) quota support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_shares","description":"1 if CPU share weighting support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_set","description":"1 if CPU set selection support is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_forwarding","description":"1 if IPv4 forwarding is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"bridge_nf_iptables","description":"1 if bridge netfilter iptables is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"bridge_nf_ip6tables","description":"1 if bridge netfilter ip6tables is enabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"oom_kill_disable","description":"1 if Out-of-memory kill is disabled. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"logging_driver","description":"Logging driver","type":"text","hidden":false,"required":false,"index":false},{"name":"cgroup_driver","description":"Control groups driver","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Operating system type","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"cpus","description":"Number of CPUs","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory","description":"Total memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"http_proxy","description":"HTTP proxy","type":"text","hidden":false,"required":false,"index":false},{"name":"https_proxy","description":"HTTPS proxy","type":"text","hidden":false,"required":false,"index":false},{"name":"no_proxy","description":"Comma-separated list of domain extensions proxy should not be used for","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the docker host","type":"text","hidden":false,"required":false,"index":false},{"name":"server_version","description":"Server version","type":"text","hidden":false,"required":false,"index":false},{"name":"root_dir","description":"Docker root directory","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_network_labels","description":"Docker network labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_networks","description":"Docker networks information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Network name","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Network driver","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"enable_ipv6","description":"1 if IPv6 is enabled on this network. 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"subnet","description":"Network subnet","type":"text","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Network gateway","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_version","description":"Docker version information.","platforms":["darwin","linux"],"columns":[{"name":"version","description":"Docker version","type":"text","hidden":false,"required":false,"index":false},{"name":"api_version","description":"API version","type":"text","hidden":false,"required":false,"index":false},{"name":"min_api_version","description":"Minimum API version supported","type":"text","hidden":false,"required":false,"index":false},{"name":"git_commit","description":"Docker build git commit","type":"text","hidden":false,"required":false,"index":false},{"name":"go_version","description":"Go version","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"Hardware architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Build time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_volume_labels","description":"Docker volume labels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Label key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"docker_volumes","description":"Docker volumes information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Volume driver","type":"text","hidden":false,"required":false,"index":false},{"name":"mount_point","description":"Mount point","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Volume type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"drivers","description":"Details for in-use Windows device drivers. This does not display installed but unused drivers.","platforms":["windows"],"columns":[{"name":"device_id","description":"Device ID","type":"text","hidden":false,"required":false,"index":false},{"name":"device_name","description":"Device name","type":"text","hidden":false,"required":false,"index":false},{"name":"image","description":"Path to driver image file","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Driver description","type":"text","hidden":false,"required":false,"index":false},{"name":"service","description":"Driver service name, if one exists","type":"text","hidden":false,"required":false,"index":false},{"name":"service_key","description":"Driver service registry key","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Driver version","type":"text","hidden":false,"required":false,"index":false},{"name":"inf","description":"Associated inf file","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Device/driver class name","type":"text","hidden":false,"required":false,"index":false},{"name":"provider","description":"Driver provider","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Device manufacturer","type":"text","hidden":false,"required":false,"index":false},{"name":"driver_key","description":"Driver key","type":"text","hidden":false,"required":false,"index":false},{"name":"date","description":"Driver date","type":"bigint","hidden":false,"required":false,"index":false},{"name":"signed","description":"Whether the driver is signed or not","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_metadata","description":"EC2 instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_type","description":"EC2 instance type","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture of this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"region","description":"AWS region in which this instance launched","type":"text","hidden":false,"required":false,"index":false},{"name":"availability_zone","description":"Availability zone in which this instance launched","type":"text","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Private IPv4 DNS hostname of the first interface of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"local_ipv4","description":"Private IPv4 address of the first interface of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address for the first network interface of this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"security_groups","description":"Comma separated list of security group names","type":"text","hidden":false,"required":false,"index":false},{"name":"iam_arn","description":"If there is an IAM role associated with the instance, contains instance profile ARN","type":"text","hidden":false,"required":false,"index":false},{"name":"ami_id","description":"AMI ID used to launch this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"reservation_id","description":"ID of the reservation","type":"text","hidden":false,"required":false,"index":false},{"name":"account_id","description":"AWS account ID which owns this EC2 instance","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_tags","description":"EC2 instance tag key value pairs.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Tag key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"elf_dynamic","description":"ELF dynamic section information.","platforms":["linux"],"columns":[{"name":"tag","description":"Tag ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"integer","hidden":false,"required":false,"index":false},{"name":"class","description":"Class (32 or 64)","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_info","description":"ELF file information.","platforms":["linux"],"columns":[{"name":"class","description":"Class type, 32 or 64bit","type":"text","hidden":false,"required":false,"index":false},{"name":"abi","description":"Section type","type":"text","hidden":false,"required":false,"index":false},{"name":"abi_version","description":"Section virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Offset of section in file","type":"text","hidden":false,"required":false,"index":false},{"name":"machine","description":"Machine type","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Object file version","type":"integer","hidden":false,"required":false,"index":false},{"name":"entry","description":"Entry point address","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"ELF header flags","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_sections","description":"ELF section information.","platforms":["linux"],"columns":[{"name":"name","description":"Section name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Section type","type":"integer","hidden":false,"required":false,"index":false},{"name":"vaddr","description":"Section virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset of section in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of section","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Section attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"link","description":"Link to other section","type":"text","hidden":false,"required":false,"index":false},{"name":"align","description":"Segment alignment","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_segments","description":"ELF segment information.","platforms":["linux"],"columns":[{"name":"name","description":"Segment type/name","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Segment offset in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"vaddr","description":"Segment virtual address in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"psize","description":"Size of segment in file","type":"integer","hidden":false,"required":false,"index":false},{"name":"msize","description":"Segment offset in memory","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Segment attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"align","description":"Segment alignment","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"elf_symbols","description":"ELF symbol list.","platforms":["linux"],"columns":[{"name":"name","description":"Symbol name","type":"text","hidden":false,"required":false,"index":false},{"name":"addr","description":"Symbol address (value)","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of object","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Symbol type","type":"text","hidden":false,"required":false,"index":false},{"name":"binding","description":"Binding type","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Section table index","type":"integer","hidden":false,"required":false,"index":false},{"name":"table","description":"Table name containing symbol","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to ELF file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"es_process_events","description":"Process execution events from EndpointSecurity.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"original_parent","description":"Original parent process ID in case of reparenting","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline_count","description":"Number of command line arguments","type":"bigint","hidden":false,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","hidden":false,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective User ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective Group ID of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false},{"name":"signing_id","description":"Signature identifier of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"team_id","description":"Team identifier of thd process","type":"text","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Codesigning hash of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_binary","description":"Indicates if the binary is Apple signed binary (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of a process in case of an exit event","type":"integer","hidden":false,"required":false,"index":false},{"name":"child_pid","description":"Process ID of a child process in case of a fork event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"etc_hosts","description":"Line-parsed /etc/hosts.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"address","description":"IP address mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"hostnames","description":"Raw hosts mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"etc_protocols","description":"Line-parsed /etc/protocols.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Protocol name","type":"text","hidden":false,"required":false,"index":false},{"name":"number","description":"Protocol number","type":"integer","hidden":false,"required":false,"index":false},{"name":"alias","description":"Protocol alias","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Comment with protocol description","type":"text","hidden":false,"required":false,"index":false}]},{"name":"etc_services","description":"Line-parsed /etc/services.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Service name","type":"text","hidden":false,"required":false,"index":false},{"name":"port","description":"Service port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"text","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Optional space separated list of other names for a service","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment for a service.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"event_taps","description":"Returns information about installed event taps.","platforms":["darwin"],"columns":[{"name":"enabled","description":"Is the Event Tap enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"event_tap_id","description":"Unique ID for the Tap","type":"integer","hidden":false,"required":false,"index":false},{"name":"event_tapped","description":"The mask that identifies the set of events to be observed.","type":"text","hidden":false,"required":false,"index":false},{"name":"process_being_tapped","description":"The process ID of the target application","type":"integer","hidden":false,"required":false,"index":false},{"name":"tapping_process","description":"The process ID of the application that created the event tap.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"example","description":"This is an example table spec.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Description for name column","type":"text","hidden":false,"required":false,"index":false},{"name":"points","description":"This is a signed SQLite int column","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"This is a signed SQLite bigint column","type":"bigint","hidden":false,"required":false,"index":false},{"name":"action","description":"Action performed in generation","type":"text","hidden":false,"required":true,"index":false},{"name":"id","description":"An index of some sort","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of example","type":"text","hidden":false,"required":false,"index":false}]},{"name":"extended_attributes","description":"Returns the extended attributes for files (similar to Windows ADS).","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute file path","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the value generated from the extended attribute","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"The parsed information from the attribute","type":"text","hidden":false,"required":false,"index":false},{"name":"base64","description":"1 if the value is base64 encoded else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"fan_speed_sensors","description":"Fan speeds.","platforms":["darwin"],"columns":[{"name":"fan","description":"Fan number","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Fan name","type":"text","hidden":false,"required":false,"index":false},{"name":"actual","description":"Actual speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimum speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum speed","type":"integer","hidden":false,"required":false,"index":false},{"name":"target","description":"Target speed","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"fbsd_kmods","description":"Loaded FreeBSD kernel modules.","platforms":["freebsd"],"columns":[{"name":"name","description":"Module name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"integer","hidden":false,"required":false,"index":false},{"name":"refs","description":"Module reverse dependencies","type":"integer","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"file","description":"Interactive filesystem attributes and metadata.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"path","description":"Absolute file path","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","hidden":false,"required":true,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Device ID (optional)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"btime","description":"(B)irth or (cr)eate time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","hidden":false,"required":false,"index":false},{"name":"symlink","description":"1 if the path is a symlink, otherwise 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","hidden":false,"required":false,"index":false},{"name":"attributes","description":"File attrib string. See: https://ss64.com/nt/attrib.html","type":"text","hidden":true,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number","type":"text","hidden":true,"required":false,"index":false},{"name":"file_id","description":"file ID","type":"text","hidden":true,"required":false,"index":false},{"name":"file_version","description":"File version","type":"text","hidden":true,"required":false,"index":false},{"name":"product_version","description":"File product version","type":"text","hidden":true,"required":false,"index":false},{"name":"bsd_flags","description":"The BSD file flags (chflags). Possible values: NODUMP, UF_IMMUTABLE, UF_APPEND, OPAQUE, HIDDEN, ARCHIVED, SF_IMMUTABLE, SF_APPEND","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"file_events","description":"Track time/action changes to files specified in configuration data.","platforms":["darwin","linux"],"columns":[{"name":"target_path","description":"The path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file defined in the config","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"md5","description":"The MD5 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"The SHA1 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"The SHA256 of the file after change","type":"text","hidden":false,"required":false,"index":false},{"name":"hashed","description":"1 if the file was hashed, 0 if not, -1 if hashing failed","type":"integer","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"firefox_addons","description":"Firefox browser extensions, webapps, and addons.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local user that owns the addon","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Addon display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Addon identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"creator","description":"Addon-supported creator string","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Extension, addon, webapp","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Addon-supplied version string","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Addon-supplied description string","type":"text","hidden":false,"required":false,"index":false},{"name":"source_url","description":"URL that installed the addon","type":"text","hidden":false,"required":false,"index":false},{"name":"visible","description":"1 If the addon is shown in browser else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If the addon is active else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 If the addon is application-disabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"1 If the addon applies background updates else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"native","description":"1 If the addon includes binary components else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"location","description":"Global, profile location","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper","description":"OS X Gatekeeper Details.","platforms":["darwin"],"columns":[{"name":"assessments_enabled","description":"1 If a Gatekeeper is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"dev_id_enabled","description":"1 If a Gatekeeper allows execution from identified developers else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of Gatekeeper's gke.bundle","type":"text","hidden":false,"required":false,"index":false},{"name":"opaque_version","description":"Version of Gatekeeper's gkopaque.bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper_approved_apps","description":"Gatekeeper apps a user has allowed to run.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of executable allowed to run","type":"text","hidden":false,"required":false,"index":false},{"name":"requirement","description":"Code signing requirement language","type":"text","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last change time","type":"double","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"double","hidden":false,"required":false,"index":false}]},{"name":"groups","description":"Local system groups.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","hidden":true,"required":false,"index":false},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"hardware_events","description":"Hardware (PCI/USB/HID) events from UDEV or IOKit.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"Remove, insert, change properties, etc","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Local device path assigned (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of hardware and hardware event","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver claiming the device","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Hardware device vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded Hardware vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"Hardware device model","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded Hardware model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"Device serial (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"Device revision (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of hardware event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"hash","description":"Filesystem hash data.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"directory","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"ssdeep","description":"ssdeep hash of provided filesystem data","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"homebrew_packages","description":"The installed homebrew package database.","platforms":["darwin"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Package install path","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Current 'linked' version","type":"text","hidden":false,"required":false,"index":false},{"name":"prefix","description":"Homebrew install prefix","type":"text","hidden":true,"required":false,"index":false}]},{"name":"hvci_status","description":"Retrieve HVCI info of the machine.","platforms":["windows"],"columns":[{"name":"version","description":"The version number of the Device Guard build.","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_identifier","description":"The instance ID of Device Guard.","type":"text","hidden":false,"required":false,"index":false},{"name":"vbs_status","description":"The status of the virtualization based security settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false},{"name":"code_integrity_policy_enforcement_status","description":"The status of the code integrity policy enforcement settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false},{"name":"umci_policy_status","description":"The status of the User Mode Code Integrity security settings. Returns UNKNOWN if an error is encountered.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ibridge_info","description":"Information about the Apple iBridge hardware controller.","platforms":["darwin"],"columns":[{"name":"boot_uuid","description":"Boot UUID of the iBridge controller","type":"text","hidden":false,"required":false,"index":false},{"name":"coprocessor_version","description":"The manufacturer and chip version","type":"text","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"The build version of the firmware","type":"text","hidden":false,"required":false,"index":false},{"name":"unique_chip_id","description":"Unique id of the iBridge controller","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ie_extensions","description":"Internet Explorer browser extensions.","platforms":["windows"],"columns":[{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"registry_path","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the executable","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executable","type":"text","hidden":false,"required":false,"index":false}]},{"name":"intel_me_info","description":"Intel ME/CSE Info.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"version","description":"Intel ME version","type":"text","hidden":false,"required":false,"index":false}]},{"name":"interface_addresses","description":"Network interfaces and relevant metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for interface","type":"text","hidden":false,"required":false,"index":false},{"name":"mask","description":"Interface netmask","type":"text","hidden":false,"required":false,"index":false},{"name":"broadcast","description":"Broadcast address for the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"point_to_point","description":"PtP address for the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of address. One of dhcp, manual, auto, other, unknown","type":"text","hidden":false,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"interface_details","description":"Detailed information and stats of network interfaces.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC of interface (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Interface type (includes virtual)","type":"integer","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Network MTU","type":"integer","hidden":false,"required":false,"index":false},{"name":"metric","description":"Metric based on the speed of the interface","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags (netdevice) for the device","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipackets","description":"Input packets","type":"bigint","hidden":false,"required":false,"index":false},{"name":"opackets","description":"Output packets","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ibytes","description":"Input bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"obytes","description":"Output bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ierrors","description":"Input errors","type":"bigint","hidden":false,"required":false,"index":false},{"name":"oerrors","description":"Output errors","type":"bigint","hidden":false,"required":false,"index":false},{"name":"idrops","description":"Input drops","type":"bigint","hidden":false,"required":false,"index":false},{"name":"odrops","description":"Output drops","type":"bigint","hidden":false,"required":false,"index":false},{"name":"collisions","description":"Packet Collisions detected","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Time of last device modification (optional)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"link_speed","description":"Interface speed in Mb/s","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pci_slot","description":"PCI slot number","type":"text","hidden":true,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","hidden":true,"required":false,"index":false},{"name":"description","description":"Short description of the object a one-line string.","type":"text","hidden":true,"required":false,"index":false},{"name":"manufacturer","description":"Name of the network adapter's manufacturer.","type":"text","hidden":true,"required":false,"index":false},{"name":"connection_id","description":"Name of the network connection as it appears in the Network Connections Control Panel program.","type":"text","hidden":true,"required":false,"index":false},{"name":"connection_status","description":"State of the network adapter connection to the network.","type":"text","hidden":true,"required":false,"index":false},{"name":"enabled","description":"Indicates whether the adapter is enabled or not.","type":"integer","hidden":true,"required":false,"index":false},{"name":"physical_adapter","description":"Indicates whether the adapter is a physical or a logical adapter.","type":"integer","hidden":true,"required":false,"index":false},{"name":"speed","description":"Estimate of the current bandwidth in bits per second.","type":"integer","hidden":true,"required":false,"index":false},{"name":"service","description":"The name of the service the network adapter uses.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_enabled","description":"If TRUE, the dynamic host configuration protocol (DHCP) server automatically assigns an IP address to the computer system when establishing a network connection.","type":"integer","hidden":true,"required":false,"index":false},{"name":"dhcp_lease_expires","description":"Expiration date and time for a leased IP address that was assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_lease_obtained","description":"Date and time the lease was obtained for the IP address assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dhcp_server","description":"IP address of the dynamic host configuration protocol (DHCP) server.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_domain","description":"Organization name followed by a period and an extension that indicates the type of organization, such as 'microsoft.com'.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_domain_suffix_search_order","description":"Array of DNS domain suffixes to be appended to the end of host names during name resolution.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_host_name","description":"Host name used to identify the local computer for authentication by some utilities.","type":"text","hidden":true,"required":false,"index":false},{"name":"dns_server_search_order","description":"Array of server IP addresses to be used in querying for DNS servers.","type":"text","hidden":true,"required":false,"index":false}]},{"name":"interface_ipv6","description":"IPv6 configuration and stats of network interfaces.","platforms":["darwin","linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"hop_limit","description":"Current Hop Limit","type":"integer","hidden":false,"required":false,"index":false},{"name":"forwarding_enabled","description":"Enable IP forwarding","type":"integer","hidden":false,"required":false,"index":false},{"name":"redirect_accept","description":"Accept ICMP redirect messages","type":"integer","hidden":false,"required":false,"index":false},{"name":"rtadv_accept","description":"Accept ICMP Router Advertisement","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iokit_devicetree","description":"The IOKit registry matching the DeviceTree plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Device node name","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent device registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"device_path","description":"Device tree path","type":"text","hidden":false,"required":false,"index":false},{"name":"service","description":"1 if the device conforms to IOService else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the device is in a busy state else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The device reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"depth","description":"Device nested depth","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iokit_registry","description":"The full IOKit registry without selecting a plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Default name of the node","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent registry ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the node is in a busy state else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The node reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"depth","description":"Node nested depth","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"iptables","description":"Linux IP packet filtering and NAT tool.","platforms":["linux"],"columns":[{"name":"filter_name","description":"Packet matching filter table name.","type":"text","hidden":false,"required":false,"index":false},{"name":"chain","description":"Size of module content.","type":"text","hidden":false,"required":false,"index":false},{"name":"policy","description":"Policy that applies for this rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"target","description":"Target that applies for this rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Protocol number identification.","type":"integer","hidden":false,"required":false,"index":false},{"name":"src_port","description":"Protocol source port(s).","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_port","description":"Protocol destination port(s).","type":"text","hidden":false,"required":false,"index":false},{"name":"src_ip","description":"Source IP address.","type":"text","hidden":false,"required":false,"index":false},{"name":"src_mask","description":"Source IP address mask.","type":"text","hidden":false,"required":false,"index":false},{"name":"iniface","description":"Input interface for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"iniface_mask","description":"Input interface mask for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_ip","description":"Destination IP address.","type":"text","hidden":false,"required":false,"index":false},{"name":"dst_mask","description":"Destination IP address mask.","type":"text","hidden":false,"required":false,"index":false},{"name":"outiface","description":"Output interface for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"outiface_mask","description":"Output interface mask for the rule.","type":"text","hidden":false,"required":false,"index":false},{"name":"match","description":"Matching rule that applies.","type":"text","hidden":false,"required":false,"index":false},{"name":"packets","description":"Number of matching packets for this rule.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of matching bytes for this rule.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"kernel_extensions","description":"OS X's kernel extensions, both loaded and within the load search path.","platforms":["darwin"],"columns":[{"name":"idx","description":"Extension load tag or index","type":"integer","hidden":false,"required":false,"index":false},{"name":"refs","description":"Reference count","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Bytes of wired memory used by extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension label","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension version","type":"text","hidden":false,"required":false,"index":false},{"name":"linked_against","description":"Indexes of extensions this extension is linked against","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Optional path to extension bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_info","description":"Basic active kernel information.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"version","description":"Kernel version","type":"text","hidden":false,"required":false,"index":false},{"name":"arguments","description":"Kernel arguments","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Kernel path","type":"text","hidden":false,"required":false,"index":false},{"name":"device","description":"Kernel device identifier","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_modules","description":"Linux kernel modules both loaded and within the load search path.","platforms":["linux"],"columns":[{"name":"name","description":"Module name","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"bigint","hidden":false,"required":false,"index":false},{"name":"used_by","description":"Module reverse dependencies","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Kernel module status","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kernel_panics","description":"System kernel panic logs.","platforms":["darwin"],"columns":[{"name":"path","description":"Location of log file","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Formatted time of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"A space delimited line of register:value pairs","type":"text","hidden":false,"required":false,"index":false},{"name":"frame_backtrace","description":"Backtrace of the crashed module","type":"text","hidden":false,"required":false,"index":false},{"name":"module_backtrace","description":"Modules appearing in the crashed module's backtrace","type":"text","hidden":false,"required":false,"index":false},{"name":"dependencies","description":"Module dependencies existing in crashed module's backtrace","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name corresponding to crashed thread","type":"text","hidden":false,"required":false,"index":false},{"name":"os_version","description":"Version of the operating system","type":"text","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Version of the system kernel","type":"text","hidden":false,"required":false,"index":false},{"name":"system_model","description":"Physical system model, for example 'MacBookPro12,1 (Mac-E43C1C25D4880AD6)'","type":"text","hidden":false,"required":false,"index":false},{"name":"uptime","description":"System uptime at kernel panic in nanoseconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_loaded","description":"Last loaded module before panic","type":"text","hidden":false,"required":false,"index":false},{"name":"last_unloaded","description":"Last unloaded module before panic","type":"text","hidden":false,"required":false,"index":false}]},{"name":"keychain_acls","description":"Applications that have ACL entries in the keychain.","platforms":["darwin"],"columns":[{"name":"keychain_path","description":"The path of the keychain","type":"text","hidden":false,"required":false,"index":false},{"name":"authorizations","description":"A space delimited set of authorization attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the authorized application","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The description included with the ACL entry","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"An optional label tag that may be included with the keychain entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"keychain_items","description":"Generic details about keychain items.","platforms":["darwin"],"columns":[{"name":"label","description":"Generic item name","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional item description","type":"text","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional keychain comment","type":"text","hidden":false,"required":false,"index":false},{"name":"created","description":"Data item was created","type":"text","hidden":false,"required":false,"index":false},{"name":"modified","description":"Date of last modification","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Keychain item type (class)","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to keychain containing item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"known_hosts","description":"A line-delimited known_hosts table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local user that owns the known_hosts file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"key","description":"parsed authorized keys line","type":"text","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to known_hosts file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"kva_speculative_info","description":"Display kernel virtual address and speculative execution information for the system.","platforms":["windows"],"columns":[{"name":"kva_shadow_enabled","description":"Kernel Virtual Address shadowing is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_user_global","description":"User pages are marked as global.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_pcid","description":"Kernel VA PCID flushing optimization is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"kva_shadow_inv_pcid","description":"Kernel VA INVPCID is enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_mitigations","description":"Branch Prediction mitigations are enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_system_pol_disabled","description":"Branch Predictions are disabled via system policy.","type":"integer","hidden":false,"required":false,"index":false},{"name":"bp_microcode_disabled","description":"Branch Predictions are disabled due to lack of microcode update.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_spec_ctrl_supported","description":"SPEC_CTRL MSR supported by CPU Microcode.","type":"integer","hidden":false,"required":false,"index":false},{"name":"ibrs_support_enabled","description":"Windows uses IBRS.","type":"integer","hidden":false,"required":false,"index":false},{"name":"stibp_support_enabled","description":"Windows uses STIBP.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_pred_cmd_supported","description":"PRED_CMD MSR supported by CPU Microcode.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"last","description":"System logins and logouts.","platforms":["darwin","linux"],"columns":[{"name":"username","description":"Entry username","type":"text","hidden":false,"required":false,"index":false},{"name":"tty","description":"Entry terminal","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Entry type, according to ut_type types (utmp.h)","type":"integer","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Entry type name, according to ut_type types (utmp.h)","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp","type":"integer","hidden":false,"required":false,"index":false},{"name":"host","description":"Entry hostname","type":"text","hidden":false,"required":false,"index":false}]},{"name":"launchd","description":"LaunchAgents and LaunchDaemons from default search paths.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to daemon or agent plist","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"File name of plist (used by launchd)","type":"text","hidden":false,"required":false,"index":false},{"name":"label","description":"Daemon or agent service name","type":"text","hidden":false,"required":false,"index":false},{"name":"program","description":"Path to target program","type":"text","hidden":false,"required":false,"index":false},{"name":"run_at_load","description":"Should the program run on launch load","type":"text","hidden":false,"required":false,"index":false},{"name":"keep_alive","description":"Should the process be restarted if killed","type":"text","hidden":false,"required":false,"index":false},{"name":"on_demand","description":"Deprecated key, replaced by keep_alive","type":"text","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Skip loading this daemon or agent on boot","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Run this daemon or agent as this username","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Run this daemon or agent as this group","type":"text","hidden":false,"required":false,"index":false},{"name":"stdout_path","description":"Pipe stdout to a target path","type":"text","hidden":false,"required":false,"index":false},{"name":"stderr_path","description":"Pipe stderr to a target path","type":"text","hidden":false,"required":false,"index":false},{"name":"start_interval","description":"Frequency to run in seconds","type":"text","hidden":false,"required":false,"index":false},{"name":"program_arguments","description":"Command line arguments passed to program","type":"text","hidden":false,"required":false,"index":false},{"name":"watch_paths","description":"Key that launches daemon or agent if path is modified","type":"text","hidden":false,"required":false,"index":false},{"name":"queue_directories","description":"Similar to watch_paths but only with non-empty directories","type":"text","hidden":false,"required":false,"index":false},{"name":"inetd_compatibility","description":"Run this daemon or agent as it was launched from inetd","type":"text","hidden":false,"required":false,"index":false},{"name":"start_on_mount","description":"Run daemon or agent every time a filesystem is mounted","type":"text","hidden":false,"required":false,"index":false},{"name":"root_directory","description":"Key used to specify a directory to chroot to before launch","type":"text","hidden":false,"required":false,"index":false},{"name":"working_directory","description":"Key used to specify a directory to chdir to before launch","type":"text","hidden":false,"required":false,"index":false},{"name":"process_type","description":"Key describes the intended purpose of the job","type":"text","hidden":false,"required":false,"index":false}]},{"name":"launchd_overrides","description":"Override keys, per user, for LaunchDaemons and Agents.","platforms":["darwin"],"columns":[{"name":"label","description":"Daemon or agent service name","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Name of the override key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Overridden value","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID applied to the override, 0 applies to all","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to daemon or agent plist","type":"text","hidden":false,"required":false,"index":false}]},{"name":"listening_ports","description":"Processes with listening (bound) network sockets/ports.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"port","description":"Transport layer port","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for bind","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path for UNIX domain sockets","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"lldp_neighbors","description":"LLDP neighbors of interfaces.","platforms":["linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","hidden":false,"required":false,"index":false},{"name":"rid","description":"Neighbor chassis index","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_id_type","description":"Neighbor chassis ID type","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_id","description":"Neighbor chassis ID value","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_sysname","description":"CPU brand string, contains vendor and model","type":"text","hidden":false,"required":false,"index":false},{"name":"chassis_sys_description","description":"Max number of CPU physical cores","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_bridge_capability_available","description":"Chassis bridge capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_bridge_capability_enabled","description":"Is chassis bridge capability enabled.","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_router_capability_available","description":"Chassis router capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_router_capability_enabled","description":"Chassis router capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_repeater_capability_available","description":"Chassis repeater capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_repeater_capability_enabled","description":"Chassis repeater capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_wlan_capability_available","description":"Chassis wlan capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_wlan_capability_enabled","description":"Chassis wlan capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_tel_capability_available","description":"Chassis telephone capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_tel_capability_enabled","description":"Chassis telephone capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_docsis_capability_available","description":"Chassis DOCSIS capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_docsis_capability_enabled","description":"Chassis DOCSIS capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_station_capability_available","description":"Chassis station capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_station_capability_enabled","description":"Chassis station capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_other_capability_available","description":"Chassis other capability availability","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_other_capability_enabled","description":"Chassis other capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"chassis_mgmt_ips","description":"Comma delimited list of chassis management IPS","type":"text","hidden":false,"required":false,"index":false},{"name":"port_id_type","description":"Port ID type","type":"text","hidden":false,"required":false,"index":false},{"name":"port_id","description":"Port ID value","type":"text","hidden":false,"required":false,"index":false},{"name":"port_description","description":"Port description","type":"text","hidden":false,"required":false,"index":false},{"name":"port_ttl","description":"Age of neighbor port","type":"bigint","hidden":false,"required":false,"index":false},{"name":"port_mfs","description":"Port max frame size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"port_aggregation_id","description":"Port aggregation ID","type":"text","hidden":false,"required":false,"index":false},{"name":"port_autoneg_supported","description":"Auto negotiation supported","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_enabled","description":"Is auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_mau_type","description":"MAU type","type":"text","hidden":false,"required":false,"index":false},{"name":"port_autoneg_10baset_hd_enabled","description":"10Base-T HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_10baset_fd_enabled","description":"10Base-T FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100basetx_hd_enabled","description":"100Base-TX HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100basetx_fd_enabled","description":"100Base-TX FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset2_hd_enabled","description":"100Base-T2 HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset2_fd_enabled","description":"100Base-T2 FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset4_hd_enabled","description":"100Base-T4 HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_100baset4_fd_enabled","description":"100Base-T4 FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000basex_hd_enabled","description":"1000Base-X HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000basex_fd_enabled","description":"1000Base-X FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000baset_hd_enabled","description":"1000Base-T HD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"port_autoneg_1000baset_fd_enabled","description":"1000Base-T FD auto negotiation enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_device_type","description":"Dot3 power device type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_mdi_supported","description":"MDI power supported","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_mdi_enabled","description":"Is MDI power enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_paircontrol_enabled","description":"Is power pair control enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_pairs","description":"Dot3 power pairs","type":"text","hidden":false,"required":false,"index":false},{"name":"power_class","description":"Power class","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_enabled","description":"Is 802.3at enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_type","description":"802.3at power type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_source","description":"802.3at power source","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_priority","description":"802.3at power priority","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_allocated","description":"802.3at power allocated","type":"text","hidden":false,"required":false,"index":false},{"name":"power_8023at_power_requested","description":"802.3at power requested","type":"text","hidden":false,"required":false,"index":false},{"name":"med_device_type","description":"Chassis MED type","type":"text","hidden":false,"required":false,"index":false},{"name":"med_capability_capabilities","description":"Is MED capabilities enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_policy","description":"Is MED policy capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_location","description":"Is MED location capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_mdi_pse","description":"Is MED MDI PSE capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_mdi_pd","description":"Is MED MDI PD capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_capability_inventory","description":"Is MED inventory capability enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"med_policies","description":"Comma delimited list of MED policies","type":"text","hidden":false,"required":false,"index":false},{"name":"vlans","description":"Comma delimited list of vlan ids","type":"text","hidden":false,"required":false,"index":false},{"name":"pvid","description":"Primary VLAN id","type":"text","hidden":false,"required":false,"index":false},{"name":"ppvids_supported","description":"Comma delimited list of supported PPVIDs","type":"text","hidden":false,"required":false,"index":false},{"name":"ppvids_enabled","description":"Comma delimited list of enabled PPVIDs","type":"text","hidden":false,"required":false,"index":false},{"name":"pids","description":"Comma delimited list of PIDs","type":"text","hidden":false,"required":false,"index":false}]},{"name":"load_average","description":"Displays information about the system wide load averages.","platforms":["darwin","linux"],"columns":[{"name":"period","description":"Period over which the average is calculated.","type":"text","hidden":false,"required":false,"index":false},{"name":"average","description":"Load average over the specified period.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"location_services","description":"Reports the status of the Location Services feature of the OS.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 if Location Services are enabled, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"logged_in_users","description":"Users with an active shell on the system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"type","description":"Login type","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"User login name","type":"text","hidden":false,"required":false,"index":false},{"name":"tty","description":"Device name","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"Remote hostname","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time entry was made","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"sid","description":"The user's unique security identifier","type":"text","hidden":true,"required":false,"index":false},{"name":"registry_hive","description":"HKEY_USERS registry hive","type":"text","hidden":true,"required":false,"index":false}]},{"name":"logical_drives","description":"Details for logical drives on the system. A logical drive generally represents a single partition.","platforms":["windows"],"columns":[{"name":"device_id","description":"The drive id, usually the drive name, e.g., 'C:'.","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Deprecated (always 'Unknown').","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"The canonical description of the drive, e.g. 'Logical Fixed Disk', 'CD-ROM Disk'.","type":"text","hidden":false,"required":false,"index":false},{"name":"free_space","description":"The amount of free space, in bytes, of the drive (-1 on failure).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"The total amount of space, in bytes, of the drive (-1 on failure).","type":"bigint","hidden":false,"required":false,"index":false},{"name":"file_system","description":"The file system of the drive.","type":"text","hidden":false,"required":false,"index":false},{"name":"boot_partition","description":"True if Windows booted from this drive.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"logon_sessions","description":"Windows Logon Session.","platforms":["windows"],"columns":[{"name":"logon_id","description":"A locally unique identifier (LUID) that identifies a logon session.","type":"integer","hidden":false,"required":false,"index":false},{"name":"user","description":"The account name of the security principal that owns the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_domain","description":"The name of the domain used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"authentication_package","description":"The authentication package used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_type","description":"The logon method.","type":"text","hidden":false,"required":false,"index":false},{"name":"session_id","description":"The Terminal Services session identifier.","type":"integer","hidden":false,"required":false,"index":false},{"name":"logon_sid","description":"The user's security identifier (SID).","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_time","description":"The time the session owner logged on.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"logon_server","description":"The name of the server used to authenticate the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"dns_domain_name","description":"The DNS name for the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"upn","description":"The user principal name (UPN) for the owner of the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"logon_script","description":"The script used for logging on.","type":"text","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The home directory for the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"home_directory","description":"The home directory for the logon session.","type":"text","hidden":false,"required":false,"index":false},{"name":"home_directory_drive","description":"The drive location of the home directory of the logon session.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_certificates","description":"LXD certificates information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"fingerprint","description":"SHA256 hash of the certificate","type":"text","hidden":false,"required":false,"index":false},{"name":"certificate","description":"Certificate content","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster","description":"LXD cluster information.","platforms":["darwin","linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether clustering enabled (1) or not (0) on this node","type":"integer","hidden":false,"required":false,"index":false},{"name":"member_config_entity","description":"Type of configuration parameter for this node","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_name","description":"Name of configuration parameter","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_key","description":"Config key","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_value","description":"Config value","type":"text","hidden":false,"required":false,"index":false},{"name":"member_config_description","description":"Config description","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster_members","description":"LXD cluster members information.","platforms":["darwin","linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","hidden":false,"required":false,"index":false},{"name":"url","description":"URL of the node","type":"text","hidden":false,"required":false,"index":false},{"name":"database","description":"Whether the server is a database node (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the node (Online/Offline)","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the node (Online/Offline)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_images","description":"LXD images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Target architecture for the image","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"OS on which image is based","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"OS release version on which the image is based","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Image description","type":"text","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Comma-separated list of image aliases","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Filename of the image file","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of image in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auto_update","description":"Whether the image auto-updates (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"cached","description":"Whether image is cached (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"public","description":"Whether image is public (1) or not (0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of image creation","type":"text","hidden":false,"required":false,"index":false},{"name":"expires_at","description":"ISO time of image expiration","type":"text","hidden":false,"required":false,"index":false},{"name":"uploaded_at","description":"ISO time of image upload","type":"text","hidden":false,"required":false,"index":false},{"name":"last_used_at","description":"ISO time for the most recent use of this image in terms of container spawn","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_server","description":"Server for image update","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_protocol","description":"Protocol used for image information update and image import from source server","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_certificate","description":"Certificate for update source server","type":"text","hidden":false,"required":false,"index":false},{"name":"update_source_alias","description":"Alias of image at update source server","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_config","description":"LXD instance configuration information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Configuration parameter name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Configuration parameter value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_devices","description":"LXD instance devices information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":true,"index":false},{"name":"device","description":"Name of the device","type":"text","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device type","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Device info param name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Device info param value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"lxd_instances","description":"LXD instances information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Instance name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Instance state (running, stopped, etc.)","type":"text","hidden":false,"required":false,"index":false},{"name":"stateful","description":"Whether the instance is stateful(1) or not(0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"ephemeral","description":"Whether the instance is ephemeral(1) or not(0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of creation","type":"text","hidden":false,"required":false,"index":false},{"name":"base_image","description":"ID of image used to launch this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Instance architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"os","description":"The OS of this instance","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Instance description","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Instance's process ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"processes","description":"Number of processes running inside this instance","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"lxd_networks","description":"LXD network information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of network","type":"text","hidden":false,"required":false,"index":false},{"name":"managed","description":"1 if network created by LXD, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"ipv4_address","description":"IPv4 address","type":"text","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","hidden":false,"required":false,"index":false},{"name":"used_by","description":"URLs for containers using this network","type":"text","hidden":false,"required":false,"index":false},{"name":"bytes_received","description":"Number of bytes received on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bytes_sent","description":"Number of bytes sent on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"packets_received","description":"Number of packets received on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"packets_sent","description":"Number of packets sent on this network","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hwaddr","description":"Hardware address for this network","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Network status","type":"text","hidden":false,"required":false,"index":false},{"name":"mtu","description":"MTU size","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"lxd_storage_pools","description":"LXD storage pool information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Name of the storage pool","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"Storage driver","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Storage pool source","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the storage pool","type":"text","hidden":false,"required":false,"index":false},{"name":"space_used","description":"Storage space used in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"space_total","description":"Total available storage space in bytes for this storage pool","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_used","description":"Number of inodes used","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_total","description":"Total number of inodes available in this storage pool","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"magic","description":"Magic number recognition library table.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute path to target file","type":"text","hidden":false,"required":true,"index":false},{"name":"magic_db_files","description":"Colon(:) separated list of files where the magic db file can be found. By default one of the following is used: /usr/share/file/magic/magic, /usr/share/misc/magic or /usr/share/misc/magic.mgc","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Magic number data from libmagic","type":"text","hidden":false,"required":false,"index":false},{"name":"mime_type","description":"MIME type data from libmagic","type":"text","hidden":false,"required":false,"index":false},{"name":"mime_encoding","description":"MIME encoding data from libmagic","type":"text","hidden":false,"required":false,"index":false}]},{"name":"managed_policies","description":"The managed configuration policies from AD, MDM, MCX, etc.","platforms":["darwin"],"columns":[{"name":"domain","description":"System or manager-chosen domain key","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Optional UUID assigned to policy set","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy key name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Policy value","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Policy applies only this user","type":"text","hidden":false,"required":false,"index":false},{"name":"manual","description":"1 if policy was loaded manually, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"md_devices","description":"Software RAID array settings.","platforms":["linux"],"columns":[{"name":"device_name","description":"md device name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Current state of the array","type":"text","hidden":false,"required":false,"index":false},{"name":"raid_level","description":"Current raid level of the array","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"size of the array in blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"chunk_size","description":"chunk size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"raid_disks","description":"Number of configured RAID disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"nr_raid_disks","description":"Number of partitions or disk devices to comprise the array","type":"integer","hidden":false,"required":false,"index":false},{"name":"working_disks","description":"Number of working disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"active_disks","description":"Number of active disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"failed_disks","description":"Number of failed disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"spare_disks","description":"Number of idle disks in array","type":"integer","hidden":false,"required":false,"index":false},{"name":"superblock_state","description":"State of the superblock","type":"text","hidden":false,"required":false,"index":false},{"name":"superblock_version","description":"Version of the superblock","type":"text","hidden":false,"required":false,"index":false},{"name":"superblock_update_time","description":"Unix timestamp of last update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"bitmap_on_mem","description":"Pages allocated in in-memory bitmap, if enabled","type":"text","hidden":false,"required":false,"index":false},{"name":"bitmap_chunk_size","description":"Bitmap chunk size","type":"text","hidden":false,"required":false,"index":false},{"name":"bitmap_external_file","description":"External referenced bitmap file","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_progress","description":"Progress of the recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_finish","description":"Estimated duration of recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"recovery_speed","description":"Speed of recovery activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_progress","description":"Progress of the resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_finish","description":"Estimated duration of resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"resync_speed","description":"Speed of resync activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_progress","description":"Progress of the reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_finish","description":"Estimated duration of reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"reshape_speed","description":"Speed of reshape activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_progress","description":"Progress of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_finish","description":"Estimated duration of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"check_array_speed","description":"Speed of the check array activity","type":"text","hidden":false,"required":false,"index":false},{"name":"unused_devices","description":"Unused devices","type":"text","hidden":false,"required":false,"index":false},{"name":"other","description":"Other information associated with array from /proc/mdstat","type":"text","hidden":false,"required":false,"index":false}]},{"name":"md_drives","description":"Drive devices used for Software RAID.","platforms":["linux"],"columns":[{"name":"md_device_name","description":"md device name","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_name","description":"Drive device name","type":"text","hidden":false,"required":false,"index":false},{"name":"slot","description":"Slot position of disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the drive","type":"text","hidden":false,"required":false,"index":false}]},{"name":"md_personalities","description":"Software RAID setting supported by the kernel.","platforms":["linux"],"columns":[{"name":"name","description":"Name of personality supported by kernel","type":"text","hidden":false,"required":false,"index":false}]},{"name":"mdfind","description":"Run searches against the spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file returned from spotlight","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"The query that was run to find the file","type":"text","hidden":false,"required":true,"index":false}]},{"name":"mdls","description":"Query file metadata in the Spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file","type":"text","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the metadata key","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value stored in the metadata key","type":"text","hidden":false,"required":false,"index":false},{"name":"valuetype","description":"CoreFoundation type of data stored in value","type":"text","hidden":true,"required":false,"index":false}]},{"name":"memory_array_mapped_addresses","description":"Data associated for address mapping of physical memory arrays.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_handle","description":"Handle of the memory array associated with this structure","type":"text","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"partition_width","description":"Number of memory devices that form a single row of memory for the address partition of this structure","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_arrays","description":"Data associated with collection of memory devices that operate to form a memory address.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the array","type":"text","hidden":false,"required":false,"index":false},{"name":"location","description":"Physical location of the memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"use","description":"Function for which the array is used","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_error_correction","description":"Primary hardware error correction or detection method supported","type":"text","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"Maximum capacity of array in gigabytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"memory_error_info_handle","description":"Handle, or instance number, associated with any error that was detected for the array","type":"text","hidden":false,"required":false,"index":false},{"name":"number_memory_devices","description":"Number of memory devices on array","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_device_mapped_addresses","description":"Data associated for address mapping of physical memory devices.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_device_handle","description":"Handle of the memory device structure associated with this structure","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_mapped_address_handle","description":"Handle of the memory array mapped address to which this device range is mapped to","type":"text","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","hidden":false,"required":false,"index":false},{"name":"partition_row_position","description":"Identifies the position of the referenced memory device in a row of the address partition","type":"integer","hidden":false,"required":false,"index":false},{"name":"interleave_position","description":"The position of the device in a interleave, i.e. 0 indicates non-interleave, 1 indicates 1st interleave, 2 indicates 2nd interleave, etc.","type":"integer","hidden":false,"required":false,"index":false},{"name":"interleave_data_depth","description":"The max number of consecutive rows from memory device that are accessed in a single interleave transfer; 0 indicates device is non-interleave","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_devices","description":"Physical memory device (type 17) information retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure in SMBIOS","type":"text","hidden":false,"required":false,"index":false},{"name":"array_handle","description":"The memory array that the device is attached to","type":"text","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Implementation form factor for this memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"total_width","description":"Total width, in bits, of this memory device, including any check or error-correction bits","type":"integer","hidden":false,"required":false,"index":false},{"name":"data_width","description":"Data width, in bits, of this memory device","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of memory device in Megabyte","type":"integer","hidden":false,"required":false,"index":false},{"name":"set","description":"Identifies if memory device is one of a set of devices. A value of 0 indicates no set affiliation.","type":"integer","hidden":false,"required":false,"index":false},{"name":"device_locator","description":"String number of the string that identifies the physically-labeled socket or board position where the memory device is located","type":"text","hidden":false,"required":false,"index":false},{"name":"bank_locator","description":"String number of the string that identifies the physically-labeled bank where the memory device is located","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_type","description":"Type of memory used","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_type_details","description":"Additional details for memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"max_speed","description":"Max speed of memory device in megatransfers per second (MT/s)","type":"integer","hidden":false,"required":false,"index":false},{"name":"configured_clock_speed","description":"Configured speed of memory device in megatransfers per second (MT/s)","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Manufacturer ID string","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Serial number of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"asset_tag","description":"Manufacturer specific asset tag of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"part_number","description":"Manufacturer specific serial number of memory device","type":"text","hidden":false,"required":false,"index":false},{"name":"min_voltage","description":"Minimum operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_voltage","description":"Maximum operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false},{"name":"configured_voltage","description":"Configured operating voltage of device in millivolts","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"memory_error_info","description":"Data associated with errors of a physical memory array.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","hidden":false,"required":false,"index":false},{"name":"error_type","description":"type of error associated with current error status for array or device","type":"text","hidden":false,"required":false,"index":false},{"name":"error_granularity","description":"Granularity to which the error can be resolved","type":"text","hidden":false,"required":false,"index":false},{"name":"error_operation","description":"Memory access operation that caused the error","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_syndrome","description":"Vendor specific ECC syndrome or CRC data associated with the erroneous access","type":"text","hidden":false,"required":false,"index":false},{"name":"memory_array_error_address","description":"32 bit physical address of the error based on the addressing of the bus to which the memory array is connected","type":"text","hidden":false,"required":false,"index":false},{"name":"device_error_address","description":"32 bit physical address of the error relative to the start of the failing memory address, in bytes","type":"text","hidden":false,"required":false,"index":false},{"name":"error_resolution","description":"Range, in bytes, within which this error can be determined, when an error address is given","type":"text","hidden":false,"required":false,"index":false}]},{"name":"memory_info","description":"Main memory information in bytes.","platforms":["linux"],"columns":[{"name":"memory_total","description":"Total amount of physical RAM, in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"memory_free","description":"The amount of physical RAM, in bytes, left unused by the system","type":"bigint","hidden":false,"required":false,"index":false},{"name":"buffers","description":"The amount of physical RAM, in bytes, used for file buffers","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cached","description":"The amount of physical RAM, in bytes, used as cache memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_cached","description":"The amount of swap, in bytes, used as cache memory","type":"bigint","hidden":false,"required":false,"index":false},{"name":"active","description":"The total amount of buffer or page cache memory, in bytes, that is in active use","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"The total amount of buffer or page cache memory, in bytes, that are free and available","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_total","description":"The total amount of swap available, in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_free","description":"The total amount of swap free, in bytes","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"memory_map","description":"OS memory region map.","platforms":["linux"],"columns":[{"name":"name","description":"Region name","type":"text","hidden":false,"required":false,"index":false},{"name":"start","description":"Start address of memory region","type":"text","hidden":false,"required":false,"index":false},{"name":"end","description":"End address of memory region","type":"text","hidden":false,"required":false,"index":false}]},{"name":"mounts","description":"System mounted devices and filesystems (not process specific).","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Mounted device","type":"text","hidden":false,"required":false,"index":false},{"name":"device_alias","description":"Mounted device alias","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Mounted device path","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Mounted device type","type":"text","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Block size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Mounted device used blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_free","description":"Mounted device free blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"blocks_available","description":"Mounted device available blocks","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Mounted device used inodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inodes_free","description":"Mounted device free inodes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flags","description":"Mounted device flags","type":"text","hidden":false,"required":false,"index":false}]},{"name":"msr","description":"Various pieces of data stored in the model specific register per processor. NOTE: the msr kernel module must be enabled, and osquery must be run as root.","platforms":["linux"],"columns":[{"name":"processor_number","description":"The processor number as reported in /proc/cpuinfo","type":"bigint","hidden":false,"required":false,"index":false},{"name":"turbo_disabled","description":"Whether the turbo feature is disabled.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"turbo_ratio_limit","description":"The turbo feature ratio limit.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"platform_info","description":"Platform information.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"perf_ctl","description":"Performance setting for the processor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"perf_status","description":"Performance status for the processor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"feature_control","description":"Bitfield controlling enabled features.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_power_limit","description":"Run Time Average Power Limiting power limit.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_energy_status","description":"Run Time Average Power Limiting energy status.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"rapl_power_units","description":"Run Time Average Power Limiting power units.","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"nfs_shares","description":"NFS shares exported by the host.","platforms":["darwin"],"columns":[{"name":"share","description":"Filesystem path to the share","type":"text","hidden":false,"required":false,"index":false},{"name":"options","description":"Options string set on the export share","type":"text","hidden":false,"required":false,"index":false},{"name":"readonly","description":"1 if the share is exported readonly else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"npm_packages","description":"Lists all npm packages in a directory or globally installed in a system.","platforms":["linux"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Package author name","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Module's package.json path","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"Node module's directory where this package is located","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"ntdomains","description":"Display basic NT domain information of a Windows machine.","platforms":["windows"],"columns":[{"name":"name","description":"The label by which the object is known.","type":"text","hidden":false,"required":false,"index":false},{"name":"client_site_name","description":"The name of the site where the domain controller is configured.","type":"text","hidden":false,"required":false,"index":false},{"name":"dc_site_name","description":"The name of the site where the domain controller is located.","type":"text","hidden":false,"required":false,"index":false},{"name":"dns_forest_name","description":"The name of the root of the DNS tree.","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_controller_address","description":"The IP Address of the discovered domain controller..","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_controller_name","description":"The name of the discovered domain controller.","type":"text","hidden":false,"required":false,"index":false},{"name":"domain_name","description":"The name of the domain.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"The current status of the domain object.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ntfs_acl_permissions","description":"Retrieve NTFS ACL permission information for files and directories.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the file or directory.","type":"text","hidden":false,"required":true,"index":false},{"name":"type","description":"Type of access mode for the access control entry.","type":"text","hidden":false,"required":false,"index":false},{"name":"principal","description":"User or group to which the ACE applies.","type":"text","hidden":false,"required":false,"index":false},{"name":"access","description":"Specific permissions that indicate the rights described by the ACE.","type":"text","hidden":false,"required":false,"index":false},{"name":"inherited_from","description":"The inheritance policy of the ACE.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ntfs_journal_events","description":"Track time/action changes to files specified in configuration data.","platforms":["windows"],"columns":[{"name":"action","description":"Change action (Write, Delete, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category that the event originated from","type":"text","hidden":false,"required":false,"index":false},{"name":"old_path","description":"Old path (renames only)","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path","type":"text","hidden":false,"required":false,"index":false},{"name":"record_timestamp","description":"Journal record timestamp","type":"text","hidden":false,"required":false,"index":false},{"name":"record_usn","description":"The update sequence number that identifies the journal record","type":"text","hidden":false,"required":false,"index":false},{"name":"node_ref_number","description":"The ordinal that associates a journal record with a filename","type":"text","hidden":false,"required":false,"index":false},{"name":"parent_ref_number","description":"The ordinal that associates a journal record with a filename's parent directory","type":"text","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"The drive letter identifying the source journal","type":"text","hidden":false,"required":false,"index":false},{"name":"file_attributes","description":"File attributes","type":"text","hidden":false,"required":false,"index":false},{"name":"partial","description":"Set to 1 if either path or old_path only contains the file or folder name","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"nvram","description":"Apple NVRAM variable listing.","platforms":["darwin"],"columns":[{"name":"name","description":"Variable name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type (CFData, CFString, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Raw variable data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"oem_strings","description":"OEM defined strings retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the Type 11 structure","type":"text","hidden":false,"required":false,"index":false},{"name":"number","description":"The string index of the structure","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the OEM string","type":"text","hidden":false,"required":false,"index":false}]},{"name":"office_mru","description":"View recently opened Office documents.","platforms":["windows"],"columns":[{"name":"application","description":"Associated Office application","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Office application version number","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File path","type":"text","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"Most recent opened time file was opened","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID","type":"text","hidden":false,"required":false,"index":false}]},{"name":"os_version","description":"A single row containing the operating system name and version.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Distribution or product name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Pretty, suitable for presentation, OS version","type":"text","hidden":false,"required":false,"index":false},{"name":"major","description":"Major release version","type":"integer","hidden":false,"required":false,"index":false},{"name":"minor","description":"Minor release version","type":"integer","hidden":false,"required":false,"index":false},{"name":"patch","description":"Optional patch release","type":"integer","hidden":false,"required":false,"index":false},{"name":"build","description":"Optional build-specific or variant string","type":"text","hidden":false,"required":false,"index":false},{"name":"platform","description":"OS Platform or ID","type":"text","hidden":false,"required":false,"index":false},{"name":"platform_like","description":"Closely related platforms","type":"text","hidden":false,"required":false,"index":false},{"name":"codename","description":"OS version codename","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"OS Architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"The install date of the OS.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"osquery_events","description":"Information about the event publishers and subscribers.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"Event publisher or subscriber name","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the associated publisher","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Either publisher or subscriber","type":"text","hidden":false,"required":false,"index":false},{"name":"subscriptions","description":"Number of subscriptions the publisher received or subscriber used","type":"integer","hidden":false,"required":false,"index":false},{"name":"events","description":"Number of events emitted or received since osquery started","type":"integer","hidden":false,"required":false,"index":false},{"name":"refreshes","description":"Publisher only: number of runloop restarts","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 if the publisher or subscriber is active else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_extensions","description":"List of active osquery extensions.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"uuid","description":"The transient ID assigned for communication","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension's name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension's version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk_version","description":"osquery SDK version used to build the extension","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the extension's Thrift connection or library path","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"SDK extension type: extension or module","type":"text","hidden":false,"required":false,"index":false}]},{"name":"osquery_flags","description":"Configurable flags that modify osquery's behavior.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"Flag name","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Flag type","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Flag description","type":"text","hidden":false,"required":false,"index":false},{"name":"default_value","description":"Flag default value","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Flag value","type":"text","hidden":false,"required":false,"index":false},{"name":"shell_only","description":"Is the flag shell only?","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_info","description":"Top level information about the running version of osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"pid","description":"Process (or thread/handle) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","hidden":false,"required":false,"index":false},{"name":"instance_id","description":"Unique, long-lived ID per instance of osquery","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"osquery toolkit version","type":"text","hidden":false,"required":false,"index":false},{"name":"config_hash","description":"Hash of the working configuration state","type":"text","hidden":false,"required":false,"index":false},{"name":"config_valid","description":"1 if the config was loaded and considered valid, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"extensions","description":"osquery extensions status","type":"text","hidden":false,"required":false,"index":false},{"name":"build_platform","description":"osquery toolkit build platform","type":"text","hidden":false,"required":false,"index":false},{"name":"build_distro","description":"osquery toolkit platform distribution name (os version)","type":"text","hidden":false,"required":false,"index":false},{"name":"start_time","description":"UNIX time in seconds when the process started","type":"integer","hidden":false,"required":false,"index":false},{"name":"watcher","description":"Process (or thread/handle) ID of optional watcher process","type":"integer","hidden":false,"required":false,"index":false},{"name":"platform_mask","description":"The osquery platform bitmask","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_packs","description":"Information about the current query packs that are loaded in osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"The given name for this query pack","type":"text","hidden":false,"required":false,"index":false},{"name":"platform","description":"Platforms this query is supported on","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Minimum osquery version that this query will run on","type":"text","hidden":false,"required":false,"index":false},{"name":"shard","description":"Shard restriction limit, 1-100, 0 meaning no restriction","type":"integer","hidden":false,"required":false,"index":false},{"name":"discovery_cache_hits","description":"The number of times that the discovery query used cached values since the last time the config was reloaded","type":"integer","hidden":false,"required":false,"index":false},{"name":"discovery_executions","description":"The number of times that the discovery queries have been executed since the last time the config was reloaded","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"Whether this pack is active (the version, platform and discovery queries match) yes=1, no=0.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_registry","description":"List the osquery registry plugins.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"registry","description":"Name of the osquery registry","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the plugin item","type":"text","hidden":false,"required":false,"index":false},{"name":"owner_uuid","description":"Extension route UUID (0 for core)","type":"integer","hidden":false,"required":false,"index":false},{"name":"internal","description":"1 If the plugin is internal else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If this plugin is active else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"osquery_schedule","description":"Information about the current queries that are scheduled in osquery.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"name","description":"The given name for this query","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"The exact query to run","type":"text","hidden":false,"required":false,"index":false},{"name":"interval","description":"The interval in seconds to run this query, not an exact interval","type":"integer","hidden":false,"required":false,"index":false},{"name":"executions","description":"Number of times the query was executed","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_executed","description":"UNIX time stamp in seconds of the last completed execution","type":"bigint","hidden":false,"required":false,"index":false},{"name":"denylisted","description":"1 if the query is denylisted else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"output_size","description":"Total number of bytes generated by the query","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wall_time","description":"Total wall time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"user_time","description":"Total user time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_time","description":"Total system time spent executing","type":"bigint","hidden":false,"required":false,"index":false},{"name":"average_memory","description":"Average private memory left after executing","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"package_bom","description":"OS X package bill of materials (BOM) file list.","platforms":["darwin"],"columns":[{"name":"filepath","description":"Package file or directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Expected user of file or directory","type":"integer","hidden":false,"required":false,"index":false},{"name":"gid","description":"Expected group of file or directory","type":"integer","hidden":false,"required":false,"index":false},{"name":"mode","description":"Expected permissions","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Timestamp the file was installed","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of package bom","type":"text","hidden":false,"required":true,"index":false}]},{"name":"package_install_history","description":"OS X package install history.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Label packageIdentifiers","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Label date as UNIX timestamp","type":"integer","hidden":false,"required":false,"index":false},{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package display version","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Install source: usually the installer process name","type":"text","hidden":false,"required":false,"index":false},{"name":"content_type","description":"Package content_type (optional)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"package_receipts","description":"OS X package receipt details.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Package domain identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"package_filename","description":"Filename of original .pkg file","type":"text","hidden":true,"required":false,"index":false},{"name":"version","description":"Installed package version","type":"text","hidden":false,"required":false,"index":false},{"name":"location","description":"Optional relative install path on volume","type":"text","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Timestamp of install time","type":"double","hidden":false,"required":false,"index":false},{"name":"installer_name","description":"Name of installer process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of receipt plist","type":"text","hidden":false,"required":false,"index":false}]},{"name":"patches","description":"Lists all the patches applied. Note: This does not include patches applied via MSI or downloaded from Windows Update (e.g. Service Packs).","platforms":["windows"],"columns":[{"name":"csname","description":"The name of the host the patch is installed on.","type":"text","hidden":false,"required":false,"index":false},{"name":"hotfix_id","description":"The KB ID of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"caption","description":"Short description of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Fuller description of the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"fix_comments","description":"Additional comments about the patch.","type":"text","hidden":false,"required":false,"index":false},{"name":"installed_by","description":"The system context in which the patch as installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the patch was installed. Lack of a value does not indicate that the patch was not installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"installed_on","description":"The date when the patch was installed.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"pci_devices","description":"PCI devices active on the host system.","platforms":["darwin","linux"],"columns":[{"name":"pci_slot","description":"PCI Device used slot","type":"text","hidden":false,"required":false,"index":false},{"name":"pci_class","description":"PCI Device class","type":"text","hidden":false,"required":false,"index":false},{"name":"driver","description":"PCI Device used driver","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor","description":"PCI Device vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded PCI Device vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"PCI Device model","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded PCI Device model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"pci_class_id","description":"PCI Device class ID in hex format","type":"text","hidden":true,"required":false,"index":false},{"name":"pci_subclass_id","description":"PCI Device subclass in hex format","type":"text","hidden":true,"required":false,"index":false},{"name":"pci_subclass","description":"PCI Device subclass","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_vendor_id","description":"Vendor ID of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_vendor","description":"Vendor of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_model_id","description":"Model ID of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false},{"name":"subsystem_model","description":"Device description of PCI device subsystem","type":"text","hidden":true,"required":false,"index":false}]},{"name":"physical_disk_performance","description":"Provides provides raw data from performance counters that monitor hard or fixed disk drives on the system.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the physical disk","type":"text","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_read","description":"Average number of bytes transferred from the disk during read operations","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_write","description":"Average number of bytes transferred to the disk during write operations","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_read_queue_length","description":"Average number of read requests that were queued for the selected disk during the sample interval","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_write_queue_length","description":"Average number of write requests that were queued for the selected disk during the sample interval","type":"bigint","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_read","description":"Average time, in seconds, of a read operation of data from the disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_write","description":"Average time, in seconds, of a write operation of data to the disk","type":"integer","hidden":false,"required":false,"index":false},{"name":"current_disk_queue_length","description":"Number of requests outstanding on the disk at the time the performance data is collected","type":"integer","hidden":false,"required":false,"index":false},{"name":"percent_disk_read_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_disk_write_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing write requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_disk_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read or write requests","type":"bigint","hidden":false,"required":false,"index":false},{"name":"percent_idle_time","description":"Percentage of time during the sample interval that the disk was idle","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"pipes","description":"Named and Anonymous pipes.","platforms":["windows"],"columns":[{"name":"pid","description":"Process ID of the process to which the pipe belongs","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the pipe","type":"text","hidden":false,"required":false,"index":false},{"name":"instances","description":"Number of instances of the named pipe","type":"integer","hidden":false,"required":false,"index":false},{"name":"max_instances","description":"The maximum number of instances creatable for this pipe","type":"integer","hidden":false,"required":false,"index":false},{"name":"flags","description":"The flags indicating whether this pipe connection is a server or client end, and if the pipe for sending messages or bytes","type":"text","hidden":false,"required":false,"index":false}]},{"name":"pkg_packages","description":"pkgng packages that are currently installed on the host system.","platforms":["freebsd"],"columns":[{"name":"name","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"flatsize","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","hidden":false,"required":false,"index":false}]},{"name":"platform_info","description":"Information about EFI/UEFI/ROM and platform/boot.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"vendor","description":"Platform code vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Platform code version","type":"text","hidden":false,"required":false,"index":false},{"name":"date","description":"Self-reported platform code update date","type":"text","hidden":false,"required":false,"index":false},{"name":"revision","description":"BIOS major and minor revision","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"Relative address of firmware mapping","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes of firmware","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_size","description":"(Optional) size of firmware volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"extra","description":"Platform-specific additional information","type":"text","hidden":false,"required":false,"index":false}]},{"name":"plist","description":"Read and parse a plist file.","platforms":["darwin"],"columns":[{"name":"key","description":"Preference top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intermediate key path, includes lists/dicts","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"(required) read preferences from a plist","type":"text","hidden":false,"required":true,"index":false}]},{"name":"portage_keywords","description":"A summary about portage configurations like keywords, mask and unmask.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","hidden":false,"required":false,"index":false},{"name":"keyword","description":"The keyword applied to the package","type":"text","hidden":false,"required":false,"index":false},{"name":"mask","description":"If the package is masked","type":"integer","hidden":false,"required":false,"index":false},{"name":"unmask","description":"If the package is unmasked","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"portage_packages","description":"List of currently installed packages.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","hidden":false,"required":false,"index":false},{"name":"slot","description":"The slot used by package","type":"text","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Unix time when package was built","type":"bigint","hidden":false,"required":false,"index":false},{"name":"repository","description":"From which repository the ebuild was used","type":"text","hidden":false,"required":false,"index":false},{"name":"eapi","description":"The eapi for the ebuild","type":"bigint","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the package","type":"bigint","hidden":false,"required":false,"index":false},{"name":"world","description":"If package is in the world file","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"portage_use","description":"List of enabled portage USE values for specific package.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"The version of the installed package","type":"text","hidden":false,"required":false,"index":false},{"name":"use","description":"USE flag which has been enabled for package","type":"text","hidden":false,"required":false,"index":false}]},{"name":"power_sensors","description":"Machine power (currents, voltages, wattages, etc) sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on OS X","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The sensor category: currents, voltage, wattage","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of power source","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Power in Watts","type":"text","hidden":false,"required":false,"index":false}]},{"name":"powershell_events","description":"Powershell script blocks reconstructed to their full script content, this table requires script block logging to be enabled.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received by the osquery event publisher","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the Powershell script event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"script_block_id","description":"The unique GUID of the powershell script to which this block belongs","type":"text","hidden":false,"required":false,"index":false},{"name":"script_block_count","description":"The total number of script blocks for this script","type":"integer","hidden":false,"required":false,"index":false},{"name":"script_text","description":"The text content of the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"script_name","description":"The name of the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"script_path","description":"The path for the Powershell script","type":"text","hidden":false,"required":false,"index":false},{"name":"cosine_similarity","description":"How similar the Powershell script is to a provided 'normal' character frequency","type":"double","hidden":false,"required":false,"index":false}]},{"name":"preferences","description":"OS X defaults and managed preferences.","platforms":["darwin"],"columns":[{"name":"domain","description":"Application ID usually in com.name.product format","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Preference top-level key","type":"text","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intemediate key path, includes lists/dicts","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","hidden":false,"required":false,"index":false},{"name":"forced","description":"1 if the value is forced/managed, else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"username","description":"(optional) read preferences for a specific user","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"'current' or 'any' host, where 'current' takes precedence","type":"text","hidden":false,"required":false,"index":false}]},{"name":"prefetch","description":"Prefetch files show metadata related to file execution.","platforms":["windows"],"columns":[{"name":"path","description":"Prefetch file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Executable filename.","type":"text","hidden":false,"required":false,"index":false},{"name":"hash","description":"Prefetch CRC hash.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Most recent time application was run.","type":"integer","hidden":false,"required":false,"index":false},{"name":"other_run_times","description":"Other execution times in prefetch file.","type":"text","hidden":false,"required":false,"index":false},{"name":"run_count","description":"Number of times the application has been run.","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Application file size.","type":"integer","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_creation","description":"Volume creation time.","type":"text","hidden":false,"required":false,"index":false},{"name":"accessed_files_count","description":"Number of files accessed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"accessed_directories_count","description":"Number of directories accessed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"accessed_files","description":"Files accessed by application within ten seconds of launch.","type":"text","hidden":false,"required":false,"index":false},{"name":"accessed_directories","description":"Directories accessed by application within ten seconds of launch.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_envs","description":"A key/value table of environment variables for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"key","description":"Environment variable name","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_events","description":"Track time/action process executions.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"File mode permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline_size","description":"Actual size (bytes) of command line arguments","type":"bigint","hidden":true,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","hidden":true,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","hidden":true,"required":false,"index":false},{"name":"env_size","description":"Actual size (bytes) of environment list","type":"bigint","hidden":true,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID at process start","type":"bigint","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"File owner user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"owner_gid","description":"File owner group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"File last access in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mtime","description":"File modification in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"File last metadata change in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"btime","description":"File creation in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"overflows","description":"List of structures that overflowed","type":"text","hidden":true,"required":false,"index":false},{"name":"parent","description":"Process parent's PID, or -1 if cannot be determined.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"status","description":"OpenBSM Attribute: Status of the process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"suid","description":"Saved user ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"sgid","description":"Saved group ID at process start","type":"bigint","hidden":true,"required":false,"index":false},{"name":"syscall","description":"Syscall name: fork, vfork, clone, execve, execveat","type":"text","hidden":true,"required":false,"index":false}]},{"name":"process_file_events","description":"A File Integrity Monitor implementation using the audit service.","platforms":["linux"],"columns":[{"name":"operation","description":"Operation type","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ppid","description":"Parent process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"executable","description":"The executable path","type":"text","hidden":false,"required":false,"index":false},{"name":"partial","description":"True if this is a partial event (i.e.: this process existed before we started osquery)","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The current working directory of the process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"The path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"dest_path","description":"The canonical path associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"The uid of the process performing the action","type":"text","hidden":false,"required":false,"index":false},{"name":"gid","description":"The gid of the process performing the action","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID of the process using the file","type":"text","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"process_memory_map","description":"Process memory mapped files and pseudo device/regions.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"start","description":"Virtual start address (hex)","type":"text","hidden":false,"required":false,"index":false},{"name":"end","description":"Virtual end address (hex)","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"r=read, w=write, x=execute, p=private (cow)","type":"text","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset into mapped path","type":"bigint","hidden":false,"required":false,"index":false},{"name":"device","description":"MA:MI Major/minor device ID","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Mapped path inode, 0 means uninitialized (BSS)","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to mapped file or mapped type","type":"text","hidden":false,"required":false,"index":false},{"name":"pseudo","description":"1 If path is a pseudo path, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"process_namespaces","description":"Linux namespaces for processes running on the host system.","platforms":["linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"ipc_namespace","description":"ipc namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"mnt_namespace","description":"mnt namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"net namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_namespace","description":"pid namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"user_namespace","description":"user namespace inode","type":"text","hidden":false,"required":false,"index":false},{"name":"uts_namespace","description":"uts namespace inode","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_files","description":"File descriptors for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fd","description":"Process-specific file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Filesystem path of descriptor","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_pipes","description":"Pipes and partner processes for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"fd","description":"File descriptor","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mode","description":"Pipe open mode (r/w)","type":"text","hidden":false,"required":false,"index":false},{"name":"inode","description":"Pipe inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"type","description":"Pipe Type: named vs unnamed/anonymous","type":"text","hidden":false,"required":false,"index":false},{"name":"partner_pid","description":"Process ID of partner process sharing a particular pipe","type":"bigint","hidden":false,"required":false,"index":false},{"name":"partner_fd","description":"File descriptor of shared pipe at partner's end","type":"bigint","hidden":false,"required":false,"index":false},{"name":"partner_mode","description":"Mode of shared pipe at partner's end","type":"text","hidden":false,"required":false,"index":false}]},{"name":"process_open_sockets","description":"Processes which have open network sockets on the system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Socket local address","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Socket remote address","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Socket local port","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Socket remote port","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"For UNIX sockets (family=AF_UNIX), the domain path","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"TCP socket state","type":"text","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","hidden":true,"required":false,"index":false}]},{"name":"processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"protection_type","description":"The protection type of the process","type":"text","hidden":true,"required":false,"index":false},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"programs","description":"Represents products as they are installed by Windows Installer. A product generally correlates to one installation package on Windows. Some fields may be blank as Windows installation details are left to the discretion of the product author.","platforms":["windows"],"columns":[{"name":"name","description":"Commonly used product name.","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Product version information.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_location","description":"The installation location directory of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_source","description":"The installation source of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"language","description":"The language of the product.","type":"text","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the product supplier.","type":"text","hidden":false,"required":false,"index":false},{"name":"uninstall_string","description":"Path and filename of the uninstaller.","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Date that this product was installed on the system. ","type":"text","hidden":false,"required":false,"index":false},{"name":"identifying_number","description":"Product identification such as a serial number on software, or a die number on a hardware chip.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"prometheus_metrics","description":"Retrieve metrics from a Prometheus server.","platforms":["darwin","linux"],"columns":[{"name":"target_name","description":"Address of prometheus target","type":"text","hidden":false,"required":false,"index":false},{"name":"metric_name","description":"Name of collected Prometheus metric","type":"text","hidden":false,"required":false,"index":false},{"name":"metric_value","description":"Value of collected Prometheus metric","type":"double","hidden":false,"required":false,"index":false},{"name":"timestamp_ms","description":"Unix timestamp of collected data in MS","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"python_packages","description":"Python packages installed in a system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Package display name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where Python modules are located","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"quicklook_cache","description":"Files and thumbnails within OS X's Quicklook Cache.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of file","type":"text","hidden":false,"required":false,"index":false},{"name":"rowid","description":"Quicklook file rowid key","type":"integer","hidden":false,"required":false,"index":false},{"name":"fs_id","description":"Quicklook file fs_id key","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_id","description":"Parsed volume ID from fs_id","type":"integer","hidden":false,"required":false,"index":false},{"name":"inode","description":"Parsed file ID (inode) from fs_id","type":"integer","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Parsed version date field","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Parsed version size field","type":"bigint","hidden":false,"required":false,"index":false},{"name":"label","description":"Parsed version 'gen' field","type":"text","hidden":false,"required":false,"index":false},{"name":"last_hit_date","description":"Apple date format for last thumbnail cache hit","type":"integer","hidden":false,"required":false,"index":false},{"name":"hit_count","description":"Number of cache hits on thumbnail","type":"text","hidden":false,"required":false,"index":false},{"name":"icon_mode","description":"Thumbnail icon mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cache_path","description":"Path to cache data","type":"text","hidden":false,"required":false,"index":false}]},{"name":"registry","description":"All of the Windows registry hives.","platforms":["windows"],"columns":[{"name":"key","description":"Name of the key to search for","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Full path to the value","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the registry value entry","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the registry value, or 'subkey' if item is a subkey","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data content of registry value","type":"text","hidden":false,"required":false,"index":false},{"name":"mtime","description":"timestamp of the most recent registry write","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"routes","description":"The active route table for the host system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"destination","description":"Destination IP address","type":"text","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Netmask length","type":"integer","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Route gateway","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Route source","type":"text","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags to describe route","type":"integer","hidden":false,"required":false,"index":false},{"name":"interface","description":"Route local interface","type":"text","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Maximum Transmission Unit for the route","type":"integer","hidden":false,"required":false,"index":false},{"name":"metric","description":"Cost of route. Lowest is preferred","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of route","type":"text","hidden":false,"required":false,"index":false},{"name":"hopcount","description":"Max hops expected","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"rpm_package_files","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"package","description":"RPM package name","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"File path within the package","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"File default username from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"File default groupname from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"File permissions mode from info DB","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size in bytes from RPM info DB","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 file digest from RPM info DB","type":"text","hidden":false,"required":false,"index":false}]},{"name":"rpm_packages","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"name","description":"RPM package name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","hidden":false,"required":false,"index":false},{"name":"release","description":"Package release","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source RPM package name (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the package contents","type":"text","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","hidden":false,"required":false,"index":false},{"name":"epoch","description":"Package epoch value","type":"integer","hidden":false,"required":false,"index":false},{"name":"install_time","description":"When the package was installed","type":"integer","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Package vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"package_group","description":"Package group","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","hidden":true,"required":false,"index":false}]},{"name":"running_apps","description":"macOS applications currently running on the host system.","platforms":["darwin"],"columns":[{"name":"pid","description":"The pid of the application","type":"integer","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"The bundle identifier of the application","type":"text","hidden":false,"required":false,"index":false},{"name":"is_active","description":"1 if the application is in focus, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"safari_extensions","description":"Safari browser extension details for all users.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the extension","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension display name","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension long version","type":"text","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Bundle SDK used to compile extension","type":"text","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Optional developer identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional extension description text","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension XAR bundle","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sandboxes","description":"OS X application sandboxes container details.","platforms":["darwin"],"columns":[{"name":"label","description":"UTI-format bundle or label ID","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"Sandbox owner","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Application sandboxings enabled on container","type":"integer","hidden":false,"required":false,"index":false},{"name":"build_id","description":"Sandbox-specific identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"Application bundle used by the sandbox","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to sandbox container directory","type":"text","hidden":false,"required":false,"index":false}]},{"name":"scheduled_tasks","description":"Lists all of the tasks in the Windows task scheduler.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Actions executed by the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the executable to be run","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether or not the scheduled task is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the scheduled task","type":"text","hidden":false,"required":false,"index":false},{"name":"hidden","description":"Whether or not the task is visible in the UI","type":"integer","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Timestamp the task last ran","type":"bigint","hidden":false,"required":false,"index":false},{"name":"next_run_time","description":"Timestamp the task is scheduled to run next","type":"bigint","hidden":false,"required":false,"index":false},{"name":"last_run_message","description":"Exit status message of the last task run","type":"text","hidden":false,"required":false,"index":false},{"name":"last_run_code","description":"Exit status code of the last task run","type":"text","hidden":false,"required":false,"index":false}]},{"name":"screenlock","description":"macOS screenlock status for the current logged in user context.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 If a password is required after sleep or the screensaver begins; else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"grace_period","description":"The amount of time in seconds the screen must be asleep or the screensaver on before a password is required on-wake. 0 = immediately; -1 = no password is required on-wake","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"seccomp_events","description":"A virtual table that tracks seccomp events.","platforms":["linux"],"columns":[{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID (loginuid) of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the user who started the analyzed process","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"ses","description":"Session ID of the session from which the analyzed process was invoked","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"exe","description":"The path to the executable that was used to invoke the analyzed process","type":"text","hidden":false,"required":false,"index":false},{"name":"sig","description":"Signal value sent to process by seccomp","type":"bigint","hidden":false,"required":false,"index":false},{"name":"arch","description":"Information about the CPU architecture","type":"text","hidden":false,"required":false,"index":false},{"name":"syscall","description":"Type of the system call","type":"text","hidden":false,"required":false,"index":false},{"name":"compat","description":"Is system call in compatibility mode","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ip","description":"Instruction pointer value","type":"text","hidden":false,"required":false,"index":false},{"name":"code","description":"The seccomp action","type":"text","hidden":false,"required":false,"index":false}]},{"name":"secureboot","description":"Secure Boot UEFI Settings.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"secure_boot","description":"Whether secure boot is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"setup_mode","description":"Whether setup mode is enabled","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"selinux_events","description":"Track SELinux events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"Message","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"selinux_settings","description":"Track active SELinux settings.","platforms":["linux"],"columns":[{"name":"scope","description":"Where the key is located inside the SELinuxFS mount point.","type":"text","hidden":false,"required":false,"index":false},{"name":"key","description":"Key or class name.","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Active value.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"services","description":"Lists all installed Windows services and their relevant data.","platforms":["windows"],"columns":[{"name":"name","description":"Service name","type":"text","hidden":false,"required":false,"index":false},{"name":"service_type","description":"Service Type: OWN_PROCESS, SHARE_PROCESS and maybe Interactive (can interact with the desktop)","type":"text","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Service Display name","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Service Current status: STOPPED, START_PENDING, STOP_PENDING, RUNNING, CONTINUE_PENDING, PAUSE_PENDING, PAUSED","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"the Process ID of the service","type":"integer","hidden":false,"required":false,"index":false},{"name":"start_type","description":"Service start type: BOOT_START, SYSTEM_START, AUTO_START, DEMAND_START, DISABLED","type":"text","hidden":false,"required":false,"index":false},{"name":"win32_exit_code","description":"The error code that the service uses to report an error that occurs when it is starting or stopping","type":"integer","hidden":false,"required":false,"index":false},{"name":"service_exit_code","description":"The service-specific error code that the service returns when an error occurs while the service is starting or stopping","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Service Executable","type":"text","hidden":false,"required":false,"index":false},{"name":"module_path","description":"Path to ServiceDll","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Service Description","type":"text","hidden":false,"required":false,"index":false},{"name":"user_account","description":"The name of the account that the service process will be logged on as when it runs. This name can be of the form Domain\\UserName. If the account belongs to the built-in domain, the name can be of the form .\\UserName.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shadow","description":"Local system users encrypted passwords and related information. Please note, that you usually need superuser rights to access `/etc/shadow`.","platforms":["linux"],"columns":[{"name":"password_status","description":"Password status","type":"text","hidden":false,"required":false,"index":false},{"name":"hash_alg","description":"Password hashing algorithm","type":"text","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Date of last password change (starting from UNIX epoch date)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimal number of days between password changes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum number of days between password changes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"warning","description":"Number of days before password expires to warn user about it","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Number of days after password expires until account is blocked","type":"bigint","hidden":false,"required":false,"index":false},{"name":"expire","description":"Number of days since UNIX epoch date until account is disabled","type":"bigint","hidden":false,"required":false,"index":false},{"name":"flag","description":"Reserved","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shared_folders","description":"Folders available to others via SMB or AFP.","platforms":["darwin"],"columns":[{"name":"name","description":"The shared name of the folder as it appears to other users","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute path of shared folder on the local system","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shared_memory","description":"OS shared memory regions.","platforms":["linux"],"columns":[{"name":"shmid","description":"Shared memory segment ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"User ID of owning process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creator_uid","description":"User ID of creator process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID to last use the segment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"creator_pid","description":"Process ID that created the segment","type":"bigint","hidden":false,"required":false,"index":false},{"name":"atime","description":"Attached time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"dtime","description":"Detached time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Changed time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Memory segment permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"attached","description":"Number of attached processes","type":"integer","hidden":false,"required":false,"index":false},{"name":"status","description":"Destination/attach status","type":"text","hidden":false,"required":false,"index":false},{"name":"locked","description":"1 if segment is locked else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shared_resources","description":"Displays shared resources on a computer system running Windows. This may be a disk drive, printer, interprocess communication, or other sharable device.","platforms":["windows"],"columns":[{"name":"description","description":"A textual description of the object","type":"text","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the object was installed. Lack of a value does not indicate that the object is not installed.","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"String that indicates the current status of the object.","type":"text","hidden":false,"required":false,"index":false},{"name":"allow_maximum","description":"Number of concurrent users for this resource has been limited. If True, the value in the MaximumAllowed property is ignored.","type":"integer","hidden":false,"required":false,"index":false},{"name":"maximum_allowed","description":"Limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum property is set to FALSE.","type":"integer","hidden":false,"required":false,"index":false},{"name":"name","description":"Alias given to a path set up as a share on a computer system running Windows.","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Local path of the Windows share.","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of resource being shared. Types include: disk drives, print queues, interprocess communications (IPC), and general devices.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"sharing_preferences","description":"OS X Sharing preferences.","platforms":["darwin"],"columns":[{"name":"screen_sharing","description":"1 If screen sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"file_sharing","description":"1 If file sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"printer_sharing","description":"1 If printer sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_login","description":"1 If remote login is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_management","description":"1 If remote management is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_apple_events","description":"1 If remote apple events are enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"internet_sharing","description":"1 If internet sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"bluetooth_sharing","description":"1 If bluetooth sharing is enabled for any user else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"disc_sharing","description":"1 If CD or DVD sharing is enabled else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"content_caching","description":"1 If content caching is enabled else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shell_history","description":"A line-delimited (command) table of per-user .*_history data.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"Shell history owner","type":"bigint","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp. It could be absent, default value is 0.","type":"integer","hidden":false,"required":false,"index":false},{"name":"command","description":"Unparsed date/line/command history line","type":"text","hidden":false,"required":false,"index":false},{"name":"history_file","description":"Path to the .*_history for this user","type":"text","hidden":false,"required":false,"index":false}]},{"name":"shellbags","description":"Shows directories accessed via Windows Explorer.","platforms":["windows"],"columns":[{"name":"sid","description":"User SID","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Shellbags source Registry file","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Directory name.","type":"text","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Directory Modified time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"created_time","description":"Directory Created time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"accessed_time","description":"Directory Accessed time.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Directory master file table entry.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Directory master file table sequence.","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shimcache","description":"Application Compatibility Cache, contains artifacts of execution.","platforms":["windows"],"columns":[{"name":"entry","description":"Execution order.","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the executed file.","type":"text","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"File Modified time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"execution_flag","description":"Boolean Execution flag, 1 for execution, 0 for no execution, -1 for missing (this flag does not exist on Windows 10 and higher).","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"shortcut_files","description":"View data about Windows Shortcut files.","platforms":["windows"],"columns":[{"name":"path","description":"Directory name.","type":"text","hidden":false,"required":true,"index":false},{"name":"target_path","description":"Target file path","type":"text","hidden":false,"required":false,"index":false},{"name":"target_modified","description":"Target Modified time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_created","description":"Target Created time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_accessed","description":"Target Accessed time.","type":"integer","hidden":false,"required":false,"index":false},{"name":"target_size","description":"Size of target file.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to target file from lnk file.","type":"text","hidden":false,"required":false,"index":false},{"name":"local_path","description":"Local system path to target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"working_path","description":"Target file directory.","type":"text","hidden":false,"required":false,"index":false},{"name":"icon_path","description":"Lnk file icon location.","type":"text","hidden":false,"required":false,"index":false},{"name":"common_path","description":"Common system path to target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"command_args","description":"Command args passed to lnk file.","type":"text","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Optional hostname of the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"share_name","description":"Share name of the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device containing the target file.","type":"text","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Target mft entry.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Target mft sequence.","type":"integer","hidden":false,"required":false,"index":false},{"name":"description","description":"Lnk file description.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"signature","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["darwin"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","hidden":false,"required":true,"index":false},{"name":"hash_resources","description":"Set to 1 to also hash resources, or 0 otherwise. Default is 1","type":"integer","hidden":false,"required":false,"index":false},{"name":"arch","description":"If applicable, the arch of the signed code","type":"text","hidden":false,"required":false,"index":false},{"name":"signed","description":"1 If the file is signed else 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"identifier","description":"The signing identifier sealed into the signature","type":"text","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Hash of the application Code Directory","type":"text","hidden":false,"required":false,"index":false},{"name":"team_identifier","description":"The team signing identifier sealed into the signature","type":"text","hidden":false,"required":false,"index":false},{"name":"authority","description":"Certificate Common Name","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sip_config","description":"Apple's System Integrity Protection (rootless) status.","platforms":["darwin"],"columns":[{"name":"config_flag","description":"The System Integrity Protection config flag","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this configuration is enabled, otherwise 0","type":"integer","hidden":false,"required":false,"index":false},{"name":"enabled_nvram","description":"1 if this configuration is enabled, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"smart_drive_info","description":"Drive information read by SMART controller utilizing autodetect.","platforms":["darwin","linux"],"columns":[{"name":"device_name","description":"Name of block device","type":"text","hidden":false,"required":false,"index":false},{"name":"disk_id","description":"Physical slot number of device, only exists when hardware storage controller exists","type":"integer","hidden":false,"required":false,"index":false},{"name":"driver_type","description":"The explicit device type used to retrieve the SMART information","type":"text","hidden":false,"required":false,"index":false},{"name":"model_family","description":"Drive model family","type":"text","hidden":false,"required":false,"index":false},{"name":"device_model","description":"Device Model","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Device serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"lu_wwn_device_id","description":"Device Identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"additional_product_id","description":"An additional drive identifier if any","type":"text","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"Drive firmware version","type":"text","hidden":false,"required":false,"index":false},{"name":"user_capacity","description":"Bytes of drive capacity","type":"text","hidden":false,"required":false,"index":false},{"name":"sector_sizes","description":"Bytes of drive sector sizes","type":"text","hidden":false,"required":false,"index":false},{"name":"rotation_rate","description":"Drive RPM","type":"text","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Form factor if reported","type":"text","hidden":false,"required":false,"index":false},{"name":"in_smartctl_db","description":"Boolean value for if drive is recognized","type":"integer","hidden":false,"required":false,"index":false},{"name":"ata_version","description":"ATA version of drive","type":"text","hidden":false,"required":false,"index":false},{"name":"transport_type","description":"Drive transport type","type":"text","hidden":false,"required":false,"index":false},{"name":"sata_version","description":"SATA version, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"read_device_identity_failure","description":"Error string for device id read, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"smart_supported","description":"SMART support status","type":"text","hidden":false,"required":false,"index":false},{"name":"smart_enabled","description":"SMART enabled status","type":"text","hidden":false,"required":false,"index":false},{"name":"packet_device_type","description":"Packet device type","type":"text","hidden":false,"required":false,"index":false},{"name":"power_mode","description":"Device power mode","type":"text","hidden":false,"required":false,"index":false},{"name":"warnings","description":"Warning messages from SMART controller","type":"text","hidden":false,"required":false,"index":false}]},{"name":"smbios_tables","description":"BIOS (DMI) structure common details and content.","platforms":["darwin","linux"],"columns":[{"name":"number","description":"Table entry number","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Table entry type","type":"integer","hidden":false,"required":false,"index":false},{"name":"description","description":"Table entry description","type":"text","hidden":false,"required":false,"index":false},{"name":"handle","description":"Table entry handle","type":"integer","hidden":false,"required":false,"index":false},{"name":"header_size","description":"Header size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"size","description":"Table entry size in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table entry","type":"text","hidden":false,"required":false,"index":false}]},{"name":"smc_keys","description":"Apple's system management controller keys.","platforms":["darwin"],"columns":[{"name":"key","description":"4-character key","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"SMC-reported type literal type","type":"text","hidden":false,"required":false,"index":false},{"name":"size","description":"Reported size of data in bytes","type":"integer","hidden":false,"required":false,"index":false},{"name":"value","description":"A type-encoded representation of the key value","type":"text","hidden":false,"required":false,"index":false},{"name":"hidden","description":"1 if this key is normally hidden, otherwise 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"socket_events","description":"Track network socket opens and closes.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"The socket action (bind, listen, close)","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"status","description":"Either 'succeeded', 'failed', 'in_progress' (connect() on non-blocking socket) or 'no_client' (null accept() on non-blocking socket)","type":"text","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","hidden":true,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","hidden":false,"required":false,"index":false},{"name":"socket","description":"The local path (UNIX domain socket only)","type":"text","hidden":true,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false},{"name":"success","description":"Deprecated. Use the 'status' column instead","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"ssh_configs","description":"A table of parsed ssh_configs.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local owner of the ssh_config file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"block","description":"The host or match block","type":"text","hidden":false,"required":false,"index":false},{"name":"option","description":"The option and value","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_config_file","description":"Path to the ssh_config file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"startup_items","description":"Applications and binaries set as user/login startup items.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"name","description":"Name of startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"args","description":"Arguments provided to startup executable","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Startup Item or Login Item","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Directory or plist containing startup item","type":"text","hidden":false,"required":false,"index":false},{"name":"status","description":"Startup status; either enabled or disabled","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"The user associated with the startup item","type":"text","hidden":false,"required":false,"index":false}]},{"name":"sudoers","description":"Rules for running commands as other users via sudo.","platforms":["darwin","linux"],"columns":[{"name":"source","description":"Source file containing the given rule","type":"text","hidden":false,"required":false,"index":false},{"name":"header","description":"Symbol for given rule","type":"text","hidden":false,"required":false,"index":false},{"name":"rule_details","description":"Rule definition","type":"text","hidden":false,"required":false,"index":false}]},{"name":"suid_bin","description":"suid binaries in common locations.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Binary path","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Binary owner username","type":"text","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Binary owner group","type":"text","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Binary permissions","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"syslog_events","description":"","platforms":["linux"],"columns":[{"name":"time","description":"Current unix epoch time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Time known to syslog","type":"text","hidden":false,"required":false,"index":false},{"name":"host","description":"Hostname configured for syslog","type":"text","hidden":false,"required":false,"index":false},{"name":"severity","description":"Syslog severity","type":"integer","hidden":false,"required":false,"index":false},{"name":"facility","description":"Syslog facility","type":"text","hidden":false,"required":false,"index":false},{"name":"tag","description":"The syslog tag","type":"text","hidden":false,"required":false,"index":false},{"name":"message","description":"The syslog message","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"system_controls","description":"sysctl names, values, and settings information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Full sysctl MIB name","type":"text","hidden":false,"required":false,"index":false},{"name":"oid","description":"Control MIB","type":"text","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"Subsystem ID, control type","type":"text","hidden":false,"required":false,"index":false},{"name":"current_value","description":"Value of setting","type":"text","hidden":false,"required":false,"index":false},{"name":"config_value","description":"The MIB value set in /etc/sysctl.conf","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type","type":"text","hidden":false,"required":false,"index":false},{"name":"field_name","description":"Specific attribute of opaque type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"system_extensions","description":"macOS (>= 10.15) system extension table.","platforms":["darwin"],"columns":[{"name":"path","description":"Original path of system extension","type":"text","hidden":false,"required":false,"index":false},{"name":"UUID","description":"Extension unique id","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"System extension state","type":"text","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier name","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"System extension version","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"System extension category","type":"text","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"System extension bundle path","type":"text","hidden":false,"required":false,"index":false},{"name":"team","description":"Signing team ID","type":"text","hidden":false,"required":false,"index":false},{"name":"mdm_managed","description":"1 if managed by MDM system extension payload configuration, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"system_info","description":"System information for identification.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"hostname","description":"Network hostname including domain","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"CPU type","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"CPU subtype","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_brand","description":"CPU brand string, contains vendor and model","type":"text","hidden":false,"required":false,"index":false},{"name":"cpu_physical_cores","description":"Number of physical CPU cores in to the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_logical_cores","description":"Number of logical CPU cores available to the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_microcode","description":"Microcode version","type":"text","hidden":false,"required":false,"index":false},{"name":"physical_memory","description":"Total physical memory in bytes","type":"bigint","hidden":false,"required":false,"index":false},{"name":"hardware_vendor","description":"Hardware vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hardware model","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_version","description":"Hardware version","type":"text","hidden":false,"required":false,"index":false},{"name":"hardware_serial","description":"Device serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"board_vendor","description":"Board vendor","type":"text","hidden":false,"required":false,"index":false},{"name":"board_model","description":"Board model","type":"text","hidden":false,"required":false,"index":false},{"name":"board_version","description":"Board version","type":"text","hidden":false,"required":false,"index":false},{"name":"board_serial","description":"Board serial number","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Friendly computer name (optional)","type":"text","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Local hostname (optional)","type":"text","hidden":false,"required":false,"index":false}]},{"name":"systemd_units","description":"Track systemd units.","platforms":["linux"],"columns":[{"name":"id","description":"Unique unit identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Unit description","type":"text","hidden":false,"required":false,"index":false},{"name":"load_state","description":"Reflects whether the unit definition was properly loaded","type":"text","hidden":false,"required":false,"index":false},{"name":"active_state","description":"The high-level unit activation state, i.e. generalization of SUB","type":"text","hidden":false,"required":false,"index":false},{"name":"sub_state","description":"The low-level unit activation state, values depend on unit type","type":"text","hidden":false,"required":false,"index":false},{"name":"following","description":"The name of another unit that this unit follows in state","type":"text","hidden":false,"required":false,"index":false},{"name":"object_path","description":"The object path for this unit","type":"text","hidden":false,"required":false,"index":false},{"name":"job_id","description":"Next queued job id","type":"bigint","hidden":false,"required":false,"index":false},{"name":"job_type","description":"Job type","type":"text","hidden":false,"required":false,"index":false},{"name":"job_path","description":"The object path for the job","type":"text","hidden":false,"required":false,"index":false},{"name":"fragment_path","description":"The unit file path this unit was read from, if there is any","type":"text","hidden":false,"required":false,"index":false},{"name":"user","description":"The configured user, if any","type":"text","hidden":false,"required":false,"index":false},{"name":"source_path","description":"Path to the (possibly generated) unit configuration file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"temperature_sensors","description":"Machine's temperature sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on OS X","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of temperature source","type":"text","hidden":false,"required":false,"index":false},{"name":"celsius","description":"Temperature in Celsius","type":"double","hidden":false,"required":false,"index":false},{"name":"fahrenheit","description":"Temperature in Fahrenheit","type":"double","hidden":false,"required":false,"index":false}]},{"name":"time","description":"Track current date and time in the system.","platforms":["darwin","linux","freebsd","windows"],"columns":[{"name":"weekday","description":"Current weekday in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"year","description":"Current year in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"month","description":"Current month in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"day","description":"Current day in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"hour","description":"Current hour in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Current minutes in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Current seconds in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"timezone","description":"Current timezone in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"local_time","description":"Current local UNIX time in the system","type":"integer","hidden":false,"required":false,"index":false},{"name":"local_timezone","description":"Current local timezone in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"unix_time","description":"Current UNIX time in the system, converted to UTC if --utc enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"timestamp","description":"Current timestamp (log format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Current date and time (ISO format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"iso_8601","description":"Current time (ISO format) in the system","type":"text","hidden":false,"required":false,"index":false},{"name":"win_timestamp","description":"Timestamp value in 100 nanosecond units.","type":"bigint","hidden":true,"required":false,"index":false}]},{"name":"time_machine_backups","description":"Backups to drives using TimeMachine.","platforms":["darwin"],"columns":[{"name":"destination_id","description":"Time Machine destination ID","type":"text","hidden":false,"required":false,"index":false},{"name":"backup_date","description":"Backup Date","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"time_machine_destinations","description":"Locations backed up to using Time Machine.","platforms":["darwin"],"columns":[{"name":"alias","description":"Human readable name of drive","type":"text","hidden":false,"required":false,"index":false},{"name":"destination_id","description":"Time Machine destination ID","type":"text","hidden":false,"required":false,"index":false},{"name":"consistency_scan_date","description":"Consistency scan date","type":"integer","hidden":false,"required":false,"index":false},{"name":"root_volume_uuid","description":"Root UUID of backup volume","type":"text","hidden":false,"required":false,"index":false},{"name":"bytes_available","description":"Bytes available on volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"bytes_used","description":"Bytes used on volume","type":"integer","hidden":false,"required":false,"index":false},{"name":"encryption","description":"Last known encrypted state","type":"text","hidden":false,"required":false,"index":false}]},{"name":"tpm_info","description":"A table that lists the TPM related information.","platforms":["windows"],"columns":[{"name":"activated","description":"TPM is activated","type":"integer","hidden":false,"required":false,"index":false},{"name":"enabled","description":"TPM is enabled","type":"integer","hidden":false,"required":false,"index":false},{"name":"owned","description":"TPM is ownned","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer_version","description":"TPM version","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer_id","description":"TPM manufacturers ID","type":"integer","hidden":false,"required":false,"index":false},{"name":"manufacturer_name","description":"TPM manufacturers name","type":"text","hidden":false,"required":false,"index":false},{"name":"product_name","description":"Product name of the TPM","type":"text","hidden":false,"required":false,"index":false},{"name":"physical_presence_version","description":"Version of the Physical Presence Interface","type":"text","hidden":false,"required":false,"index":false},{"name":"spec_version","description":"Trusted Computing Group specification that the TPM supports","type":"text","hidden":false,"required":false,"index":false}]},{"name":"ulimit_info","description":"System resource usage limits.","platforms":["darwin","linux"],"columns":[{"name":"type","description":"System resource to be limited","type":"text","hidden":false,"required":false,"index":false},{"name":"soft_limit","description":"Current limit value","type":"text","hidden":false,"required":false,"index":false},{"name":"hard_limit","description":"Maximum limit value","type":"text","hidden":false,"required":false,"index":false}]},{"name":"uptime","description":"Track time passed since last boot. Some systems track this as calendar time, some as runtime.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"days","description":"Days of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"hours","description":"Hours of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Minutes of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Seconds of uptime","type":"integer","hidden":false,"required":false,"index":false},{"name":"total_seconds","description":"Total uptime seconds","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"usb_devices","description":"USB devices that are actively plugged into the host system.","platforms":["darwin","linux"],"columns":[{"name":"usb_address","description":"USB Device used address","type":"integer","hidden":false,"required":false,"index":false},{"name":"usb_port","description":"USB Device used port","type":"integer","hidden":false,"required":false,"index":false},{"name":"vendor","description":"USB Device vendor string","type":"text","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded USB Device vendor identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"version","description":"USB Device version number","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"USB Device model string","type":"text","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded USB Device model identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"serial","description":"USB Device serial connection","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"USB Device class","type":"text","hidden":false,"required":false,"index":false},{"name":"subclass","description":"USB Device subclass","type":"text","hidden":false,"required":false,"index":false},{"name":"protocol","description":"USB Device protocol","type":"text","hidden":false,"required":false,"index":false},{"name":"removable","description":"1 If USB device is removable else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"user_events","description":"Track user events from the audit framework.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the event","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"The file description for the process socket","type":"integer","hidden":false,"required":false,"index":false},{"name":"path","description":"Supplied path from event","type":"text","hidden":false,"required":false,"index":false},{"name":"address","description":"The Internet protocol address or family ID","type":"text","hidden":false,"required":false,"index":false},{"name":"terminal","description":"The network protocol ID","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"user_groups","description":"Local system user group relationships.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"user_interaction_events","description":"Track user interaction events from macOS' event tapping framework.","platforms":["darwin"],"columns":[{"name":"time","description":"Time","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"user_ssh_keys","description":"Returns the private keys in the users ~/.ssh directory and whether or not they are encrypted.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"The local user that owns the key file","type":"bigint","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to key file","type":"text","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 if key is encrypted, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"key_type","description":"The type of the private key. One of [rsa, dsa, dh, ec, hmac, cmac], or the empty string.","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"userassist","description":"UserAssist Registry Key tracks when a user executes an application from Windows Explorer.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of times the application has been executed.","type":"integer","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"video_info","description":"Retrieve video card information of the machine.","platforms":["windows"],"columns":[{"name":"color_depth","description":"The amount of bits per pixel to represent color.","type":"integer","hidden":false,"required":false,"index":false},{"name":"driver","description":"The driver of the device.","type":"text","hidden":false,"required":false,"index":false},{"name":"driver_date","description":"The date listed on the installed driver.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"driver_version","description":"The version of the installed driver.","type":"text","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"series","description":"The series of the gpu.","type":"text","hidden":false,"required":false,"index":false},{"name":"video_mode","description":"The current resolution of the display.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"virtual_memory_info","description":"Darwin Virtual Memory statistics.","platforms":["darwin"],"columns":[{"name":"free","description":"Total number of free pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"active","description":"Total number of active pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Total number of inactive pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"speculative","description":"Total number of speculative pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"throttled","description":"Total number of throttled pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"wired","description":"Total number of wired down pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"purgeable","description":"Total number of purgeable pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"faults","description":"Total number of calls to vm_faults.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"copy","description":"Total number of copy-on-write pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"zero_fill","description":"Total number of zero filled pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"reactivated","description":"Total number of reactivated pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"purged","description":"Total number of purged pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"file_backed","description":"Total number of file backed pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"anonymous","description":"Total number of anonymous pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uncompressed","description":"Total number of uncompressed pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"compressor","description":"The number of pages used to store compressed VM pages.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"decompressed","description":"The total number of pages that have been decompressed by the VM compressor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"compressed","description":"The total number of pages that have been compressed by the VM compressor.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"page_ins","description":"The total number of requests for pages from a pager.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"page_outs","description":"Total number of pages paged out.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_ins","description":"The total number of compressed pages that have been swapped out to disk.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"swap_outs","description":"The total number of compressed pages that have been swapped back in from disk.","type":"bigint","hidden":false,"required":false,"index":false}]},{"name":"wifi_networks","description":"OS X known/remembered Wi-Fi networks list.","platforms":["darwin"],"columns":[{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","hidden":false,"required":false,"index":false},{"name":"last_connected","description":"Last time this netword was connected to as a unix_time","type":"integer","hidden":false,"required":false,"index":false},{"name":"passpoint","description":"1 if Passpoint is supported, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"possibly_hidden","description":"1 if network is possibly a hidden network, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"roaming","description":"1 if roaming is supported, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"roaming_profile","description":"Describe the roaming profile, usually one of Single, Dual or Multi","type":"text","hidden":false,"required":false,"index":false},{"name":"captive_portal","description":"1 if this network has a captive portal, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"auto_login","description":"1 if auto login is enabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"temporarily_disabled","description":"1 if this network is temporarily disabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 if this network is disabled, 0 otherwise","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"wifi_status","description":"OS X current WiFi status.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","hidden":false,"required":false,"index":false},{"name":"transmit_rate","description":"The current transmit rate","type":"text","hidden":false,"required":false,"index":false},{"name":"mode","description":"The current operating mode for the Wi-Fi interface","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wifi_survey","description":"Scan for nearby WiFi networks.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"winbaseobj","description":"Lists named Windows objects in the default object directories, across all terminal services sessions. Example Windows ojbect types include Mutexes, Events, Jobs and Semaphors.","platforms":["windows"],"columns":[{"name":"session_id","description":"Terminal Services Session Id","type":"integer","hidden":false,"required":false,"index":false},{"name":"object_name","description":"Object Name","type":"text","hidden":false,"required":false,"index":false},{"name":"object_type","description":"Object Type","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_crashes","description":"Extracted information from Windows crash logs (Minidumps).","platforms":["windows"],"columns":[{"name":"datetime","description":"Timestamp (log format) of the crash","type":"text","hidden":false,"required":false,"index":false},{"name":"module","description":"Path of the crashed module within the process","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the executable file for the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID of the crashed process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID of the crashed thread","type":"bigint","hidden":false,"required":false,"index":false},{"name":"version","description":"File version info of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"process_uptime","description":"Uptime of the process in seconds","type":"bigint","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Multiple stack frames from the stack trace","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_code","description":"The Windows exception code","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_message","description":"The NTSTATUS error message associated with the exception code","type":"text","hidden":false,"required":false,"index":false},{"name":"exception_address","description":"Address (in hex) where the exception occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"registers","description":"The values of the system registers","type":"text","hidden":false,"required":false,"index":false},{"name":"command_line","description":"Command-line string passed to the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"current_directory","description":"Current working directory of the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"username","description":"Username of the user who ran the crashed process","type":"text","hidden":false,"required":false,"index":false},{"name":"machine_name","description":"Name of the machine where the crash happened","type":"text","hidden":false,"required":false,"index":false},{"name":"major_version","description":"Windows major version of the machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"minor_version","description":"Windows minor version of the machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"build_number","description":"Windows build number of the crashing machine","type":"integer","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of crash log","type":"text","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Path of the log file","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_eventlog","description":"Table for querying all recorded Windows event logs.","platforms":["windows"],"columns":[{"name":"channel","description":"Source or channel of the event","type":"text","hidden":false,"required":true,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"level","description":"Severity level associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID which emitted the event record","type":"integer","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID which emitted the event record","type":"integer","hidden":false,"required":false,"index":false},{"name":"time_range","description":"System time to selectively filter the events","type":"text","hidden":true,"required":false,"index":false},{"name":"timestamp","description":"Timestamp to selectively filter the events","type":"text","hidden":true,"required":false,"index":false},{"name":"xpath","description":"The custom query to filter events","type":"text","hidden":true,"required":true,"index":false}]},{"name":"windows_events","description":"Windows Event logs.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received","type":"bigint","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","hidden":false,"required":false,"index":false},{"name":"source","description":"Source or channel of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"level","description":"The severity level associated with the event","type":"integer","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"windows_optional_features","description":"Lists names and installation states of windows features. Maps to Win32_OptionalFeature WMI class.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the feature","type":"text","hidden":false,"required":false,"index":false},{"name":"caption","description":"Caption of feature in settings UI","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Installation state value. 1 == Enabled, 2 == Disabled, 3 == Absent","type":"integer","hidden":false,"required":false,"index":false},{"name":"statename","description":"Installation state name. 'Enabled','Disabled','Absent'","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_security_center","description":"The health status of Window Security features. Health values can be \"Good\", \"Poor\". \"Snoozed\", \"Not Monitored\", and \"Error\".","platforms":["windows"],"columns":[{"name":"firewall","description":"The health of the monitored Firewall (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"The health of the Windows Autoupdate feature","type":"text","hidden":false,"required":false,"index":false},{"name":"antivirus","description":"The health of the monitored Antivirus solution (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"antispyware","description":"The health of the monitored Antispyware solution (see windows_security_products)","type":"text","hidden":false,"required":false,"index":false},{"name":"internet_settings","description":"The health of the Internet Settings","type":"text","hidden":false,"required":false,"index":false},{"name":"windows_security_center_service","description":"The health of the Windows Security Center Service","type":"text","hidden":false,"required":false,"index":false},{"name":"user_account_control","description":"The health of the User Account Control (UAC) capability in Windows","type":"text","hidden":false,"required":false,"index":false}]},{"name":"windows_security_products","description":"Enumeration of registered Windows security products.","platforms":["windows"],"columns":[{"name":"type","description":"Type of security product","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of product","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"State of protection","type":"text","hidden":false,"required":false,"index":false},{"name":"state_timestamp","description":"Timestamp for the product state","type":"text","hidden":false,"required":false,"index":false},{"name":"remediation_path","description":"Remediation path","type":"text","hidden":false,"required":false,"index":false},{"name":"signatures_up_to_date","description":"1 if product signatures are up to date, else 0","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"wmi_bios_info","description":"Lists important information from the system bios.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the Bios setting","type":"text","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the Bios setting","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_cli_event_consumers","description":"WMI CommandLineEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique name of a consumer.","type":"text","hidden":false,"required":false,"index":false},{"name":"command_line_template","description":"Standard string template that specifies the process to be started. This property can be NULL, and the ExecutablePath property is used as the command line.","type":"text","hidden":false,"required":false,"index":false},{"name":"executable_path","description":"Module to execute. The string can specify the full path and file name of the module to execute, or it can specify a partial name. If a partial name is specified, the current drive and current directory are assumed.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_event_filters","description":"Lists WMI event filters.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier of an event filter.","type":"text","hidden":false,"required":false,"index":false},{"name":"query","description":"Windows Management Instrumentation Query Language (WQL) event query that specifies the set of events for consumer notification, and the specific conditions for notification.","type":"text","hidden":false,"required":false,"index":false},{"name":"query_language","description":"Query language that the query is written in.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_filter_consumer_binding","description":"Lists the relationship between event consumers and filters.","platforms":["windows"],"columns":[{"name":"consumer","description":"Reference to an instance of __EventConsumer that represents the object path to a logical consumer, the recipient of an event.","type":"text","hidden":false,"required":false,"index":false},{"name":"filter","description":"Reference to an instance of __EventFilter that represents the object path to an event filter which is a query that specifies the type of event to be received.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"wmi_script_event_consumers","description":"WMI ActiveScriptEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier for the event consumer. ","type":"text","hidden":false,"required":false,"index":false},{"name":"scripting_engine","description":"Name of the scripting engine to use, for example, 'VBScript'. This property cannot be NULL.","type":"text","hidden":false,"required":false,"index":false},{"name":"script_file_name","description":"Name of the file from which the script text is read, intended as an alternative to specifying the text of the script in the ScriptText property.","type":"text","hidden":false,"required":false,"index":false},{"name":"script_text","description":"Text of the script that is expressed in a language known to the scripting engine. This property must be NULL if the ScriptFileName property is not NULL.","type":"text","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"xprotect_entries","description":"Database of the machine's XProtect signatures.","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","hidden":false,"required":false,"index":false},{"name":"launch_type","description":"Launch services content type","type":"text","hidden":false,"required":false,"index":false},{"name":"identity","description":"XProtect identity (SHA1) of content","type":"text","hidden":false,"required":false,"index":false},{"name":"filename","description":"Use this file name to match","type":"text","hidden":false,"required":false,"index":false},{"name":"filetype","description":"Use this file type to match","type":"text","hidden":false,"required":false,"index":false},{"name":"optional","description":"Match any of the identities/patterns for this XProtect name","type":"integer","hidden":false,"required":false,"index":false},{"name":"uses_pattern","description":"Uses a match pattern instead of identity","type":"integer","hidden":false,"required":false,"index":false}]},{"name":"xprotect_meta","description":"Database of the machine's XProtect browser-related signatures.","platforms":["darwin"],"columns":[{"name":"identifier","description":"Browser plugin or extension identifier","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Either plugin or extension","type":"text","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Developer identity (SHA1) of extension","type":"text","hidden":false,"required":false,"index":false},{"name":"min_version","description":"The minimum allowed plugin version.","type":"text","hidden":false,"required":false,"index":false}]},{"name":"xprotect_reports","description":"Database of XProtect matches (if user generated/sent an XProtect report).","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","hidden":false,"required":false,"index":false},{"name":"user_action","description":"Action taken by user after prompted","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Quarantine alert time","type":"text","hidden":false,"required":false,"index":false}]},{"name":"yara","description":"Track YARA matches for files or PIDs.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"The path scanned","type":"text","hidden":false,"required":true,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","hidden":false,"required":false,"index":false},{"name":"sig_group","description":"Signature group used","type":"text","hidden":false,"required":false,"index":false},{"name":"sigfile","description":"Signature file used","type":"text","hidden":false,"required":false,"index":false},{"name":"sigrule","description":"Signature strings used","type":"text","hidden":true,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","hidden":false,"required":false,"index":false},{"name":"sigurl","description":"Signature url","type":"text","hidden":true,"required":false,"index":false}]},{"name":"yara_events","description":"Track YARA matches for files specified in configuration data.","platforms":["darwin","linux","windows"],"columns":[{"name":"target_path","description":"The path scanned","type":"text","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file","type":"text","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","hidden":false,"required":false,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","hidden":false,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of the scan","type":"bigint","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","hidden":true,"required":false,"index":false}]},{"name":"ycloud_instance_metadata","description":"Yandex.Cloud instance metadata.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"instance_id","description":"Unique identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"folder_id","description":"Folder identifier for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Hostname of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","hidden":false,"required":false,"index":false},{"name":"serial_port_enabled","description":"Indicates if serial port is enabled for the VM","type":"text","hidden":false,"required":false,"index":false},{"name":"metadata_endpoint","description":"Endpoint used to fetch VM metadata","type":"text","hidden":false,"required":false,"index":false}]},{"name":"yum_sources","description":"Current list of Yum repositories or software channels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Repository name","type":"text","hidden":false,"required":false,"index":false},{"name":"baseurl","description":"Repository base URL","type":"text","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether the repository is used","type":"text","hidden":false,"required":false,"index":false},{"name":"gpgcheck","description":"Whether packages are GPG checked","type":"text","hidden":false,"required":false,"index":false},{"name":"gpgkey","description":"URL to GPG key","type":"text","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"host_users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"uid","description":"User ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","hidden":false,"required":false,"index":false},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"host_groups","description":"Local system groups.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","hidden":true,"required":false,"index":false},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","hidden":true,"required":false,"index":false},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","hidden":true,"required":false,"index":false}]},{"name":"host_processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows","freebsd"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"protection_type","description":"The protection type of the process","type":"text","hidden":true,"required":false,"index":false},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","hidden":true,"required":false,"index":false},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","hidden":true,"required":false,"index":false},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","hidden":false,"required":false,"index":false}]}] \ No newline at end of file diff --git a/x-pack/plugins/osquery/public/components/beta_badge.tsx b/x-pack/plugins/osquery/public/components/beta_badge.tsx deleted file mode 100644 index f63c80168b487..0000000000000 --- a/x-pack/plugins/osquery/public/components/beta_badge.tsx +++ /dev/null @@ -1,37 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiBetaBadge, EuiText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import styled from 'styled-components'; - -export const BetaBadgeRowWrapper = styled(EuiText)` - display: flex; - align-items: center; -`; - -const Wrapper = styled.div` - padding-left: ${({ theme }) => theme.eui.paddingSizes.s}; -`; - -const betaBadgeLabel = i18n.translate('xpack.osquery.common.tabBetaBadgeLabel', { - defaultMessage: 'Beta', -}); - -const betaBadgeTooltipContent = i18n.translate('xpack.osquery.common.tabBetaBadgeTooltipContent', { - defaultMessage: - 'This feature is under active development. Extra functionality is coming, and some functionality may change.', -}); - -const BetaBadgeComponent = () => ( - - - -); - -export const BetaBadge = React.memo(BetaBadgeComponent); diff --git a/x-pack/plugins/osquery/public/fleet_integration/config_uploader.tsx b/x-pack/plugins/osquery/public/fleet_integration/config_uploader.tsx new file mode 100644 index 0000000000000..95ccc0e5cccf5 --- /dev/null +++ b/x-pack/plugins/osquery/public/fleet_integration/config_uploader.tsx @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiLink, EuiFormRow, EuiFilePicker, EuiSpacer } from '@elastic/eui'; +import React, { useCallback, useState, useRef } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +const SUPPORTED_CONFIG_EXTENSIONS = ['application/json', 'text/plain']; + +const ExampleConfigLink = React.memo(() => ( + + + +)); + +ExampleConfigLink.displayName = 'ExampleOsqueryConfigLink'; + +interface ConfigUploaderProps { + onChange: (payload: Record) => void; +} + +const ConfigUploaderComponent: React.FC = ({ onChange }) => { + const filePickerRef = useRef(null); + const [isInvalid, setIsInvalid] = useState(null); + // @ts-expect-error update types + let fileReader; + + const handleFileRead = () => { + // @ts-expect-error update types + const content = fileReader.result; + + let parsedContent; + + try { + parsedContent = JSON.parse(content.replaceAll('\\\n', ''), (key, value) => { + if (key === 'query') { + // remove any multiple spaces from the query + return value.replaceAll(/\s(?=\s)/gm, ''); + } + return value; + }); + + setIsInvalid(null); + } catch (error) { + setIsInvalid(error); + // @ts-expect-error update types + filePickerRef.current?.removeFiles(new Event('fake')); + } + + onChange(parsedContent); + // @ts-expect-error update types + filePickerRef.current?.removeFiles(new Event('fake')); + }; + + // @ts-expect-error update types + // eslint-disable-next-line react-hooks/exhaustive-deps + const handleFileChosen = (file) => { + fileReader = new FileReader(); + fileReader.onloadend = handleFileRead; + fileReader.readAsText(file); + }; + + const handleInputChange = useCallback( + (inputFiles) => { + if (!inputFiles.length) { + return; + } + + if ( + inputFiles.length && + ((!!inputFiles[0].type.length && + !SUPPORTED_CONFIG_EXTENSIONS.includes(inputFiles[0].type)) ?? + !inputFiles[0].name.endsWith('.conf')) + ) { + setIsInvalid( + i18n.translate('xpack.osquery.configUploader.unsupportedFileTypeText', { + defaultMessage: + 'File type {fileType} is not supported, please upload {supportedFileTypes} config file', + values: { + fileType: inputFiles[0].type, + supportedFileTypes: SUPPORTED_CONFIG_EXTENSIONS.join(' or '), + }, + }) + ); + // @ts-expect-error update types + filePickerRef.current?.removeFiles(new Event('fake')); + return; + } + + handleFileChosen(inputFiles[0]); + }, + [handleFileChosen] + ); + + return ( + <> + + } + isInvalid={!!isInvalid} + error={<>{`${isInvalid}`}} + > + + + + ); +}; + +export const ConfigUploader = React.memo(ConfigUploaderComponent); diff --git a/x-pack/plugins/osquery/public/fleet_integration/navigation_buttons.tsx b/x-pack/plugins/osquery/public/fleet_integration/navigation_buttons.tsx index b6a90541d26c6..4bcc9d9ebf2a1 100644 --- a/x-pack/plugins/osquery/public/fleet_integration/navigation_buttons.tsx +++ b/x-pack/plugins/osquery/public/fleet_integration/navigation_buttons.tsx @@ -14,13 +14,11 @@ import { useKibana, isModifiedEvent, isLeftClickEvent } from '../common/lib/kiba interface NavigationButtonsProps { isDisabled?: boolean; - integrationPolicyId?: string | undefined; agentPolicyId?: string | undefined; } const NavigationButtonsComponent: React.FC = ({ isDisabled = false, - integrationPolicyId, agentPolicyId, }) => { const { @@ -52,7 +50,7 @@ const NavigationButtonsComponent: React.FC = ({ ); const packsHref = getUrlForApp(PLUGIN_ID, { - path: integrationPolicyId ? `/packs/${integrationPolicyId}/edit` : `/packs`, + path: `/packs`, }); const packsClick = useCallback( @@ -60,11 +58,11 @@ const NavigationButtonsComponent: React.FC = ({ if (!isModifiedEvent(event) && isLeftClickEvent(event)) { event.preventDefault(); navigateToApp(PLUGIN_ID, { - path: integrationPolicyId ? `/packs/${integrationPolicyId}/edit` : `/packs`, + path: `/packs`, }); } }, - [navigateToApp, integrationPolicyId] + [navigateToApp] ); return ( diff --git a/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx b/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx index 752e95b70efac..4ac20e6144c08 100644 --- a/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx +++ b/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { get, isEmpty, unset, set } from 'lodash'; +import { pickBy, get, isEmpty, isString, unset, set, intersection } from 'lodash'; import satisfies from 'semver/functions/satisfies'; import { EuiFlexGroup, @@ -15,7 +15,7 @@ import { EuiLink, EuiAccordion, } from '@elastic/eui'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { produce } from 'immer'; import { i18n } from '@kbn/i18n'; import useDebounce from 'react-use/lib/useDebounce'; @@ -35,7 +35,105 @@ import { import { useKibana } from '../common/lib/kibana'; import { NavigationButtons } from './navigation_buttons'; import { DisabledCallout } from './disabled_callout'; -import { Form, useForm, Field, getUseField, FIELD_TYPES, fieldValidators } from '../shared_imports'; +import { ConfigUploader } from './config_uploader'; +import { + Form, + useForm, + useFormData, + Field, + getUseField, + FIELD_TYPES, + fieldValidators, + ValidationFunc, +} from '../shared_imports'; + +// https://github.com/elastic/beats/blob/master/x-pack/osquerybeat/internal/osqd/args.go#L57 +const RESTRICTED_CONFIG_OPTIONS = [ + 'force', + 'disable_watchdog', + 'utc', + 'events_expiry', + 'extensions_socket', + 'extensions_interval', + 'extensions_timeout', + 'pidfile', + 'database_path', + 'extensions_autoload', + 'flagfile', + 'config_plugin', + 'logger_plugin', + 'pack_delimiter', + 'config_refresh', +]; + +export const configProtectedKeysValidator = ( + ...args: Parameters +): ReturnType => { + const [{ value }] = args; + + let configJSON; + try { + configJSON = JSON.parse(value as string); + } catch (e) { + return; + } + + const restrictedFlags = intersection( + Object.keys(configJSON?.options ?? {}), + RESTRICTED_CONFIG_OPTIONS + ); + + if (restrictedFlags.length) { + return { + code: 'ERR_RESTRICTED_OPTIONS', + message: i18n.translate( + 'xpack.osquery.fleetIntegration.osqueryConfig.restrictedOptionsErrorMessage', + { + defaultMessage: + 'The following osquery options are not supported and must be removed: {restrictedFlags}.', + values: { + restrictedFlags: restrictedFlags.join(', '), + }, + } + ), + }; + } + + return; +}; + +export const packConfigFilesValidator = ( + ...args: Parameters +): ReturnType => { + const [{ value }] = args; + + let configJSON; + try { + configJSON = JSON.parse(value as string); + } catch (e) { + return; + } + + const packsWithConfigPaths = Object.keys(pickBy(configJSON?.packs ?? {}, isString)); + + if (packsWithConfigPaths.length) { + return { + code: 'ERR_RESTRICTED_OPTIONS', + message: i18n.translate( + 'xpack.osquery.fleetIntegration.osqueryConfig.packConfigFilesErrorMessage', + { + defaultMessage: + 'Pack configuration files are not supported. These packs must be removed: {packNames}.', + values: { + packNames: packsWithConfigPaths.join(', '), + }, + } + ), + }; + } + + return; +}; const CommonUseField = getUseField({ component: Field }); @@ -67,6 +165,16 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< defaultValue: { config: JSON.stringify(get(newPolicy, 'inputs[0].config.osquery.value', {}), null, 2), }, + serializer: (formData) => { + let config; + try { + // @ts-expect-error update types + config = JSON.parse(formData.config); + } catch (e) { + config = {}; + } + return { config }; + }, schema: { config: { label: i18n.translate('xpack.osquery.fleetIntegration.osqueryConfig.configFieldLabel', { @@ -82,35 +190,63 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< { allowEmptyString: true } ), }, + { validator: packConfigFilesValidator }, + { + validator: configProtectedKeysValidator, + }, ], }, }, }); - const { isValid, getFormData } = configForm; + const [{ config }] = useFormData({ form: configForm, watch: 'config' }); + const { isValid, setFieldValue } = configForm; const agentsLinkHref = useMemo(() => { if (!policy?.policy_id) return '#'; return getUrlForApp(PLUGIN_ID, { - path: - `#` + - pagePathGetters.policy_details({ policyId: policy?.policy_id })[1] + - '?openEnrollmentFlyout=true', + path: pagePathGetters.policy_details({ policyId: policy?.policy_id })[1], }); }, [getUrlForApp, policy?.policy_id]); + const handleConfigUpload = useCallback( + (newConfig) => { + let currentPacks = {}; + try { + currentPacks = JSON.parse(config)?.packs; + // eslint-disable-next-line no-empty + } catch (e) {} + + if (newConfig) { + setFieldValue( + 'config', + JSON.stringify( + { + ...newConfig, + ...(currentPacks || newConfig.packs + ? { packs: { ...newConfig.packs, ...currentPacks } } + : {}), + }, + null, + 2 + ) + ); + } + }, + [config, setFieldValue] + ); + useDebounce( () => { // if undefined it means that config was not modified if (isValid === undefined) return; - const configData = getFormData().config; const updatedPolicy = produce(newPolicy, (draft) => { - if (isEmpty(configData)) { + if (isEmpty(config)) { unset(draft, 'inputs[0].config'); } else { - set(draft, 'inputs[0].config.osquery.value', configData); + set(draft, 'inputs[0].config.osquery.value', config); } return draft; }); @@ -118,7 +254,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< onChange({ isValid: !!isValid, updatedPolicy: isValid ? updatedPolicy : newPolicy }); }, 500, - [isValid] + [isValid, config] ); useEffect(() => { @@ -220,11 +356,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< ) : null} - +
+
diff --git a/x-pack/plugins/osquery/public/live_queries/index.tsx b/x-pack/plugins/osquery/public/live_queries/index.tsx index 93459260a7333..81d3a6592a3c9 100644 --- a/x-pack/plugins/osquery/public/live_queries/index.tsx +++ b/x-pack/plugins/osquery/public/live_queries/index.tsx @@ -48,14 +48,19 @@ const LiveQueryComponent: React.FC = ({ const { data: hasActionResultsPrivileges, isFetched } = useActionResultsPrivileges(); const defaultValue = useMemo(() => { - if (agentId || agentPolicyIds || query) { + if (agentId || agentPolicyIds?.length || query?.length) { + const agentSelection = + agentId || agentPolicyIds?.length + ? { + allAgentsSelected: false, + agents: castArray(agentId ?? agentIds ?? []), + platformsSelected: [], + policiesSelected: agentPolicyIds ?? [], + } + : null; + return { - agentSelection: { - allAgentsSelected: false, - agents: castArray(agentId ?? agentIds ?? []), - platformsSelected: [], - policiesSelected: agentPolicyIds ?? [], - }, + ...(agentSelection ? { agentSelection } : {}), query, savedQueryId, ecs_mapping, diff --git a/x-pack/plugins/osquery/public/packs/packs_table.tsx b/x-pack/plugins/osquery/public/packs/packs_table.tsx index 75a006e9743f6..3d4efd88b789f 100644 --- a/x-pack/plugins/osquery/public/packs/packs_table.tsx +++ b/x-pack/plugins/osquery/public/packs/packs_table.tsx @@ -5,9 +5,17 @@ * 2.0. */ -import { EuiInMemoryTable, EuiBasicTableColumn, EuiLink, EuiToolTip } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiText, + EuiPopover, + EuiInMemoryTable, + EuiBasicTableColumn, + EuiLink, + EuiToolTip, +} from '@elastic/eui'; import moment from 'moment-timezone'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; @@ -15,6 +23,7 @@ import { PackagePolicy } from '../../../fleet/common'; import { useRouterNavigate } from '../common/lib/kibana'; import { usePacks } from './use_packs'; import { ActiveStateSwitch } from './active_state_switch'; +import { AgentsPolicyLink } from '../agent_policies/agents_policy_link'; const UpdatedBy = styled.span` white-space: nowrap; @@ -32,10 +41,53 @@ const renderName = (_: unknown, item: { id: string; attributes: { name: string } ); +export const AgentPoliciesPopover = ({ agentPolicyIds }: { agentPolicyIds: string[] }) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onButtonClick = useCallback( + () => setIsPopoverOpen((currentIsPopoverOpen) => !currentIsPopoverOpen), + [] + ); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + + const button = useMemo( + () => ( + + <>{agentPolicyIds?.length ?? 0} + + ), + [agentPolicyIds?.length, onButtonClick] + ); + + if (!agentPolicyIds?.length) { + return <>{agentPolicyIds?.length ?? 0}; + } + + return ( + + + {agentPolicyIds?.map((policyId) => ( +
+ +
+ ))} +
+
+ ); +}; + const PacksTableComponent = () => { const { data } = usePacks({}); - const renderAgentPolicy = useCallback((policyIds) => <>{policyIds?.length ?? 0}, []); + const renderAgentPolicy = useCallback( + (agentPolicyIds) => , + [] + ); const renderQueries = useCallback( (queries) => <>{(queries && Object.keys(queries).length) ?? 0}, diff --git a/x-pack/plugins/osquery/public/packs/queries/ecs_mapping_editor_field.tsx b/x-pack/plugins/osquery/public/packs/queries/ecs_mapping_editor_field.tsx index 4d7776bdb2954..f6967f26cfbc2 100644 --- a/x-pack/plugins/osquery/public/packs/queries/ecs_mapping_editor_field.tsx +++ b/x-pack/plugins/osquery/public/packs/queries/ecs_mapping_editor_field.tsx @@ -93,6 +93,7 @@ const StyledFieldSpan = styled.span` // align the icon to the inputs const StyledButtonWrapper = styled.div` margin-top: 11px; + width: 24px; `; const ECSFieldWrapper = styled(EuiFlexItem)` @@ -476,12 +477,19 @@ export const ECSMappingEditorForm = forwardRef { + if (onAdd && !deepEqual(formData, currentFormData.current)) { + currentFormData.current = formData; + handleSubmit(); + } + }, [handleSubmit, formData, onAdd]); + useEffect(() => { if (onChange && !deepEqual(formData, currentFormData.current)) { currentFormData.current = formData; onChange(formData); } - }, [defaultValue, formData, onChange]); + }, [defaultValue, formData, handleDeleteClick, onChange]); useEffect(() => { if (defaultValue) { @@ -497,18 +505,15 @@ export const ECSMappingEditorForm = forwardRef - +
@@ -517,16 +522,19 @@ export const ECSMappingEditorForm = forwardRef {!isDisabled && ( - {defaultValue ? ( + {defaultValue && ( - ) : ( - )} @@ -768,7 +764,7 @@ export const ECSMappingEditorField = ({ LIMIT 5; */ - if (selectItem.type === 'FunctionCall' && selectItem.hasAs) { + if (selectItem.hasAs && selectItem.alias) { return [ { label: selectItem.alias, @@ -873,16 +869,16 @@ export const ECSMappingEditorField = ({ diff --git a/x-pack/plugins/osquery/public/results/results_table.tsx b/x-pack/plugins/osquery/public/results/results_table.tsx index e0dfb208e0ebc..5b8143c874e2b 100644 --- a/x-pack/plugins/osquery/public/results/results_table.tsx +++ b/x-pack/plugins/osquery/public/results/results_table.tsx @@ -77,7 +77,7 @@ const ResultsTableComponent: React.FC = ({ const getFleetAppUrl = useCallback( (agentId) => getUrlForApp('fleet', { - path: `#` + pagePathGetters.agent_details({ agentId })[1], + path: pagePathGetters.agent_details({ agentId })[1], }), [getUrlForApp] ); diff --git a/x-pack/plugins/osquery/public/routes/live_queries/details/index.tsx b/x-pack/plugins/osquery/public/routes/live_queries/details/index.tsx index 02f5c8b6fb2a5..116430d026a79 100644 --- a/x-pack/plugins/osquery/public/routes/live_queries/details/index.tsx +++ b/x-pack/plugins/osquery/public/routes/live_queries/details/index.tsx @@ -6,7 +6,14 @@ */ import { get } from 'lodash'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiCodeBlock, EuiSpacer } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiCodeBlock, + EuiSpacer, + EuiText, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo } from 'react'; import { useParams } from 'react-router-dom'; @@ -16,7 +23,6 @@ import { WithHeaderLayout } from '../../../components/layouts'; import { useActionDetails } from '../../../actions/use_action_details'; import { ResultTabs } from '../../saved_queries/edit/tabs'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const LiveQueryDetailsPageComponent = () => { const { actionId } = useParams<{ actionId: string }>(); @@ -37,15 +43,14 @@ const LiveQueryDetailsPageComponent = () => {
- +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/live_queries/list/index.tsx b/x-pack/plugins/osquery/public/routes/live_queries/list/index.tsx index 23bc44b455405..ccf9b655a96d7 100644 --- a/x-pack/plugins/osquery/public/routes/live_queries/list/index.tsx +++ b/x-pack/plugins/osquery/public/routes/live_queries/list/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo } from 'react'; @@ -13,7 +13,6 @@ import { useKibana, useRouterNavigate } from '../../../common/lib/kibana'; import { ActionsTable } from '../../../actions/actions_table'; import { WithHeaderLayout } from '../../../components/layouts'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const LiveQueriesPageComponent = () => { const permissions = useKibana().services.application.capabilities.osquery; @@ -24,15 +23,14 @@ const LiveQueriesPageComponent = () => { () => ( - +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/live_queries/new/index.tsx b/x-pack/plugins/osquery/public/routes/live_queries/new/index.tsx index 28db39ac1805f..2d2f6bac55144 100644 --- a/x-pack/plugins/osquery/public/routes/live_queries/new/index.tsx +++ b/x-pack/plugins/osquery/public/routes/live_queries/new/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useEffect, useMemo, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; @@ -15,7 +15,6 @@ import { WithHeaderLayout } from '../../../components/layouts'; import { useRouterNavigate } from '../../../common/lib/kibana'; import { LiveQuery } from '../../../live_queries'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const NewLiveQueryPageComponent = () => { useBreadcrumbs('live_query_new'); @@ -49,15 +48,14 @@ const NewLiveQueryPageComponent = () => {
- +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/packs/add/index.tsx b/x-pack/plugins/osquery/public/routes/packs/add/index.tsx index b34550d07f811..bd9abd7ff2625 100644 --- a/x-pack/plugins/osquery/public/routes/packs/add/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/add/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo } from 'react'; @@ -13,7 +13,6 @@ import { WithHeaderLayout } from '../../../components/layouts'; import { useRouterNavigate } from '../../../common/lib/kibana'; import { PackForm } from '../../../packs/form'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const AddPackPageComponent = () => { useBreadcrumbs('pack_add'); @@ -31,12 +30,11 @@ const AddPackPageComponent = () => { - +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/packs/details/index.tsx b/x-pack/plugins/osquery/public/routes/packs/details/index.tsx index 063cc75db2572..f81150468d018 100644 --- a/x-pack/plugins/osquery/public/routes/packs/details/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/details/index.tsx @@ -26,8 +26,8 @@ import { WithHeaderLayout } from '../../../components/layouts'; import { usePack } from '../../../packs/use_pack'; import { PackQueriesStatusTable } from '../../../packs/pack_queries_status_table'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; import { useAgentPolicyAgentIds } from '../../../agents/use_agent_policy_agent_ids'; +import { AgentPoliciesPopover } from '../../../packs/packs_table'; const Divider = styled.div` width: 0; @@ -69,7 +69,7 @@ const PackDetailsPageComponent = () => { - +

{ }} />

- -
+
{data?.description && ( @@ -111,7 +110,7 @@ const PackDetailsPageComponent = () => { { // @ts-expect-error update types - data?.policy_ids?.length + } diff --git a/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx b/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx index bd1d7a5e0875c..a5935243d763e 100644 --- a/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx @@ -12,6 +12,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingContent, + EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useCallback, useMemo, useState } from 'react'; @@ -24,7 +25,6 @@ import { usePack } from '../../../packs/use_pack'; import { useDeletePack } from '../../../packs/use_delete_pack'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const EditPackPageComponent = () => { const { packId } = useParams<{ packId: string }>(); @@ -67,7 +67,7 @@ const EditPackPageComponent = () => { - +

{ }} />

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/packs/list/index.tsx b/x-pack/plugins/osquery/public/routes/packs/list/index.tsx index 12f646e230ff6..945677cade577 100644 --- a/x-pack/plugins/osquery/public/routes/packs/list/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/list/index.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo } from 'react'; import { useKibana, useRouterNavigate } from '../../../common/lib/kibana'; import { WithHeaderLayout } from '../../../components/layouts'; import { PacksTable } from '../../../packs/packs_table'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; const PacksPageComponent = () => { const permissions = useKibana().services.application.capabilities.osquery; @@ -22,12 +21,11 @@ const PacksPageComponent = () => { () => ( - +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/edit/index.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/edit/index.tsx index 71d0c886aac56..df9576c0070a8 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/edit/index.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/edit/index.tsx @@ -11,6 +11,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiConfirmModal, + EuiText, } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import React, { useCallback, useMemo, useState } from 'react'; @@ -20,7 +21,6 @@ import { useParams } from 'react-router-dom'; import { useKibana, useRouterNavigate } from '../../../common/lib/kibana'; import { WithHeaderLayout } from '../../../components/layouts'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; import { EditSavedQueryForm } from './form'; import { useDeleteSavedQuery, useUpdateSavedQuery, useSavedQuery } from '../../../saved_queries'; @@ -65,7 +65,7 @@ const EditSavedQueryPageComponent = () => { - +

{viewMode ? ( { /> )}

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/list/index.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/list/index.tsx index 9f6ec176faac2..f59a07763f0fa 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/list/index.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/list/index.tsx @@ -12,6 +12,7 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, + EuiText, } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; @@ -23,7 +24,6 @@ import { ECSMapping } from '../../../../common/schemas/common'; import { WithHeaderLayout } from '../../../components/layouts'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; import { useKibana, useRouterNavigate } from '../../../common/lib/kibana'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; import { useSavedQueries } from '../../../saved_queries/use_saved_queries'; type SavedQuerySO = SavedObject<{ @@ -218,15 +218,14 @@ const SavedQueriesPageComponent = () => { () => ( - +

- -
+
), diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/new/index.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/new/index.tsx index 3dc42aabe7a94..2a09a4c4ee556 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/new/index.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/new/index.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { useRouterNavigate } from '../../../common/lib/kibana'; import { WithHeaderLayout } from '../../../components/layouts'; import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs'; -import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge'; import { NewSavedQueryForm } from './form'; import { useCreateSavedQuery } from '../../../saved_queries/use_create_saved_query'; @@ -34,15 +33,14 @@ const NewSavedQueryPageComponent = () => { - +

- -
+
), diff --git a/x-pack/plugins/osquery/public/saved_queries/form/index.tsx b/x-pack/plugins/osquery/public/saved_queries/form/index.tsx index 1d3677e96298e..314c5e07b0b2a 100644 --- a/x-pack/plugins/osquery/public/saved_queries/form/index.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/form/index.tsx @@ -156,7 +156,12 @@ const SavedQueryFormComponent = forwardRef - {playgroundVisible && } + {playgroundVisible && ( + + )} ); } diff --git a/x-pack/plugins/osquery/scripts/schema_formatter/osquery_formatter.ts b/x-pack/plugins/osquery/scripts/schema_formatter/osquery_formatter.ts index 53d48f45ea92b..157f4ab0a5936 100644 --- a/x-pack/plugins/osquery/scripts/schema_formatter/osquery_formatter.ts +++ b/x-pack/plugins/osquery/scripts/schema_formatter/osquery_formatter.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { map, partialRight, pick } from 'lodash'; +import { find, map, partialRight, pick } from 'lodash'; import { promises as fs } from 'fs'; import path from 'path'; import { run } from '@kbn/dev-utils'; const OSQUERY_COLUMN_SCHEMA_FIELDS = ['name', 'description', 'platforms', 'columns']; +const ELASTIC_OSQUERY_HOSTFS_TABLES = ['users', 'groups', 'processes']; run( async ({ flags }) => { @@ -20,9 +21,14 @@ run( const schemaData = await require(schemaFile); const formattedSchema = map(schemaData, partialRight(pick, OSQUERY_COLUMN_SCHEMA_FIELDS)); + const elasticTables = map(ELASTIC_OSQUERY_HOSTFS_TABLES, (tableName) => ({ + ...find(formattedSchema, { name: tableName }), + name: `host_${tableName}`, + })); + formattedSchema.push(...elasticTables); await fs.writeFile( - path.join(schemaPath, `v${flags.schema_version}-formatted.json`), + path.join(schemaPath, `${flags.schema_version}`), JSON.stringify(formattedSchema) ); }, diff --git a/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agents.ts b/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agents.ts index d45cb26e0d199..f129e95fd9508 100644 --- a/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agents.ts +++ b/x-pack/plugins/osquery/server/routes/fleet_wrapper/get_agents.ts @@ -22,10 +22,15 @@ export const getAgentsRoute = (router: IRouter, osqueryContext: OsqueryAppContex async (context, request, response) => { const esClient = context.core.elasticsearch.client.asInternalUser; - const agents = await osqueryContext.service - .getAgentService() - // @ts-expect-error update types - ?.listAgents(esClient, request.query); + let agents; + try { + agents = await osqueryContext.service + .getAgentService() + // @ts-expect-error update types + ?.listAgents(esClient, request.query); + } catch (error) { + return response.badRequest({ body: error }); + } return response.ok({ body: agents }); } diff --git a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts index aa4e3cb36b4c9..630ec8b3743c8 100644 --- a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts +++ b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts @@ -17,6 +17,7 @@ import { PLUGIN_ID, OSQUERY_INTEGRATION_NAME } from '../../../common'; import { IRouter } from '../../../../../../src/core/server'; import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; import { convertPackQueriesToSO } from '../pack/utils'; +import { getInternalSavedObjectsClient } from '../../usage/collector'; export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => { router.get( @@ -27,18 +28,21 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon }, async (context, request, response) => { const esClient = context.core.elasticsearch.client.asInternalUser; - const soClient = context.core.savedObjects.client; + const internalSavedObjectsClient = await getInternalSavedObjectsClient( + osqueryContext.getStartServices + ); const packageService = osqueryContext.service.getPackageService(); const packagePolicyService = osqueryContext.service.getPackagePolicyService(); const agentPolicyService = osqueryContext.service.getAgentPolicyService(); - const packageInfo = await osqueryContext.service - .getPackageService() - ?.getInstallation({ savedObjectsClient: soClient, pkgName: OSQUERY_INTEGRATION_NAME }); + const packageInfo = await osqueryContext.service.getPackageService()?.getInstallation({ + savedObjectsClient: internalSavedObjectsClient, + pkgName: OSQUERY_INTEGRATION_NAME, + }); if (packageInfo?.install_version && satisfies(packageInfo?.install_version, '<0.6.0')) { try { - const policyPackages = await packagePolicyService?.list(soClient, { + const policyPackages = await packagePolicyService?.list(internalSavedObjectsClient, { kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${OSQUERY_INTEGRATION_NAME}`, perPage: 10000, page: 1, @@ -99,7 +103,7 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon await packageService?.ensureInstalledPackage({ esClient, - savedObjectsClient: soClient, + savedObjectsClient: internalSavedObjectsClient, pkgName: OSQUERY_INTEGRATION_NAME, }); @@ -110,12 +114,15 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon // @ts-expect-error update types pack.policy_ids.includes(key) ); - await packagePolicyService?.upgrade(soClient, esClient, [value]); - const packagePolicy = await packagePolicyService?.get(soClient, value); + await packagePolicyService?.upgrade(internalSavedObjectsClient, esClient, [value]); + const packagePolicy = await packagePolicyService?.get( + internalSavedObjectsClient, + value + ); if (packagePolicy) { return packagePolicyService?.update( - soClient, + internalSavedObjectsClient, esClient, packagePolicy.id, produce(packagePolicy, (draft) => { @@ -147,13 +154,13 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon const agentPolicyIds = uniq(map(policyPackages?.items, 'policy_id')); const agentPolicies = mapKeys( - await agentPolicyService?.getByIds(soClient, agentPolicyIds), + await agentPolicyService?.getByIds(internalSavedObjectsClient, agentPolicyIds), 'id' ); await Promise.all( map(migrationObject.packs, async (packObject) => { - await soClient.create( + await internalSavedObjectsClient.create( packSavedObjectType, { // @ts-expect-error update types @@ -183,7 +190,7 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon ); await packagePolicyService?.delete( - soClient, + internalSavedObjectsClient, esClient, migrationObject.packagePoliciesToDelete ); diff --git a/x-pack/plugins/osquery/server/search_strategy/osquery/factory/actions/all/query.all_actions.dsl.ts b/x-pack/plugins/osquery/server/search_strategy/osquery/factory/actions/all/query.all_actions.dsl.ts index 8dc8fad02a7c1..5162475529792 100644 --- a/x-pack/plugins/osquery/server/search_strategy/osquery/factory/actions/all/query.all_actions.dsl.ts +++ b/x-pack/plugins/osquery/server/search_strategy/osquery/factory/actions/all/query.all_actions.dsl.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ISearchRequestParams } from '../../../../../../../../../src/plugins/data/common'; import { AgentsRequestOptions } from '../../../../../../common/search_strategy'; diff --git a/x-pack/plugins/osquery/server/usage/fetchers.ts b/x-pack/plugins/osquery/server/usage/fetchers.ts index 3ac7d56acac4d..cbf72f9144b4b 100644 --- a/x-pack/plugins/osquery/server/usage/fetchers.ts +++ b/x-pack/plugins/osquery/server/usage/fetchers.ts @@ -10,7 +10,7 @@ import { AggregationsTopHitsAggregate, AggregationsValueAggregate, SearchResponse, -} from '@elastic/elasticsearch/api/types'; +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { PackagePolicyServiceInterface } from '../../../fleet/server'; import { getRouteMetric } from '../routes/usage'; import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../src/core/server'; diff --git a/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts b/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts index 129326dea95ec..856b8062e320e 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts @@ -164,6 +164,7 @@ describe('UPDATE remote clusters', () => { test('updates v1 proxy cluster', async () => { remoteInfoMockFn.mockResolvedValueOnce( + // @ts-expect-error not full interface createApiResponse({ body: { test: { diff --git a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap index c5d87410f596f..40cf48555a8c0 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap +++ b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap @@ -259,6 +259,8 @@ exports[`ScreenCapturePanelContent properly renders a view with "canvas" layout - + + + + + +