diff --git a/.ci/Dockerfile b/.ci/Dockerfile index ec7befe05f0d4..8a972c65f8412 100644 --- a/.ci/Dockerfile +++ b/.ci/Dockerfile @@ -1,7 +1,7 @@ # NOTE: This Dockerfile is ONLY used to run certain tasks in CI. It is not used to run Kibana or as a distributable. # If you're looking for the Kibana Docker image distributable, please see: src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.ts -ARG NODE_VERSION=14.15.1 +ARG NODE_VERSION=14.15.3 FROM node:${NODE_VERSION} AS base diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index 11a39faa9aed0..3c38d6279a038 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -56,8 +56,6 @@ kibanaPipeline(timeoutMinutes: 150) { 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), 'xpack-ciGroup11': kibanaPipeline.xpackCiGroupProcess(11), - 'xpack-ciGroup12': kibanaPipeline.xpackCiGroupProcess(12), - 'xpack-ciGroup13': kibanaPipeline.xpackCiGroupProcess(13), ]), ]) } diff --git a/.ci/jobs.yml b/.ci/jobs.yml index d6ffb7d8f90a3..f62ec9510d2d4 100644 --- a/.ci/jobs.yml +++ b/.ci/jobs.yml @@ -1,4 +1,4 @@ -# This file is needed by functionalTests:ensureAllTestsInCiGroup for the list of ciGroups. That must be changed before this file can be removed +# This file is needed by node scripts/ensure_all_tests_in_ci_group for the list of ciGroups. That must be changed before this file can be removed JOB: - kibana-intake @@ -32,8 +32,6 @@ JOB: - x-pack-ciGroup9 - x-pack-ciGroup10 - x-pack-ciGroup11 - - x-pack-ciGroup12 - - x-pack-ciGroup13 - x-pack-accessibility - x-pack-visualRegression diff --git a/.ci/teamcity/bootstrap.sh b/.ci/teamcity/bootstrap.sh index adb884ca064ba..fc57811bb2077 100755 --- a/.ci/teamcity/bootstrap.sh +++ b/.ci/teamcity/bootstrap.sh @@ -7,7 +7,7 @@ source "$(dirname "${0}")/util.sh" tc_start_block "Bootstrap" tc_start_block "yarn install and kbn bootstrap" -verify_no_git_changes yarn kbn bootstrap --prefer-offline +verify_no_git_changes yarn kbn bootstrap tc_end_block "yarn install and kbn bootstrap" tc_start_block "build kbn-pm" diff --git a/.ci/teamcity/checks/bundle_limits.sh b/.ci/teamcity/checks/bundle_limits.sh index 3f7daef6d0473..751ec5a03ee7b 100755 --- a/.ci/teamcity/checks/bundle_limits.sh +++ b/.ci/teamcity/checks/bundle_limits.sh @@ -4,4 +4,5 @@ set -euo pipefail source "$(dirname "${0}")/../util.sh" -node scripts/build_kibana_platform_plugins --validate-limits +checks-reporter-with-killswitch "Check Bundle Limits" \ + node scripts/build_kibana_platform_plugins --validate-limits diff --git a/.ci/teamcity/checks/commit.sh b/.ci/teamcity/checks/commit.sh new file mode 100755 index 0000000000000..387ec0c126785 --- /dev/null +++ b/.ci/teamcity/checks/commit.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source "$(dirname "${0}")/../util.sh" + +# Runs pre-commit hook script for the files touched in the last commit. +# That way we can ensure a set of quick commit checks earlier as we removed +# the pre-commit hook installation by default. +# If files are more than 200 we will skip it and just use +# the further ci steps that already check linting and file casing for the entire repo. +checks-reporter-with-killswitch "Quick commit checks" \ + "$(dirname "${0}")/commit_check_runner.sh" diff --git a/.ci/teamcity/checks/commit_check_runner.sh b/.ci/teamcity/checks/commit_check_runner.sh new file mode 100755 index 0000000000000..f2a4a20568215 --- /dev/null +++ b/.ci/teamcity/checks/commit_check_runner.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +echo "!!!!!!!! ATTENTION !!!!!!!! +That check is intended to provide earlier CI feedback after we remove the automatic install for the local pre-commit hook. +If you want, you can still manually install the pre-commit hook locally by running 'node scripts/register_git_hook locally' +!!!!!!!!!!!!!!!!!!!!!!!!!!! +" + +node scripts/precommit_hook.js --ref HEAD~1..HEAD --max-files 200 --verbose diff --git a/.ci/teamcity/checks/jest_configs.sh b/.ci/teamcity/checks/jest_configs.sh new file mode 100755 index 0000000000000..6703ffffb5651 --- /dev/null +++ b/.ci/teamcity/checks/jest_configs.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source "$(dirname "${0}")/../util.sh" + +checks-reporter-with-killswitch "Check Jest Configs" \ + node scripts/check_jest_configs diff --git a/.ci/teamcity/checks/plugins_with_circular_deps.sh b/.ci/teamcity/checks/plugins_with_circular_deps.sh new file mode 100755 index 0000000000000..5acc4b2ae351b --- /dev/null +++ b/.ci/teamcity/checks/plugins_with_circular_deps.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source "$(dirname "${0}")/../util.sh" + +checks-reporter-with-killswitch "Check Plugins With Circular Dependencies" \ + node scripts/find_plugins_with_circular_deps diff --git a/.ci/teamcity/oss/plugin_functional.sh b/.ci/teamcity/oss/plugin_functional.sh index 5d1ecbcbd48ee..3570bf01e49c4 100755 --- a/.ci/teamcity/oss/plugin_functional.sh +++ b/.ci/teamcity/oss/plugin_functional.sh @@ -13,6 +13,21 @@ if [[ ! -d "target" ]]; then fi cd - -./test/scripts/test/plugin_functional.sh -./test/scripts/test/example_functional.sh -./test/scripts/test/interpreter_functional.sh +checks-reporter-with-killswitch "Plugin Functional Tests" \ + node scripts/functional_tests \ + --config test/plugin_functional/config.ts \ + --bail \ + --debug + +checks-reporter-with-killswitch "Example Functional Tests" \ + node scripts/functional_tests \ + --config test/examples/config.js \ + --bail \ + --debug + +checks-reporter-with-killswitch "Interpreter Functional Tests" \ + node scripts/functional_tests \ + --config test/interpreter_functional/config.ts \ + --bail \ + --debug \ + --kibana-install-dir "$KIBANA_INSTALL_DIR" diff --git a/.ci/teamcity/setup_env.sh b/.ci/teamcity/setup_env.sh index f662d36247a2f..982d129dae2a6 100755 --- a/.ci/teamcity/setup_env.sh +++ b/.ci/teamcity/setup_env.sh @@ -25,12 +25,14 @@ tc_set_env FORCE_COLOR 1 tc_set_env TEST_BROWSER_HEADLESS 1 tc_set_env ELASTIC_APM_ENVIRONMENT ci +tc_set_env ELASTIC_APM_TRANSACTION_SAMPLE_RATE 0.1 if [[ "${KIBANA_CI_REPORTER_KEY_BASE64-}" ]]; then tc_set_env KIBANA_CI_REPORTER_KEY "$(echo "$KIBANA_CI_REPORTER_KEY_BASE64" | base64 -d)" fi if is_pr; then + tc_set_env ELASTIC_APM_ACTIVE false tc_set_env CHECKS_REPORTER_ACTIVE true # These can be removed once we're not supporting Jenkins and TeamCity at the same time @@ -39,6 +41,7 @@ if is_pr; then tc_set_env ghprbActualCommit "$GITHUB_PR_TRIGGERED_SHA" tc_set_env BUILD_URL "$TEAMCITY_BUILD_URL" else + tc_set_env ELASTIC_APM_ACTIVE true tc_set_env CHECKS_REPORTER_ACTIVE false fi diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0993876f98a6a..94afc5dd22ba9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -258,7 +258,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services /docs/user/alerting/ @elastic/kibana-alerting-services /docs/management/alerting/ @elastic/kibana-alerting-services -#CC# /x-pack/plugins/stack_alerts @elastic/kibana-alerting-services +#CC# /x-pack/plugins/stack_alerts/ @elastic/kibana-alerting-services # Enterprise Search # Shared diff --git a/.node-version b/.node-version index 420568d75691b..c91434ab584a7 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -14.15.2 +14.15.4 diff --git a/.nvmrc b/.nvmrc index 420568d75691b..c91434ab584a7 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14.15.2 +14.15.4 diff --git a/.teamcity/pom.xml b/.teamcity/pom.xml index 5fa068d0a92e0..e6ec1f1c043c2 100644 --- a/.teamcity/pom.xml +++ b/.teamcity/pom.xml @@ -46,6 +46,14 @@ true + + teamcity + https://artifactory.elstc.co/artifactory/teamcity + + true + always + + @@ -53,6 +61,10 @@ JetBrains https://download.jetbrains.com/teamcity-repository + + teamcity + https://artifactory.elstc.co/artifactory/teamcity + @@ -124,5 +136,10 @@ junit 4.13 + + co.elastic.teamcity + teamcity-common + 1.0.0-SNAPSHOT + diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts index ec1b1c6eb94ef..28108d019327b 100644 --- a/.teamcity/settings.kts +++ b/.teamcity/settings.kts @@ -2,7 +2,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.* import projects.Kibana import projects.KibanaConfiguration -version = "2020.1" +version = "2020.2" val config = KibanaConfiguration { agentNetwork = DslContext.getParameter("agentNetwork", "teamcity") diff --git a/.teamcity/src/Agents.kt b/.teamcity/src/Agents.kt new file mode 100644 index 0000000000000..557cce80d0f55 --- /dev/null +++ b/.teamcity/src/Agents.kt @@ -0,0 +1,28 @@ +import co.elastic.teamcity.common.GoogleCloudAgent +import co.elastic.teamcity.common.GoogleCloudAgentDiskType +import co.elastic.teamcity.common.GoogleCloudProfile + +private val sizes = listOf("2", "4", "8", "16") + +val StandardAgents = sizes.map { size -> size to GoogleCloudAgent { + sourceImageFamily = "elastic-kibana-ci-ubuntu-1804-lts" + agentPrefix = "kibana-standard-$size-" + machineType = "n2-standard-$size" + diskSizeGb = 75 + diskType = GoogleCloudAgentDiskType.SSD +} }.toMap() + +val BuildAgent = GoogleCloudAgent { + sourceImageFamily = "elastic-kibana-ci-ubuntu-1804-lts" + agentPrefix = "kibana-c2-16-" + machineType = "c2-standard-16" + diskSizeGb = 250 + diskType = GoogleCloudAgentDiskType.SSD +} + +val CloudProfile = GoogleCloudProfile { + accessKeyId = "447fdd4d-7129-46b7-9822-2e57658c7422" + + agents(StandardAgents) + agent(BuildAgent) +} diff --git a/.teamcity/src/Extensions.kt b/.teamcity/src/Extensions.kt index 120b333d43e72..2942a6385f13f 100644 --- a/.teamcity/src/Extensions.kt +++ b/.teamcity/src/Extensions.kt @@ -1,9 +1,7 @@ +import co.elastic.teamcity.common.requireAgent import jetbrains.buildServer.configs.kotlin.v2019_2.* -import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.notifications import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.ScriptBuildStep import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script -import jetbrains.buildServer.configs.kotlin.v2019_2.ui.insert -import projects.kibanaConfiguration fun BuildFeatures.junit(dirs: String = "target/**/TEST-*.xml") { feature { @@ -13,40 +11,8 @@ fun BuildFeatures.junit(dirs: String = "target/**/TEST-*.xml") { } } -fun ProjectFeatures.kibanaAgent(init: ProjectFeature.() -> Unit) { - feature { - type = "CloudImage" - param("network", kibanaConfiguration.agentNetwork) - param("subnet", kibanaConfiguration.agentSubnet) - param("growingId", "true") - param("agent_pool_id", "-2") - param("preemptible", "false") - param("sourceProject", "elastic-images-prod") - param("sourceImageFamily", "elastic-kibana-ci-ubuntu-1804-lts") - param("zone", "us-central1-a") - param("profileId", "kibana") - param("diskType", "pd-ssd") - param("machineCustom", "false") - param("maxInstances", "200") - param("imageType", "ImageFamily") - param("diskSizeGb", "75") // TODO - init() - } -} - -fun ProjectFeatures.kibanaAgent(size: String, init: ProjectFeature.() -> Unit = {}) { - kibanaAgent { - id = "KIBANA_STANDARD_$size" - param("source-id", "kibana-standard-$size-") - param("machineType", "n2-standard-$size") - init() - } -} - fun BuildType.kibanaAgent(size: String) { - requirements { - startsWith("teamcity.agent.name", "kibana-standard-$size-", "RQ_AGENT_NAME") - } + requireAgent(StandardAgents[size]!!) } fun BuildType.kibanaAgent(size: Int) { diff --git a/.teamcity/src/builds/Checks.kt b/.teamcity/src/builds/Checks.kt index 1228ea4d94f4c..37336316c4c91 100644 --- a/.teamcity/src/builds/Checks.kt +++ b/.teamcity/src/builds/Checks.kt @@ -11,16 +11,18 @@ object Checks : BuildType({ kibanaAgent(4) val checkScripts = mapOf( + "Quick Commit Checks" to ".ci/teamcity/checks/commit.sh", "Check Telemetry Schema" to ".ci/teamcity/checks/telemetry.sh", "Check TypeScript Projects" to ".ci/teamcity/checks/ts_projects.sh", "Check File Casing" to ".ci/teamcity/checks/file_casing.sh", "Check Licenses" to ".ci/teamcity/checks/licenses.sh", "Verify NOTICE" to ".ci/teamcity/checks/verify_notice.sh", - "Test Hardening" to ".ci/teamcity/checks/test_hardening.sh", "Check Types" to ".ci/teamcity/checks/type_check.sh", + "Check Jest Configs" to ".ci/teamcity/checks/jest_configs.sh", "Check Doc API Changes" to ".ci/teamcity/checks/doc_api_changes.sh", "Check Bundle Limits" to ".ci/teamcity/checks/bundle_limits.sh", - "Check i18n" to ".ci/teamcity/checks/i18n.sh" + "Check i18n" to ".ci/teamcity/checks/i18n.sh", + "Check Plugins With Circular Dependencies" to ".ci/teamcity/checks/plugins_with_circular_deps.sh" ) steps { diff --git a/.teamcity/src/builds/default/DefaultCiGroup.kt b/.teamcity/src/builds/default/DefaultCiGroup.kt index 7dbe9cd0ba84c..2c3b0d348591e 100755 --- a/.teamcity/src/builds/default/DefaultCiGroup.kt +++ b/.teamcity/src/builds/default/DefaultCiGroup.kt @@ -1,5 +1,7 @@ package builds.default +import StandardAgents +import co.elastic.teamcity.common.requireAgent import jetbrains.buildServer.configs.kotlin.v2019_2.* import runbld @@ -11,5 +13,7 @@ class DefaultCiGroup(val ciGroup: Int = 0, init: BuildType.() -> Unit = {}) : De runbld("Default CI Group $ciGroup", "./.ci/teamcity/default/ci_group.sh $ciGroup") } + requireAgent(StandardAgents["4"]!!) + init() }) diff --git a/.teamcity/src/builds/default/DefaultCiGroups.kt b/.teamcity/src/builds/default/DefaultCiGroups.kt index 6f1d45598c92e..4f39283149e73 100644 --- a/.teamcity/src/builds/default/DefaultCiGroups.kt +++ b/.teamcity/src/builds/default/DefaultCiGroups.kt @@ -3,7 +3,7 @@ package builds.default import dependsOn import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType -const val DEFAULT_CI_GROUP_COUNT = 10 +const val DEFAULT_CI_GROUP_COUNT = 11 val defaultCiGroups = (1..DEFAULT_CI_GROUP_COUNT).map { DefaultCiGroup(it) } object DefaultCiGroups : BuildType({ diff --git a/.teamcity/src/builds/es_snapshots/Verify.kt b/.teamcity/src/builds/es_snapshots/Verify.kt index c778814af536c..4c0307e9eca55 100644 --- a/.teamcity/src/builds/es_snapshots/Verify.kt +++ b/.teamcity/src/builds/es_snapshots/Verify.kt @@ -6,7 +6,7 @@ import builds.default.defaultCiGroups import builds.oss.OssBuild import builds.oss.OssPluginFunctional import builds.oss.ossCiGroups -import builds.test.ApiServerIntegration +import builds.oss.OssApiServerIntegration import builds.test.JestIntegration import dependsOn import jetbrains.buildServer.configs.kotlin.v2019_2.* @@ -49,7 +49,7 @@ val defaultBuildsToClone = listOf( val defaultCloned = defaultBuildsToClone.map { cloneForVerify(it) } val integrationsBuildsToClone = listOf( - ApiServerIntegration, + OssApiServerIntegration, JestIntegration ) diff --git a/.teamcity/src/builds/test/ApiServerIntegration.kt b/.teamcity/src/builds/oss/OssApiServerIntegration.kt similarity index 62% rename from .teamcity/src/builds/test/ApiServerIntegration.kt rename to .teamcity/src/builds/oss/OssApiServerIntegration.kt index ca58b628cbd22..a04512fb2aba5 100644 --- a/.teamcity/src/builds/test/ApiServerIntegration.kt +++ b/.teamcity/src/builds/oss/OssApiServerIntegration.kt @@ -1,10 +1,8 @@ -package builds.test +package builds.oss -import addTestSettings -import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType import runbld -object ApiServerIntegration : BuildType({ +object OssApiServerIntegration : OssFunctionalBase({ name = "API/Server Integration" description = "Executes API and Server Integration Tests" @@ -12,6 +10,4 @@ object ApiServerIntegration : BuildType({ runbld("API Integration", "./.ci/teamcity/oss/api_integration.sh") runbld("Server Integration", "./.ci/teamcity/oss/server_integration.sh") } - - addTestSettings() }) diff --git a/.teamcity/src/builds/test/AllTests.kt b/.teamcity/src/builds/test/AllTests.kt index d1b5898d1a5f5..9506d98cbe50e 100644 --- a/.teamcity/src/builds/test/AllTests.kt +++ b/.teamcity/src/builds/test/AllTests.kt @@ -1,5 +1,6 @@ package builds.test +import builds.oss.OssApiServerIntegration import dependsOn import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType @@ -8,5 +9,5 @@ object AllTests : BuildType({ description = "All Non-Functional Tests" type = Type.COMPOSITE - dependsOn(QuickTests, Jest, XPackJest, JestIntegration, ApiServerIntegration) + dependsOn(QuickTests, Jest, XPackJest, JestIntegration, OssApiServerIntegration) }) diff --git a/.teamcity/src/builds/test/QuickTests.kt b/.teamcity/src/builds/test/QuickTests.kt index 5b1d2541480ad..a294fce9599c3 100644 --- a/.teamcity/src/builds/test/QuickTests.kt +++ b/.teamcity/src/builds/test/QuickTests.kt @@ -12,7 +12,7 @@ object QuickTests : BuildType({ kibanaAgent(2) val testScripts = mapOf( - "Test Hardening" to ".ci/teamcity/checkes/test_hardening.sh", + "Test Hardening" to ".ci/teamcity/checks/test_hardening.sh", "Test Projects" to ".ci/teamcity/tests/test_projects.sh", "Mocha Tests" to ".ci/teamcity/tests/mocha.sh" ) diff --git a/.teamcity/src/projects/Kibana.kt b/.teamcity/src/projects/Kibana.kt index 20c30eedf5b91..1878f49debe8c 100644 --- a/.teamcity/src/projects/Kibana.kt +++ b/.teamcity/src/projects/Kibana.kt @@ -5,9 +5,10 @@ import builds.* import builds.default.* import builds.oss.* import builds.test.* +import CloudProfile +import co.elastic.teamcity.common.googleCloudProfile import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.slackConnection -import kibanaAgent import templates.KibanaTemplate import templates.DefaultTemplate import vcs.Elasticsearch @@ -31,7 +32,7 @@ fun Kibana(config: KibanaConfiguration = KibanaConfiguration()) : Project { param("teamcity.ui.settings.readOnly", "true") // https://github.com/JetBrains/teamcity-webhooks - param("teamcity.internal.webhooks.enable", "true") + param("teamcity.internal.webhooks.enable", "false") param("teamcity.internal.webhooks.events", "BUILD_STARTED;BUILD_FINISHED;BUILD_INTERRUPTED;CHANGES_LOADED;BUILD_TYPE_ADDED_TO_QUEUE;BUILD_PROBLEMS_CHANGED") param("teamcity.internal.webhooks.url", "https://ci-stats.kibana.dev/_teamcity_webhook") param("teamcity.internal.webhooks.username", "automation") @@ -46,36 +47,9 @@ fun Kibana(config: KibanaConfiguration = KibanaConfiguration()) : Project { defaultTemplate = DefaultTemplate - features { - val sizes = listOf("2", "4", "8", "16") - for (size in sizes) { - kibanaAgent(size) - } - - kibanaAgent { - id = "KIBANA_C2_16" - param("source-id", "kibana-c2-16-") - param("machineType", "c2-standard-16") - } - - feature { - id = "kibana" - type = "CloudProfile" - param("agentPushPreset", "") - param("profileId", "kibana") - param("profileServerUrl", "") - param("name", "kibana") - param("total-work-time", "") - param("credentialsType", "key") - param("description", "") - param("next-hour", "") - param("cloud-code", "google") - param("terminate-after-build", "true") - param("terminate-idle-time", "30") - param("enabled", "true") - param("secure:accessKey", "credentialsJSON:447fdd4d-7129-46b7-9822-2e57658c7422") - } + googleCloudProfile(CloudProfile) + features { slackConnection { id = "KIBANA_SLACK" displayName = "Kibana Slack" @@ -106,7 +80,6 @@ fun Kibana(config: KibanaConfiguration = KibanaConfiguration()) : Project { buildType(JestIntegration) } - buildType(ApiServerIntegration) buildType(QuickTests) buildType(AllTests) } @@ -125,6 +98,7 @@ fun Kibana(config: KibanaConfiguration = KibanaConfiguration()) : Project { buildType(OssFirefox) buildType(OssAccessibility) buildType(OssPluginFunctional) + buildType(OssApiServerIntegration) subProject { id("CIGroups") diff --git a/.teamcity/src/templates/DefaultTemplate.kt b/.teamcity/src/templates/DefaultTemplate.kt index 762218b72ab10..1f7f364600e21 100644 --- a/.teamcity/src/templates/DefaultTemplate.kt +++ b/.teamcity/src/templates/DefaultTemplate.kt @@ -1,15 +1,14 @@ package templates +import StandardAgents +import co.elastic.teamcity.common.requireAgent import jetbrains.buildServer.configs.kotlin.v2019_2.Template import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.perfmon object DefaultTemplate : Template({ name = "Default Template" - requirements { - equals("system.cloud.profile_id", "kibana", "RQ_CLOUD_PROFILE_ID") - startsWith("teamcity.agent.name", "kibana-standard-2-", "RQ_AGENT_NAME") - } + requireAgent(StandardAgents["2"]!!) params { param("env.HOME", "/var/lib/jenkins") // TODO once the agent images are sorted out diff --git a/.teamcity/src/templates/KibanaTemplate.kt b/.teamcity/src/templates/KibanaTemplate.kt index 117c30ddb86e3..83fe4fdaa1edd 100644 --- a/.teamcity/src/templates/KibanaTemplate.kt +++ b/.teamcity/src/templates/KibanaTemplate.kt @@ -1,5 +1,7 @@ package templates +import StandardAgents +import co.elastic.teamcity.common.requireAgent import vcs.Kibana import jetbrains.buildServer.configs.kotlin.v2019_2.BuildStep import jetbrains.buildServer.configs.kotlin.v2019_2.ParameterDisplay @@ -21,10 +23,7 @@ object KibanaTemplate : Template({ // checkoutDir = "/dev/shm/%system.teamcity.buildType.id%/%system.build.number%/kibana" } - requirements { - equals("system.cloud.profile_id", "kibana", "RQ_CLOUD_PROFILE_ID") - startsWith("teamcity.agent.name", "kibana-standard-2-", "RQ_AGENT_NAME") - } + requireAgent(StandardAgents["2"]!!) features { perfmon { } @@ -41,7 +40,7 @@ object KibanaTemplate : Template({ } failureConditions { - executionTimeoutMin = 120 + executionTimeoutMin = 160 testFailure = false } diff --git a/.teamcity/tests/projects/KibanaTest.kt b/.teamcity/tests/projects/KibanaTest.kt index 677effec5be65..311c15a1da7cb 100644 --- a/.teamcity/tests/projects/KibanaTest.kt +++ b/.teamcity/tests/projects/KibanaTest.kt @@ -1,5 +1,7 @@ package projects +import jetbrains.buildServer.configs.kotlin.v2019_2.AbsoluteId +import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext import org.junit.Assert.* import org.junit.Test @@ -18,10 +20,11 @@ class KibanaTest { @Test fun test_CloudImages_Exist() { + DslContext.projectId = AbsoluteId("My Project") val project = Kibana(TestConfig) assertTrue(project.features.items.any { - it.type == "CloudImage" && it.params.any { param -> param.name == "network" && param.value == "network"} + it.type == "CloudImage" && it.params.any { param -> param.name == "network" && param.value == "teamcity" } }) } } diff --git a/NOTICE.txt b/NOTICE.txt index bf3cb4aa4ac87..2341a478cbda9 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Kibana source code with Kibana X-Pack source code -Copyright 2012-2020 Elasticsearch B.V. +Copyright 2012-2021 Elasticsearch B.V. --- Pretty handling of logarithmic axes. diff --git a/data/.empty b/data/.empty deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/api/upgrade-assistant.asciidoc b/docs/api/upgrade-assistant.asciidoc index 15d87fbd0dc9d..39d3cb9ecb76b 100644 --- a/docs/api/upgrade-assistant.asciidoc +++ b/docs/api/upgrade-assistant.asciidoc @@ -22,5 +22,6 @@ include::upgrade-assistant/status.asciidoc[] include::upgrade-assistant/reindexing.asciidoc[] include::upgrade-assistant/batch_reindexing.asciidoc[] include::upgrade-assistant/batch_queue.asciidoc[] +include::upgrade-assistant/default-field.asciidoc[] include::upgrade-assistant/check_reindex_status.asciidoc[] include::upgrade-assistant/cancel_reindex.asciidoc[] diff --git a/docs/api/upgrade-assistant/check_reindex_status.asciidoc b/docs/api/upgrade-assistant/check_reindex_status.asciidoc index 98cf263673f73..75aac7b3699f5 100644 --- a/docs/api/upgrade-assistant/check_reindex_status.asciidoc +++ b/docs/api/upgrade-assistant/check_reindex_status.asciidoc @@ -6,8 +6,6 @@ experimental[] Check the status of the reindex operation. -Check the status of the reindex operation. - [[check-reindex-status-request]] ==== Request diff --git a/docs/api/upgrade-assistant/default-field.asciidoc b/docs/api/upgrade-assistant/default-field.asciidoc new file mode 100644 index 0000000000000..8bdcd359d5668 --- /dev/null +++ b/docs/api/upgrade-assistant/default-field.asciidoc @@ -0,0 +1,113 @@ +[[upgrade-assistant-api-default-field]] +=== Add default field API +++++ +Add default field +++++ + +experimental[] In {es} 7.0 and later, some query types, such as Simple Query String, have a limit to the number of fields they can query against. +To configure the cap in {es}, set the `indices.query.bool.max_clause_count` cluster setting, which is 1024 by default. + +For indices with more fields than the cap, add the `index.query.default_field` index setting to inform {es} which +fields to use by default when no field is specified for a query. Use the add default field API to add the `index.query.default_field` setting to an {es} index. + +[[upgrade-assistant-api-default-field-request]] +==== Request + +To add the `index.query.default_field` setting to an {es} index, submit a POST request to `/api/upgrade_assistant/add_query_default_field/`: + +[source,js] +-------------------------------------------------- +GET /api/upgrade_assistant/add_query_default_field/myIndex +{ + "fieldTypes": ["text", "keyword"], <1> + "otherFields": ["myField.*"] <2> +} +-------------------------------------------------- +// KIBANA + +<1> A required array of {es} field types that generate the list of fields. +<2> An optional array of additional field names, dot-deliminated. + +To add the `index.query.default_field` index setting to the specified index, {kib} generates an array of all fields from the index mapping. +The fields contain the types specified in `fieldTypes`. {kib} appends any other fields specified in `otherFields` to the array of default fields. + +[[upgrade-assistant-api-default-field-response-codes]] +==== Response codes + +`200`:: + Indicates a successful call. + + `400`:: + Indicates that the index already has the `index.query.default_field` setting. No changes are made to the index. + +[[upgrade-assistant-api-default-field-response-body]] +==== Response body + +The response body contains a JSON structure, similar to the following: + +[source,js] +-------------------------------------------------- +{ + "acknowledged": true +} +-------------------------------------------------- + +[[upgrade-assistant-api-default-field-example]] +==== Example + +Your index contains following mappings: + +[source,js] +-------------------------------------------------- +GET /myIndex/_mappings +{ + "myIndex": { + "mappings": { + "properties": { + "field1": { "type": "text" }, + "field2": { "type": "float" }, + "nestedfield": { + "properties": { + "field3": { "type": "keyword" }, + "field4": { "type": "long" }, + } + } + } + } + } +} +-------------------------------------------------- +// CONSOLE + +Make the following request to {kib}: + +[source,js] +-------------------------------------------------- +GET /api/upgrade_assistant/add_query_default_field/myIndex +{ + "fieldTypes": ["text", "long"], + "otherFields": ["field2"] +} +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,js] +-------------------------------------------------- +GET /myIndex/_settings?flat_settings=true +{ + "myIndex": { + "settings": { + "index.query.default_field": [ + "field1", + "nestedfield.field4", + "field2", + ] + } + } +} +-------------------------------------------------- +// CONSOLE + +{kib} generates the `field1` and `nestedfield.field4` values based on the specified `fieldTypes`, then appends the `otherFields` to the array. \ No newline at end of file diff --git a/docs/canvas/canvas-share-workpad.asciidoc b/docs/canvas/canvas-share-workpad.asciidoc index f49e2a944c900..0df8357bb3bd6 100644 --- a/docs/canvas/canvas-share-workpad.asciidoc +++ b/docs/canvas/canvas-share-workpad.asciidoc @@ -36,7 +36,7 @@ For more information, refer to <> or a script. -To begin, click *Share > PDF reports > Copy POST URL*. +To begin, click *Share > PDF reports > Advanced options > Copy POST URL*. [role="screenshot"] image::images/canvas-create-URL.gif[Image showing how to create POST URL] diff --git a/docs/canvas/images/canvas-create-URL.gif b/docs/canvas/images/canvas-create-URL.gif index 11327224fc897..60d69cdd599a3 100644 Binary files a/docs/canvas/images/canvas-create-URL.gif and b/docs/canvas/images/canvas-create-URL.gif differ diff --git a/docs/canvas/images/canvas-generate-pdf.gif b/docs/canvas/images/canvas-generate-pdf.gif index 513f6b3b960f9..24711d01fbe0c 100644 Binary files a/docs/canvas/images/canvas-generate-pdf.gif and b/docs/canvas/images/canvas-generate-pdf.gif differ diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index e32984f911d97..d4d2b229eeba7 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -272,7 +272,7 @@ heatmap charts. |{kib-repo}blob/{branch}/src/plugins/vis_type_xy/README.md[visTypeXy] |Contains the new xy-axis chart using the elastic-charts library, which will eventually -replace the vislib xy-axis (bar, area, line) charts. +replace the vislib xy-axis charts including bar, area, and line. |{kib-repo}blob/{branch}/src/plugins/visualizations/README.md[visualizations] diff --git a/docs/development/core/public/kibana-plugin-core-public.app.md b/docs/development/core/public/kibana-plugin-core-public.app.md index 8e8bae5ad9c58..b24ced68b7d38 100644 --- a/docs/development/core/public/kibana-plugin-core-public.app.md +++ b/docs/development/core/public/kibana-plugin-core-public.app.md @@ -24,10 +24,10 @@ export interface App | [exactRoute](./kibana-plugin-core-public.app.exactroute.md) | boolean | If set to true, the application's route will only be checked against an exact match. Defaults to false. | | [icon](./kibana-plugin-core-public.app.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | | [id](./kibana-plugin-core-public.app.id.md) | string | The unique identifier of the application | +| [meta](./kibana-plugin-core-public.app.meta.md) | AppMeta | Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) | | [mount](./kibana-plugin-core-public.app.mount.md) | AppMount<HistoryLocationState> | AppMountDeprecated<HistoryLocationState> | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-core-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-core-public.appmountdeprecated.md). | | [navLinkStatus](./kibana-plugin-core-public.app.navlinkstatus.md) | AppNavLinkStatus | The initial status of the application's navLink. Defaulting to visible if status is accessible and hidden if status is inaccessible See [AppNavLinkStatus](./kibana-plugin-core-public.appnavlinkstatus.md) | | [order](./kibana-plugin-core-public.app.order.md) | number | An ordinal used to sort nav links relative to one another for display. | -| [searchDeepLinks](./kibana-plugin-core-public.app.searchdeeplinks.md) | AppSearchDeepLink[] | Array of links that represent secondary in-app locations for the app. | | [status](./kibana-plugin-core-public.app.status.md) | AppStatus | The initial status of the application. Defaulting to accessible | | [title](./kibana-plugin-core-public.app.title.md) | string | The title of the application. | | [tooltip](./kibana-plugin-core-public.app.tooltip.md) | string | A tooltip shown when hovering over app link. | diff --git a/docs/development/core/public/kibana-plugin-core-public.app.meta.md b/docs/development/core/public/kibana-plugin-core-public.app.meta.md new file mode 100644 index 0000000000000..574fa11605aec --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.app.meta.md @@ -0,0 +1,43 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [meta](./kibana-plugin-core-public.app.meta.md) + +## App.meta property + +Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) + +Signature: + +```typescript +meta?: AppMeta; +``` + +## Remarks + +Used to populate navigational search results (where available). Can be updated using the [App.updater$](./kibana-plugin-core-public.app.updater_.md) observable. See [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) for more details. + +## Example + + +```ts +core.application.register({ + id: 'my_app', + title: 'Translated title', + meta: { + keywords: ['translated keyword1', 'translated keyword2'], + searchDeepLinks: [ + { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, + { + id: 'sub2', + title: 'Sub2', + searchDeepLinks: [ + { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } + ] + } + ], + }, + mount: () => { ... } +}) + +``` + diff --git a/docs/development/core/public/kibana-plugin-core-public.app.searchdeeplinks.md b/docs/development/core/public/kibana-plugin-core-public.app.searchdeeplinks.md deleted file mode 100644 index 667fddbc212a5..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.app.searchdeeplinks.md +++ /dev/null @@ -1,42 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [searchDeepLinks](./kibana-plugin-core-public.app.searchdeeplinks.md) - -## App.searchDeepLinks property - -Array of links that represent secondary in-app locations for the app. - -Signature: - -```typescript -searchDeepLinks?: AppSearchDeepLink[]; -``` - -## Remarks - -Used to populate navigational search results (where available). Can be updated using the [App.updater$](./kibana-plugin-core-public.app.updater_.md) observable. See for more details. - -## Example - -The `path` property on deep links should not include the application's `appRoute`: - -```ts -core.application.register({ - id: 'my_app', - title: 'My App', - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1' }, - { - id: 'sub2', - title: 'Sub2', - searchDeepLinks: [ - { id: 'subsub', title: 'SubSub', path: '/sub2/sub' } - ] - } - ], - mount: () => { ... }, -}) - -``` -Will produce deep links on these paths: - `/app/my_app/sub1` - `/app/my_app/sub2/sub` - diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md new file mode 100644 index 0000000000000..13709df68e76a --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [keywords](./kibana-plugin-core-public.appmeta.keywords.md) + +## AppMeta.keywords property + +Keywords to represent this application + +Signature: + +```typescript +keywords?: string[]; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.md new file mode 100644 index 0000000000000..a2b72f7ec799d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.appmeta.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) + +## AppMeta interface + +Input type for meta data for an application. + +Meta fields include `keywords` and `searchDeepLinks` Keywords is an array of string with which to associate the app, must include at least one unique string as an array. `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. + +Signature: + +```typescript +export interface AppMeta +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [keywords](./kibana-plugin-core-public.appmeta.keywords.md) | string[] | Keywords to represent this application | +| [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) | AppSearchDeepLink[] | Array of links that represent secondary in-app locations for the app. | + diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md new file mode 100644 index 0000000000000..7ec0bbaa4b418 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) + +## AppMeta.searchDeepLinks property + +Array of links that represent secondary in-app locations for the app. + +Signature: + +```typescript +searchDeepLinks?: AppSearchDeepLink[]; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md b/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md index 7e5ccf7d06ed1..29aad675fb105 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md +++ b/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md @@ -17,8 +17,10 @@ export declare type AppSearchDeepLink = { } & ({ path: string; searchDeepLinks?: AppSearchDeepLink[]; + keywords?: string[]; } | { path?: string; searchDeepLinks: AppSearchDeepLink[]; + keywords?: string[]; }); ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md index b6f404c3d11aa..55672d9339f61 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md +++ b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md @@ -9,5 +9,5 @@ Defines the list of fields that can be updated via an [AppUpdater](./kibana-plug Signature: ```typescript -export declare type AppUpdatableFields = Pick; +export declare type AppUpdatableFields = Pick; ``` 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 d73ed716e6b19..fd620d31a1e64 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 @@ -44,6 +44,7 @@ readonly links: { readonly aggs: { readonly date_histogram: string; readonly date_range: string; + readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; @@ -73,6 +74,7 @@ readonly links: { readonly sum: string; readonly top_hits: string; }; + readonly runtimeFields: string; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; @@ -87,6 +89,7 @@ readonly links: { }; readonly addData: string; readonly kibana: string; + readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; @@ -104,5 +107,13 @@ readonly links: { readonly ml: Record; readonly transforms: Record; readonly visualize: Record; + readonly apis: Record; + readonly observability: Record; + readonly alerting: Record; + readonly maps: Record; + readonly monitoring: Record; + readonly security: Record; + readonly watcher: Record; + readonly ccs: Record; }; ``` 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 7aa170eef9b50..3ad747a42f84e 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 dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly date_histogram: string;
readonly date_range: 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 scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly eql: string;
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
} | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
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: string;
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly elasticsearch: Record<string, string>;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly eql: string;
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
readonly apis: Record<string, string>;
readonly observability: Record<string, string>;
readonly alerting: Record<string, string>;
readonly maps: Record<string, string>;
readonly monitoring: Record<string, string>;
readonly security: Record<string, string>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
} | | diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index da19377054499..7f671d9edcd86 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -37,6 +37,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AppLeaveDefaultAction](./kibana-plugin-core-public.appleavedefaultaction.md) | Action to return from a [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md) to execute the default behaviour when leaving the application.See | | [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) | | | [ApplicationStart](./kibana-plugin-core-public.applicationstart.md) | | +| [AppMeta](./kibana-plugin-core-public.appmeta.md) | Input type for meta data for an application.Meta fields include keywords and searchDeepLinks Keywords is an array of string with which to associate the app, must include at least one unique string as an array. searchDeepLinks is an array of links that represent secondary in-app locations for the app. | | [AppMountContext](./kibana-plugin-core-public.appmountcontext.md) | The context object received when applications are mounted to the DOM. Deprecated, use [CoreSetup.getStartServices](./kibana-plugin-core-public.coresetup.getstartservices.md). | | [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) | | | [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | @@ -164,6 +165,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [PluginInitializer](./kibana-plugin-core-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | | [PluginOpaqueId](./kibana-plugin-core-public.pluginopaqueid.md) | | | [PublicAppInfo](./kibana-plugin-core-public.publicappinfo.md) | Public information about a registered [application](./kibana-plugin-core-public.app.md) | +| [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) | Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) | | [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) | Public information about a registered app's [searchDeepLinks](./kibana-plugin-core-public.appsearchdeeplink.md) | | [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. | | [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md index d56b0ac58cd9b..9f45a06935fe4 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md @@ -9,10 +9,10 @@ Public information about a registered [application](./kibana-plugin-core-public. Signature: ```typescript -export declare type PublicAppInfo = Omit & { +export declare type PublicAppInfo = Omit & { status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + meta: PublicAppMetaInfo; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md new file mode 100644 index 0000000000000..3ef0460aec467 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) + +## PublicAppMetaInfo type + +Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) + +Signature: + +```typescript +export declare type PublicAppMetaInfo = Omit & { + keywords: string[]; + searchDeepLinks: PublicAppSearchDeepLinkInfo[]; +}; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md index 9814f0408d047..e88cdb7d55edd 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md @@ -9,7 +9,8 @@ Public information about a registered app's [searchDeepLinks](./kibana-plugin-co Signature: ```typescript -export declare type PublicAppSearchDeepLinkInfo = Omit & { +export declare type PublicAppSearchDeepLinkInfo = Omit & { searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + keywords: string[]; }; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.capabilitiessetup.registerswitcher.md b/docs/development/core/server/kibana-plugin-core-server.capabilitiessetup.registerswitcher.md index d0fd524f3234f..715f15ec812a3 100644 --- a/docs/development/core/server/kibana-plugin-core-server.capabilitiessetup.registerswitcher.md +++ b/docs/development/core/server/kibana-plugin-core-server.capabilitiessetup.registerswitcher.md @@ -31,7 +31,19 @@ How to restrict some capabilities ```ts // my-plugin/server/plugin.ts public setup(core: CoreSetup, deps: {}) { - core.capabilities.registerSwitcher((request, capabilities) => { + core.capabilities.registerSwitcher((request, capabilities, useDefaultCapabilities) => { + // useDefaultCapabilities is a special case that switchers typically don't have to concern themselves with. + // The default capabilities are typically the ones you provide in your CapabilitiesProvider, but this flag + // gives each switcher an opportunity to change the default capabilities of other plugins' capabilities. + // For example, you may decide to flip another plugin's capability to false if today is Tuesday, + // but you wouldn't want to do this when we are requesting the default set of capabilities. + if (useDefaultCapabilities) { + return { + somePlugin: { + featureEnabledByDefault: true + } + } + } if(myPluginApi.shouldRestrictSomePluginBecauseOf(request)) { return { somePlugin: { diff --git a/docs/development/core/server/kibana-plugin-core-server.capabilitiesswitcher.md b/docs/development/core/server/kibana-plugin-core-server.capabilitiesswitcher.md index 01aa3a32c9abb..e6a0a9a096671 100644 --- a/docs/development/core/server/kibana-plugin-core-server.capabilitiesswitcher.md +++ b/docs/development/core/server/kibana-plugin-core-server.capabilitiesswitcher.md @@ -9,5 +9,5 @@ See [CapabilitiesSetup](./kibana-plugin-core-server.capabilitiessetup.md) Signature: ```typescript -export declare type CapabilitiesSwitcher = (request: KibanaRequest, uiCapabilities: Capabilities) => Partial | Promise>; +export declare type CapabilitiesSwitcher = (request: KibanaRequest, uiCapabilities: Capabilities, useDefaultCapabilities: boolean) => Partial | Promise>; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md index 40fc1a8e05a68..7c53356615ee9 100644 --- a/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md +++ b/docs/development/core/server/kibana-plugin-core-server.legacyelasticsearcherror.md @@ -9,7 +9,7 @@ Signature: ```typescript -export interface LegacyElasticsearchError extends Boom +export interface LegacyElasticsearchError extends Boom.Boom ``` ## Properties diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.apply_filter_trigger.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.apply_filter_trigger.md new file mode 100644 index 0000000000000..aaed18b3b8890 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.apply_filter_trigger.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [APPLY\_FILTER\_TRIGGER](./kibana-plugin-plugins-data-public.apply_filter_trigger.md) + +## APPLY\_FILTER\_TRIGGER variable + +Signature: + +```typescript +APPLY_FILTER_TRIGGER = "FILTER_TRIGGER" +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md index 027ae4209b77f..dbeeeb9979aae 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md @@ -7,5 +7,5 @@ Signature: ```typescript -embeddable?: IEmbeddable; +embeddable?: unknown; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md index 62817cd0a1e33..2f844b6844645 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md @@ -14,7 +14,7 @@ export interface ApplyGlobalFilterActionContext | Property | Type | Description | | --- | --- | --- | -| [embeddable](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md) | IEmbeddable | | +| [embeddable](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md) | unknown | | | [filters](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md) | Filter[] | | | [timeFieldName](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md) | string | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.allownoindex.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.allownoindex.md new file mode 100644 index 0000000000000..5e397d11b0a89 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.allownoindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [allowNoIndex](./kibana-plugin-plugins-data-public.indexpattern.allownoindex.md) + +## IndexPattern.allowNoIndex property + +prevents errors when index pattern exists before indices + +Signature: + +```typescript +readonly allowNoIndex: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.getassavedobjectbody.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.getassavedobjectbody.md index a370341000960..b318427012c0a 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.getassavedobjectbody.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.getassavedobjectbody.md @@ -19,6 +19,7 @@ getAsSavedObjectBody(): { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }; ``` Returns: @@ -33,5 +34,6 @@ getAsSavedObjectBody(): { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md index 179148265e68d..b640ef1b89606 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md @@ -20,6 +20,7 @@ export declare class IndexPattern implements IIndexPattern | Property | Modifiers | Type | Description | | --- | --- | --- | --- | +| [allowNoIndex](./kibana-plugin-plugins-data-public.indexpattern.allownoindex.md) | | boolean | prevents errors when index pattern exists before indices | | [deleteFieldFormat](./kibana-plugin-plugins-data-public.indexpattern.deletefieldformat.md) | | (fieldName: string) => void | | | [fieldAttrs](./kibana-plugin-plugins-data-public.indexpattern.fieldattrs.md) | | FieldAttrs | | | [fieldFormatMap](./kibana-plugin-plugins-data-public.indexpattern.fieldformatmap.md) | | Record<string, any> | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.allownoindex.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.allownoindex.md new file mode 100644 index 0000000000000..9438f38194493 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.allownoindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternAttributes](./kibana-plugin-plugins-data-public.indexpatternattributes.md) > [allowNoIndex](./kibana-plugin-plugins-data-public.indexpatternattributes.allownoindex.md) + +## IndexPatternAttributes.allowNoIndex property + +prevents errors when index pattern exists before indices + +Signature: + +```typescript +allowNoIndex?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.md index c5ea38278e820..1bbede5658942 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternattributes.md @@ -14,6 +14,7 @@ export interface IndexPatternAttributes | Property | Type | Description | | --- | --- | --- | +| [allowNoIndex](./kibana-plugin-plugins-data-public.indexpatternattributes.allownoindex.md) | boolean | prevents errors when index pattern exists before indices | | [fieldAttrs](./kibana-plugin-plugins-data-public.indexpatternattributes.fieldattrs.md) | string | | | [fieldFormatMap](./kibana-plugin-plugins-data-public.indexpatternattributes.fieldformatmap.md) | string | | | [fields](./kibana-plugin-plugins-data-public.indexpatternattributes.fields.md) | string | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.allownoindex.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.allownoindex.md new file mode 100644 index 0000000000000..50adef8268694 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.allownoindex.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternSpec](./kibana-plugin-plugins-data-public.indexpatternspec.md) > [allowNoIndex](./kibana-plugin-plugins-data-public.indexpatternspec.allownoindex.md) + +## IndexPatternSpec.allowNoIndex property + +Signature: + +```typescript +allowNoIndex?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.md index 06917fcac1b4d..9357ad7d5077e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternspec.md @@ -14,6 +14,7 @@ export interface IndexPatternSpec | Property | Type | Description | | --- | --- | --- | +| [allowNoIndex](./kibana-plugin-plugins-data-public.indexpatternspec.allownoindex.md) | boolean | | | [fieldAttrs](./kibana-plugin-plugins-data-public.indexpatternspec.fieldattrs.md) | FieldAttrs | | | [fieldFormats](./kibana-plugin-plugins-data-public.indexpatternspec.fieldformats.md) | Record<string, SerializedFieldFormat> | | | [fields](./kibana-plugin-plugins-data-public.indexpatternspec.fields.md) | IndexPatternFieldMap | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 8de3821161ab4..2040043d4351b 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -102,6 +102,7 @@ | [ACTION\_GLOBAL\_APPLY\_FILTER](./kibana-plugin-plugins-data-public.action_global_apply_filter.md) | | | [AggGroupLabels](./kibana-plugin-plugins-data-public.agggrouplabels.md) | | | [AggGroupNames](./kibana-plugin-plugins-data-public.agggroupnames.md) | | +| [APPLY\_FILTER\_TRIGGER](./kibana-plugin-plugins-data-public.apply_filter_trigger.md) | | | [baseFormattersPublic](./kibana-plugin-plugins-data-public.baseformatterspublic.md) | | | [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string | | [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 1ed6059c23062..20181a5208b52 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters @@ -15,7 +15,7 @@ setup(core: CoreSetup, { bfetch, e | Parameter | Type | Description | | --- | --- | --- | | core | CoreSetup<DataStartDependencies, DataPublicPluginStart> | | -| { bfetch, expressions, uiActions, usageCollection } | DataSetupDependencies | | +| { bfetch, expressions, uiActions, usageCollection, inspector } | DataSetupDependencies | | Returns: diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.allownoindex.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.allownoindex.md new file mode 100644 index 0000000000000..fe7bec70196c8 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.allownoindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IndexPattern](./kibana-plugin-plugins-data-server.indexpattern.md) > [allowNoIndex](./kibana-plugin-plugins-data-server.indexpattern.allownoindex.md) + +## IndexPattern.allowNoIndex property + +prevents errors when index pattern exists before indices + +Signature: + +```typescript +readonly allowNoIndex: boolean; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.getassavedobjectbody.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.getassavedobjectbody.md index 274a475872b0b..7d70af4b535fe 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.getassavedobjectbody.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.getassavedobjectbody.md @@ -19,6 +19,7 @@ getAsSavedObjectBody(): { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }; ``` Returns: @@ -33,5 +34,6 @@ getAsSavedObjectBody(): { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.md index b2cb217fecaa2..54f020e57cf4a 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpattern.md @@ -20,6 +20,7 @@ export declare class IndexPattern implements IIndexPattern | Property | Modifiers | Type | Description | | --- | --- | --- | --- | +| [allowNoIndex](./kibana-plugin-plugins-data-server.indexpattern.allownoindex.md) | | boolean | prevents errors when index pattern exists before indices | | [deleteFieldFormat](./kibana-plugin-plugins-data-server.indexpattern.deletefieldformat.md) | | (fieldName: string) => void | | | [fieldAttrs](./kibana-plugin-plugins-data-server.indexpattern.fieldattrs.md) | | FieldAttrs | | | [fieldFormatMap](./kibana-plugin-plugins-data-server.indexpattern.fieldformatmap.md) | | Record<string, any> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.allownoindex.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.allownoindex.md new file mode 100644 index 0000000000000..1255a6fe9f0ca --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.allownoindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) > [allowNoIndex](./kibana-plugin-plugins-data-server.indexpatternattributes.allownoindex.md) + +## IndexPatternAttributes.allowNoIndex property + +prevents errors when index pattern exists before indices + +Signature: + +```typescript +allowNoIndex?: boolean; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.md index 6559b4d7110be..b9b9f955c7ab5 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternattributes.md @@ -14,6 +14,7 @@ export interface IndexPatternAttributes | Property | Type | Description | | --- | --- | --- | +| [allowNoIndex](./kibana-plugin-plugins-data-server.indexpatternattributes.allownoindex.md) | boolean | prevents errors when index pattern exists before indices | | [fieldAttrs](./kibana-plugin-plugins-data-server.indexpatternattributes.fieldattrs.md) | string | | | [fieldFormatMap](./kibana-plugin-plugins-data-server.indexpatternattributes.fieldformatmap.md) | string | | | [fields](./kibana-plugin-plugins-data-server.indexpatternattributes.fields.md) | string | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.extend.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.extend.md new file mode 100644 index 0000000000000..65e3c2868f29f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.extend.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) > [extend](./kibana-plugin-plugins-data-server.isearchstrategy.extend.md) + +## ISearchStrategy.extend property + +Signature: + +```typescript +extend?: (id: string, keepAlive: string, options: ISearchOptions, deps: SearchStrategyDependencies) => Promise; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md index c9f4c886735a7..c46a580d5ceb8 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md @@ -17,5 +17,6 @@ export interface ISearchStrategy(id: string, options: ISearchOptions, deps: SearchStrategyDependencies) => Promise<void> | | +| [extend](./kibana-plugin-plugins-data-server.isearchstrategy.extend.md) | (id: string, keepAlive: string, options: ISearchOptions, deps: SearchStrategyDependencies) => Promise<void> | | | [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | (request: SearchStrategyRequest, options: ISearchOptions, deps: SearchStrategyDependencies) => Observable<SearchStrategyResponse> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index b90018c3d9cdd..bd90f23b4ab59 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -11,7 +11,7 @@ setup(core: CoreSetup, { bfetch, e __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }; ``` @@ -29,7 +29,7 @@ setup(core: CoreSetup, { bfetch, e __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 8a3dbe5a6350c..88f85eb7a7d05 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -12,7 +12,7 @@ start(core: CoreStart): { fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -31,7 +31,7 @@ start(core: CoreStart): { fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md deleted file mode 100644 index 0ddbcb3546d1e..0000000000000 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [Adapters](./kibana-plugin-plugins-embeddable-public.adapters.md) > [data](./kibana-plugin-plugins-embeddable-public.adapters.data.md) - -## Adapters.data property - -Signature: - -```typescript -data?: DataAdapter; -``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md index 47484dc79d88c..8ba759e333fa3 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md @@ -16,6 +16,5 @@ export interface Adapters | Property | Type | Description | | --- | --- | --- | -| [data](./kibana-plugin-plugins-embeddable-public.adapters.data.md) | DataAdapter | | | [requests](./kibana-plugin-plugins-embeddable-public.adapters.requests.md) | RequestAdapter | | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.contextmenutrigger.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.contextmenutrigger.md index 0a88e1e0a2ea8..eec1e9ac7e3fb 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.contextmenutrigger.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.contextmenutrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> +contextMenuTrigger: Trigger ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.supportedtriggers.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.supportedtriggers.md index 16676bc732b1c..8a5efe60ba411 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.supportedtriggers.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.supportedtriggers.md @@ -7,9 +7,9 @@ Signature: ```typescript -supportedTriggers(): Array; +supportedTriggers(): string[]; ``` Returns: -`Array` +`string[]` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md index 06e51958a2d1e..92926d10a543c 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md @@ -7,5 +7,5 @@ Signature: ```typescript -embeddable: IEmbeddable; +embeddable: T; ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.md index a2c2d9245eabe..753a3ff2ec6ec 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablecontext.md @@ -7,12 +7,12 @@ Signature: ```typescript -export interface EmbeddableContext +export interface EmbeddableContext ``` ## Properties | Property | Type | Description | | --- | --- | --- | -| [embeddable](./kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md) | IEmbeddable | | +| [embeddable](./kibana-plugin-plugins-embeddable-public.embeddablecontext.embeddable.md) | T | | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md index f36f7b4ee77a4..07ede291e33d2 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md @@ -16,9 +16,7 @@ export declare type EmbeddableInput = { enhancements?: SerializableState; disabledActions?: string[]; disableTriggers?: boolean; - timeRange?: TimeRange; - query?: Query; - filters?: Filter[]; searchSessionId?: string; + syncColors?: boolean; }; ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.data.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.data.md deleted file mode 100644 index d3a62657372ac..0000000000000 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.data.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableSetupDependencies](./kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.md) > [data](./kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.data.md) - -## EmbeddableSetupDependencies.data property - -Signature: - -```typescript -data: DataPublicPluginSetup; -``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.md index fdd31ca75be2a..957e3f279ff60 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.md @@ -14,6 +14,5 @@ export interface EmbeddableSetupDependencies | Property | Type | Description | | --- | --- | --- | -| [data](./kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.data.md) | DataPublicPluginSetup | | | [uiActions](./kibana-plugin-plugins-embeddable-public.embeddablesetupdependencies.uiactions.md) | UiActionsSetup | | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.data.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.data.md deleted file mode 100644 index 0595609b11e49..0000000000000 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.data.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableStartDependencies](./kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.md) > [data](./kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.data.md) - -## EmbeddableStartDependencies.data property - -Signature: - -```typescript -data: DataPublicPluginStart; -``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.md index 5a1b5d1e06861..342163ed2e413 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.md @@ -14,7 +14,6 @@ export interface EmbeddableStartDependencies | Property | Type | Description | | --- | --- | --- | -| [data](./kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.data.md) | DataPublicPluginStart | | | [inspector](./kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.inspector.md) | InspectorStart | | | [uiActions](./kibana-plugin-plugins-embeddable-public.embeddablestartdependencies.uiactions.md) | UiActionsStart | | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md index 276499b435e1f..77e9c2d00b2dd 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md @@ -9,7 +9,7 @@ Constructs a new instance of the `EmbeddableStateTransfer` class Signature: ```typescript -constructor(navigateToApp: ApplicationStart['navigateToApp'], appList?: ReadonlyMap | undefined, customStorage?: Storage); +constructor(navigateToApp: ApplicationStart['navigateToApp'], currentAppId$: ApplicationStart['currentAppId$'], appList?: ReadonlyMap | undefined, customStorage?: Storage); ``` ## Parameters @@ -17,6 +17,7 @@ constructor(navigateToApp: ApplicationStart['navigateToApp'], appList?: Readonly | Parameter | Type | Description | | --- | --- | --- | | navigateToApp | ApplicationStart['navigateToApp'] | | +| currentAppId$ | ApplicationStart['currentAppId$'] | | | appList | ReadonlyMap<string, PublicAppInfo> | undefined | | | customStorage | Storage | | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.istransferinprogress.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.istransferinprogress.md new file mode 100644 index 0000000000000..f00d015f316d2 --- /dev/null +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.istransferinprogress.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableStateTransfer](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.md) > [isTransferInProgress](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.istransferinprogress.md) + +## EmbeddableStateTransfer.isTransferInProgress property + +Signature: + +```typescript +isTransferInProgress: boolean; +``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.md index 3676b744b8cc9..76b6708b93bd1 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.md @@ -16,13 +16,14 @@ export declare class EmbeddableStateTransfer | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(navigateToApp, appList, customStorage)](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md) | | Constructs a new instance of the EmbeddableStateTransfer class | +| [(constructor)(navigateToApp, currentAppId$, appList, customStorage)](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer._constructor_.md) | | Constructs a new instance of the EmbeddableStateTransfer class | ## Properties | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [getAppNameFromId](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.getappnamefromid.md) | | (appId: string) => string | undefined | Fetches an internationalized app title when given an appId. | +| [isTransferInProgress](./kibana-plugin-plugins-embeddable-public.embeddablestatetransfer.istransferinprogress.md) | | boolean | | ## Methods diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iembeddable.supportedtriggers.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iembeddable.supportedtriggers.md index 5480f3b246648..bb560c11bf440 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iembeddable.supportedtriggers.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iembeddable.supportedtriggers.md @@ -9,9 +9,9 @@ List of triggers that this embeddable will execute. Signature: ```typescript -supportedTriggers(): Array; +supportedTriggers(): string[]; ``` Returns: -`Array` +`string[]` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md index 62610624655a1..2f5966f9ba940 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md @@ -7,5 +7,5 @@ Signature: ```typescript -isContextMenuTriggerContext: (context: unknown) => context is EmbeddableContext +isContextMenuTriggerContext: (context: unknown) => context is EmbeddableContext> ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.md index a6aeba23cd280..b875b1fce4288 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.md @@ -86,6 +86,8 @@ | [PANEL\_NOTIFICATION\_TRIGGER](./kibana-plugin-plugins-embeddable-public.panel_notification_trigger.md) | | | [panelBadgeTrigger](./kibana-plugin-plugins-embeddable-public.panelbadgetrigger.md) | | | [panelNotificationTrigger](./kibana-plugin-plugins-embeddable-public.panelnotificationtrigger.md) | | +| [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-embeddable-public.select_range_trigger.md) | | +| [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-embeddable-public.value_click_trigger.md) | | | [withEmbeddableSubscription](./kibana-plugin-plugins-embeddable-public.withembeddablesubscription.md) | | ## Type Aliases diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.openaddpanelflyout.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.openaddpanelflyout.md index ce97f79b4beb9..add4646375359 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.openaddpanelflyout.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.openaddpanelflyout.md @@ -14,7 +14,7 @@ export declare function openAddPanelFlyout(options: { overlays: OverlayStart; notifications: NotificationsStart; SavedObjectFinder: React.ComponentType; -}): Promise; +}): OverlayRef; ``` ## Parameters @@ -25,5 +25,5 @@ export declare function openAddPanelFlyout(options: { Returns: -`Promise` +`OverlayRef` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelbadgetrigger.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelbadgetrigger.md index f6113c93a1c66..feacd0152d384 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelbadgetrigger.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelbadgetrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> +panelBadgeTrigger: Trigger ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelnotificationtrigger.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelnotificationtrigger.md index df606c11f64ce..c831df19d2959 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelnotificationtrigger.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.panelnotificationtrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'> +panelNotificationTrigger: Trigger ``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.select_range_trigger.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.select_range_trigger.md new file mode 100644 index 0000000000000..175e3fe947a0f --- /dev/null +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.select_range_trigger.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-embeddable-public.select_range_trigger.md) + +## SELECT\_RANGE\_TRIGGER variable + +Signature: + +```typescript +SELECT_RANGE_TRIGGER = "SELECT_RANGE_TRIGGER" +``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.value_click_trigger.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.value_click_trigger.md new file mode 100644 index 0000000000000..a85be3142d0f2 --- /dev/null +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.value_click_trigger.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-embeddable-public.value_click_trigger.md) + +## VALUE\_CLICK\_TRIGGER variable + +Signature: + +```typescript +VALUE_CLICK_TRIGGER = "VALUE_CLICK_TRIGGER" +``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md index 1565202e84674..9dfad91c33679 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md @@ -9,7 +9,7 @@ Constructs a new instance of the `ExpressionRenderHandler` class Signature: ```typescript -constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActions, }?: ExpressionRenderHandlerParams); +constructor(element: HTMLElement, { onRenderError, renderMode, syncColors, hasCompatibleActions, }?: ExpressionRenderHandlerParams); ``` ## Parameters @@ -17,5 +17,5 @@ constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActi | Parameter | Type | Description | | --- | --- | --- | | element | HTMLElement | | -| { onRenderError, renderMode, hasCompatibleActions, } | ExpressionRenderHandlerParams | | +| { onRenderError, renderMode, syncColors, hasCompatibleActions, } | ExpressionRenderHandlerParams | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler.md index d65c06bdaed83..1a7050f3ffd4e 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderhandler.md @@ -14,7 +14,7 @@ export declare class ExpressionRenderHandler | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(element, { onRenderError, renderMode, hasCompatibleActions, })](./kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md) | | Constructs a new instance of the ExpressionRenderHandler class | +| [(constructor)(element, { onRenderError, renderMode, syncColors, hasCompatibleActions, })](./kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md) | | Constructs a new instance of the ExpressionRenderHandler class | ## Properties diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md index 22a73fff039e6..4ef1225ae0d7e 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md @@ -25,6 +25,7 @@ export interface IExpressionLoaderParams | [renderMode](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.rendermode.md) | RenderMode | | | [searchContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md) | SerializableState | | | [searchSessionId](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchsessionid.md) | string | | +| [syncColors](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md) | boolean | | | [uiState](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.uistate.md) | unknown | | | [variables](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.variables.md) | Record<string, any> | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md new file mode 100644 index 0000000000000..619f54ad88ef2 --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [IExpressionLoaderParams](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md) > [syncColors](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md) + +## IExpressionLoaderParams.syncColors property + +Signature: + +```typescript +syncColors?: boolean; +``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md new file mode 100644 index 0000000000000..6cdc796bf464b --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [IInterpreterRenderHandlers](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md) > [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md) + +## IInterpreterRenderHandlers.isSyncColorsEnabled property + +Signature: + +```typescript +isSyncColorsEnabled: () => boolean; +``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md index 931e474a41006..0b39a9b4b3ea2 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md @@ -18,8 +18,9 @@ export interface IInterpreterRenderHandlers | [event](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.event.md) | (event: any) => void | | | [getRenderMode](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.getrendermode.md) | () => RenderMode | | | [hasCompatibleActions](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.hascompatibleactions.md) | (event: any) => Promise<boolean> | | +| [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md) | () => boolean | | | [onDestroy](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.ondestroy.md) | (fn: () => void) => void | | | [reload](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.reload.md) | () => void | | -| [uiState](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md) | PersistedState | | +| [uiState](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md) | unknown | This uiState interface is actually PersistedState from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. | | [update](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.update.md) | (params: any) => void | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md index 8d74c8e555fee..461bf861d4d5e 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md @@ -4,8 +4,10 @@ ## IInterpreterRenderHandlers.uiState property +This uiState interface is actually `PersistedState` from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. + Signature: ```typescript -uiState?: PersistedState; +uiState?: unknown; ``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md index a03ea32482011..1b97c9e11f83c 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md @@ -20,6 +20,7 @@ | [ExpressionsService](./kibana-plugin-plugins-expressions-public.expressionsservice.md) | ExpressionsService class is used for multiple purposes:1. It implements the same Expressions service that can be used on both: (1) server-side and (2) browser-side. 2. It implements the same Expressions service that users can fork/clone, thus have their own instance of the Expressions plugin. 3. ExpressionsService defines the public contracts of \*setup\* and \*start\* Kibana Platform life-cycles for ease-of-use on server-side and browser-side. 4. ExpressionsService creates a bound version of all exported contract functions. 5. Functions are bound the way there are:\`\`\`ts registerFunction = (...args: Parameters<Executor\['registerFunction'\]> ): ReturnType<Executor\['registerFunction'\]> => this.executor.registerFunction(...args); \`\`\`so that JSDoc appears in developers IDE when they use those plugins.expressions.registerFunction(. | | [ExpressionType](./kibana-plugin-plugins-expressions-public.expressiontype.md) | | | [FunctionsRegistry](./kibana-plugin-plugins-expressions-public.functionsregistry.md) | | +| [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) | | | [TypesRegistry](./kibana-plugin-plugins-expressions-public.typesregistry.md) | | ## Enumerations diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md new file mode 100644 index 0000000000000..281f48918416b --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) > [logDatatable](./kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md) + +## TablesAdapter.logDatatable() method + +Signature: + +```typescript +logDatatable(name: string, datatable: Datatable): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | | +| datatable | Datatable | | + +Returns: + +`void` + diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md new file mode 100644 index 0000000000000..c489eff4cc252 --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) + +## TablesAdapter class + +Signature: + +```typescript +export declare class TablesAdapter extends EventEmitter +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [tables](./kibana-plugin-plugins-expressions-public.tablesadapter.tables.md) | | {
[key: string]: Datatable;
} | | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [logDatatable(name, datatable)](./kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md) | | | + diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md new file mode 100644 index 0000000000000..ef5ada66e50b3 --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) > [tables](./kibana-plugin-plugins-expressions-public.tablesadapter.tables.md) + +## TablesAdapter.tables property + +Signature: + +```typescript +get tables(): { + [key: string]: Datatable; + }; +``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md new file mode 100644 index 0000000000000..71a7e020e65a5 --- /dev/null +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [IInterpreterRenderHandlers](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md) > [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md) + +## IInterpreterRenderHandlers.isSyncColorsEnabled property + +Signature: + +```typescript +isSyncColorsEnabled: () => boolean; +``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md index 273703cacca06..831c9023c7e48 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md @@ -18,8 +18,9 @@ export interface IInterpreterRenderHandlers | [event](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.event.md) | (event: any) => void | | | [getRenderMode](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.getrendermode.md) | () => RenderMode | | | [hasCompatibleActions](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.hascompatibleactions.md) | (event: any) => Promise<boolean> | | +| [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md) | () => boolean | | | [onDestroy](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.ondestroy.md) | (fn: () => void) => void | | | [reload](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.reload.md) | () => void | | -| [uiState](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md) | PersistedState | | +| [uiState](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md) | unknown | This uiState interface is actually PersistedState from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. | | [update](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.update.md) | (params: any) => void | | diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md index b09433c6454ad..ca1c8eec8c2f7 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md @@ -4,8 +4,10 @@ ## IInterpreterRenderHandlers.uiState property +This uiState interface is actually `PersistedState` from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. + Signature: ```typescript -uiState?: PersistedState; +uiState?: unknown; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.md index 19af63a679de8..d8e527debcc4e 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface Action extends Partial>> +export interface Action extends Partial>> ``` ## Properties @@ -17,7 +17,7 @@ export interface Action extend | [id](./kibana-plugin-plugins-ui_actions-public.action.id.md) | string | A unique identifier for this action instance. | | [MenuItem](./kibana-plugin-plugins-ui_actions-public.action.menuitem.md) | UiComponent<{
context: ActionExecutionContext<Context>;
}> | UiComponent to render when displaying this action as a context menu item. If not provided, getDisplayName will be used instead. | | [order](./kibana-plugin-plugins-ui_actions-public.action.order.md) | number | Determined the order when there is more than one action matched to a trigger. Higher numbers are displayed first. | -| [type](./kibana-plugin-plugins-ui_actions-public.action.type.md) | T | The action type is what determines the context shape. | +| [type](./kibana-plugin-plugins-ui_actions-public.action.type.md) | string | The action type is what determines the context shape. | ## Methods diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.type.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.type.md index c423df9d1324c..6905f3deb441d 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.type.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.action.type.md @@ -9,5 +9,5 @@ The action type is what determines the context shape. Signature: ```typescript -readonly type: T; +readonly type: string; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionbytype.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionbytype.md deleted file mode 100644 index 3ceb96adadb1a..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionbytype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionByType](./kibana-plugin-plugins-ui_actions-public.actionbytype.md) - -## ActionByType type - -Signature: - -```typescript -export declare type ActionByType = Action; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.__.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.__.md deleted file mode 100644 index eb7b1e5954ed2..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.__.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) > [""](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.__.md) - -## ActionContextMapping."" property - -Signature: - -```typescript -[DEFAULT_ACTION]: BaseContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_field.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_field.md deleted file mode 100644 index eb0547bbf8261..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_field.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) > [ACTION\_VISUALIZE\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_field.md) - -## ActionContextMapping.ACTION\_VISUALIZE\_FIELD property - -Signature: - -```typescript -[ACTION_VISUALIZE_FIELD]: VisualizeFieldContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_geo_field.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_geo_field.md deleted file mode 100644 index b44ed75106423..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_geo_field.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) > [ACTION\_VISUALIZE\_GEO\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_geo_field.md) - -## ActionContextMapping.ACTION\_VISUALIZE\_GEO\_FIELD property - -Signature: - -```typescript -[ACTION_VISUALIZE_GEO_FIELD]: VisualizeFieldContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_lens_field.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_lens_field.md deleted file mode 100644 index 96370a07806d3..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_lens_field.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) > [ACTION\_VISUALIZE\_LENS\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_lens_field.md) - -## ActionContextMapping.ACTION\_VISUALIZE\_LENS\_FIELD property - -Signature: - -```typescript -[ACTION_VISUALIZE_LENS_FIELD]: VisualizeFieldContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md deleted file mode 100644 index f83632dea0aa9..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) - -## ActionContextMapping interface - -Signature: - -```typescript -export interface ActionContextMapping -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [""](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.__.md) | BaseContext | | -| [ACTION\_VISUALIZE\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_field.md) | VisualizeFieldContext | | -| [ACTION\_VISUALIZE\_GEO\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_geo_field.md) | VisualizeFieldContext | | -| [ACTION\_VISUALIZE\_LENS\_FIELD](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.action_visualize_lens_field.md) | VisualizeFieldContext | | - diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiondefinitionbytype.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiondefinitionbytype.md deleted file mode 100644 index ba4dc39088fe4..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiondefinitionbytype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionDefinitionByType](./kibana-plugin-plugins-ui_actions-public.actiondefinitionbytype.md) - -## ActionDefinitionByType type - -Signature: - -```typescript -export declare type ActionDefinitionByType = ActionDefinition; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionexecutioncontext.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionexecutioncontext.md index 3271d86779959..d6f754a1ba458 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionexecutioncontext.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actionexecutioncontext.md @@ -9,5 +9,5 @@ Action methods are executed with Context from trigger + [ActionExecutionMeta](./ Signature: ```typescript -export declare type ActionExecutionContext = Context & ActionExecutionMeta; +export declare type ActionExecutionContext = Context & ActionExecutionMeta; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiontype.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiontype.md deleted file mode 100644 index 4916585531004..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.actiontype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [ActionType](./kibana-plugin-plugins-ui_actions-public.actiontype.md) - -## ActionType type - -Signature: - -```typescript -export declare type ActionType = keyof ActionContextMapping; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.apply_filter_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.apply_filter_trigger.md deleted file mode 100644 index 94e66bf404f5c..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.apply_filter_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [APPLY\_FILTER\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.apply_filter_trigger.md) - -## APPLY\_FILTER\_TRIGGER variable - -Signature: - -```typescript -APPLY_FILTER_TRIGGER = "FILTER_TRIGGER" -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.applyfiltertrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.applyfiltertrigger.md deleted file mode 100644 index e1fb6d342457e..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.applyfiltertrigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [applyFilterTrigger](./kibana-plugin-plugins-ui_actions-public.applyfiltertrigger.md) - -## applyFilterTrigger variable - -Signature: - -```typescript -applyFilterTrigger: Trigger<'FILTER_TRIGGER'> -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.createaction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.createaction.md index 04ab36c2e3f58..8bb9094a1d8bf 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.createaction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.createaction.md @@ -7,16 +7,16 @@ Signature: ```typescript -export declare function createAction(action: ActionDefinitionByType): ActionByType; +export declare function createAction(action: ActionDefinition): Action; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| action | ActionDefinitionByType<T> | | +| action | ActionDefinition<Context> | | Returns: -`ActionByType` +`Action` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.md index fd1ea7df4fb74..9f009d1617cc8 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.md @@ -24,11 +24,9 @@ | Interface | Description | | --- | --- | | [Action](./kibana-plugin-plugins-ui_actions-public.action.md) | | -| [ActionContextMapping](./kibana-plugin-plugins-ui_actions-public.actioncontextmapping.md) | | | [ActionExecutionMeta](./kibana-plugin-plugins-ui_actions-public.actionexecutionmeta.md) | During action execution we can provide additional information, for example, trigger, that caused the action execution | | [RowClickContext](./kibana-plugin-plugins-ui_actions-public.rowclickcontext.md) | | | [Trigger](./kibana-plugin-plugins-ui_actions-public.trigger.md) | This is a convenience interface used to register a \*trigger\*.Trigger specifies a named anchor to which Action can be attached. When Trigger is being \*called\* it creates a Context object and passes it to the execute method of an Action.More than one action can be attached to a single trigger, in which case when trigger is \*called\* it first displays a context menu for user to pick a single action to execute. | -| [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) | | | [UiActionsActionDefinition](./kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.md) | A convenience interface used to register an action. | | [UiActionsPresentable](./kibana-plugin-plugins-ui_actions-public.uiactionspresentable.md) | Represents something that can be displayed to user in UI. | | [UiActionsServiceParams](./kibana-plugin-plugins-ui_actions-public.uiactionsserviceparams.md) | | @@ -41,14 +39,8 @@ | [ACTION\_VISUALIZE\_FIELD](./kibana-plugin-plugins-ui_actions-public.action_visualize_field.md) | | | [ACTION\_VISUALIZE\_GEO\_FIELD](./kibana-plugin-plugins-ui_actions-public.action_visualize_geo_field.md) | | | [ACTION\_VISUALIZE\_LENS\_FIELD](./kibana-plugin-plugins-ui_actions-public.action_visualize_lens_field.md) | | -| [APPLY\_FILTER\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.apply_filter_trigger.md) | | -| [applyFilterTrigger](./kibana-plugin-plugins-ui_actions-public.applyfiltertrigger.md) | | | [ROW\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.row_click_trigger.md) | | | [rowClickTrigger](./kibana-plugin-plugins-ui_actions-public.rowclicktrigger.md) | | -| [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.select_range_trigger.md) | | -| [selectRangeTrigger](./kibana-plugin-plugins-ui_actions-public.selectrangetrigger.md) | | -| [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.value_click_trigger.md) | | -| [valueClickTrigger](./kibana-plugin-plugins-ui_actions-public.valueclicktrigger.md) | | | [VISUALIZE\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.visualize_field_trigger.md) | | | [VISUALIZE\_GEO\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.visualize_geo_field_trigger.md) | | | [visualizeFieldTrigger](./kibana-plugin-plugins-ui_actions-public.visualizefieldtrigger.md) | | @@ -58,12 +50,7 @@ | Type Alias | Description | | --- | --- | -| [ActionByType](./kibana-plugin-plugins-ui_actions-public.actionbytype.md) | | -| [ActionDefinitionByType](./kibana-plugin-plugins-ui_actions-public.actiondefinitionbytype.md) | | | [ActionExecutionContext](./kibana-plugin-plugins-ui_actions-public.actionexecutioncontext.md) | Action methods are executed with Context from trigger + [ActionExecutionMeta](./kibana-plugin-plugins-ui_actions-public.actionexecutionmeta.md) | -| [ActionType](./kibana-plugin-plugins-ui_actions-public.actiontype.md) | | -| [TriggerContext](./kibana-plugin-plugins-ui_actions-public.triggercontext.md) | | -| [TriggerId](./kibana-plugin-plugins-ui_actions-public.triggerid.md) | | | [UiActionsPresentableGrouping](./kibana-plugin-plugins-ui_actions-public.uiactionspresentablegrouping.md) | | | [UiActionsSetup](./kibana-plugin-plugins-ui_actions-public.uiactionssetup.md) | | | [UiActionsStart](./kibana-plugin-plugins-ui_actions-public.uiactionsstart.md) | | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md index e8baf44ff9cbc..a75637e8ea9d3 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md @@ -7,5 +7,5 @@ Signature: ```typescript -embeddable?: IEmbeddable; +embeddable?: unknown; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.md index 74b55d85f10e3..b69734cfc3233 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclickcontext.md @@ -15,5 +15,5 @@ export interface RowClickContext | Property | Type | Description | | --- | --- | --- | | [data](./kibana-plugin-plugins-ui_actions-public.rowclickcontext.data.md) | {
rowIndex: number;
table: Datatable;
columns?: string[];
} | | -| [embeddable](./kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md) | IEmbeddable | | +| [embeddable](./kibana-plugin-plugins-ui_actions-public.rowclickcontext.embeddable.md) | unknown | | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclicktrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclicktrigger.md index aa1097d8c0864..f05138296e6e8 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclicktrigger.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.rowclicktrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -rowClickTrigger: Trigger<'ROW_CLICK_TRIGGER'> +rowClickTrigger: Trigger ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.select_range_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.select_range_trigger.md deleted file mode 100644 index fd784ff17fa84..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.select_range_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.select_range_trigger.md) - -## SELECT\_RANGE\_TRIGGER variable - -Signature: - -```typescript -SELECT_RANGE_TRIGGER = "SELECT_RANGE_TRIGGER" -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.selectrangetrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.selectrangetrigger.md deleted file mode 100644 index 0d9fa2d83ee57..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.selectrangetrigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [selectRangeTrigger](./kibana-plugin-plugins-ui_actions-public.selectrangetrigger.md) - -## selectRangeTrigger variable - -Signature: - -```typescript -selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'> -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.id.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.id.md index 426f17f9a0352..5bf868720cdec 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.id.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.id.md @@ -4,10 +4,10 @@ ## Trigger.id property -Unique name of the trigger as identified in `ui_actions` plugin trigger registry, such as "SELECT\_RANGE\_TRIGGER" or "VALUE\_CLICK\_TRIGGER". +Unique name of the trigger as identified in `ui_actions` plugin trigger registry. Signature: ```typescript -id: ID; +id: string; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.md index b69bba892f475..d829d7b87c177 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.trigger.md @@ -13,7 +13,7 @@ More than one action can be attached to a single trigger, in which case when tri Signature: ```typescript -export interface Trigger +export interface Trigger ``` ## Properties @@ -21,6 +21,6 @@ export interface Trigger | Property | Type | Description | | --- | --- | --- | | [description](./kibana-plugin-plugins-ui_actions-public.trigger.description.md) | string | A longer user friendly description of the trigger. | -| [id](./kibana-plugin-plugins-ui_actions-public.trigger.id.md) | ID | Unique name of the trigger as identified in ui_actions plugin trigger registry, such as "SELECT\_RANGE\_TRIGGER" or "VALUE\_CLICK\_TRIGGER". | +| [id](./kibana-plugin-plugins-ui_actions-public.trigger.id.md) | string | Unique name of the trigger as identified in ui_actions plugin trigger registry. | | [title](./kibana-plugin-plugins-ui_actions-public.trigger.title.md) | string | User friendly name of the trigger. | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontext.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontext.md deleted file mode 100644 index 4ce95d27ecffa..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontext.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContext](./kibana-plugin-plugins-ui_actions-public.triggercontext.md) - -## TriggerContext type - -Signature: - -```typescript -export declare type TriggerContext = T extends TriggerId ? TriggerContextMapping[T] : never; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.__.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.__.md deleted file mode 100644 index 17ad926f8ee82..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.__.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [""](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.__.md) - -## TriggerContextMapping."" property - -Signature: - -```typescript -[DEFAULT_TRIGGER]: TriggerContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.filter_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.filter_trigger.md deleted file mode 100644 index 0ccf8aa3d7415..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.filter_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [FILTER\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.filter_trigger.md) - -## TriggerContextMapping.FILTER\_TRIGGER property - -Signature: - -```typescript -[APPLY_FILTER_TRIGGER]: ApplyGlobalFilterActionContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md deleted file mode 100644 index 2f0d22cf6dd74..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) - -## TriggerContextMapping interface - -Signature: - -```typescript -export interface TriggerContextMapping -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [""](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.__.md) | TriggerContext | | -| [FILTER\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.filter_trigger.md) | ApplyGlobalFilterActionContext | | -| [ROW\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.row_click_trigger.md) | RowClickContext | | -| [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.select_range_trigger.md) | RangeSelectContext | | -| [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.value_click_trigger.md) | ValueClickContext | | -| [VISUALIZE\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_field_trigger.md) | VisualizeFieldContext | | -| [VISUALIZE\_GEO\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_geo_field_trigger.md) | VisualizeFieldContext | | - diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.row_click_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.row_click_trigger.md deleted file mode 100644 index cf253df337378..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.row_click_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [ROW\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.row_click_trigger.md) - -## TriggerContextMapping.ROW\_CLICK\_TRIGGER property - -Signature: - -```typescript -[ROW_CLICK_TRIGGER]: RowClickContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.select_range_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.select_range_trigger.md deleted file mode 100644 index c5ef6843390b3..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.select_range_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [SELECT\_RANGE\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.select_range_trigger.md) - -## TriggerContextMapping.SELECT\_RANGE\_TRIGGER property - -Signature: - -```typescript -[SELECT_RANGE_TRIGGER]: RangeSelectContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.value_click_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.value_click_trigger.md deleted file mode 100644 index 129144a66cee5..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.value_click_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.value_click_trigger.md) - -## TriggerContextMapping.VALUE\_CLICK\_TRIGGER property - -Signature: - -```typescript -[VALUE_CLICK_TRIGGER]: ValueClickContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_field_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_field_trigger.md deleted file mode 100644 index feaaffac8a234..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_field_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [VISUALIZE\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_field_trigger.md) - -## TriggerContextMapping.VISUALIZE\_FIELD\_TRIGGER property - -Signature: - -```typescript -[VISUALIZE_FIELD_TRIGGER]: VisualizeFieldContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_geo_field_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_geo_field_trigger.md deleted file mode 100644 index 023490a2ae027..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_geo_field_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerContextMapping](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.md) > [VISUALIZE\_GEO\_FIELD\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.triggercontextmapping.visualize_geo_field_trigger.md) - -## TriggerContextMapping.VISUALIZE\_GEO\_FIELD\_TRIGGER property - -Signature: - -```typescript -[VISUALIZE_GEO_FIELD_TRIGGER]: VisualizeFieldContext; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggerid.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggerid.md deleted file mode 100644 index 6e5a234e286f9..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.triggerid.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [TriggerId](./kibana-plugin-plugins-ui_actions-public.triggerid.md) - -## TriggerId type - -Signature: - -```typescript -export declare type TriggerId = keyof TriggerContextMapping; -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.md index 7c873715795e9..a4de28ff4d1af 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.md @@ -9,7 +9,7 @@ A convenience interface used to register an action. Signature: ```typescript -export interface ActionDefinition extends Partial>> +export interface ActionDefinition extends Partial>> ``` ## Properties @@ -17,7 +17,7 @@ export interface ActionDefinition extends Part | Property | Type | Description | | --- | --- | --- | | [id](./kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.id.md) | string | ID of the action that uniquely identifies this action in the actions registry. | -| [type](./kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md) | ActionType | ID of the factory for this action. Used to construct dynamic actions. | +| [type](./kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md) | string | ID of the factory for this action. Used to construct dynamic actions. | ## Methods diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md index 125f834e9036e..c2cc8b41568ce 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsactiondefinition.type.md @@ -9,5 +9,5 @@ ID of the factory for this action. Used to construct dynamic actions. Signature: ```typescript -readonly type?: ActionType; +readonly type?: string; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentable.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentable.md index 03fa7fb6e447e..659ea999b9f8e 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentable.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentable.md @@ -9,7 +9,7 @@ Represents something that can be displayed to user in UI. Signature: ```typescript -export interface Presentable +export interface Presentable ``` ## Properties diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentablegrouping.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentablegrouping.md index a61ff65e39c69..2fb6c3e187d3d 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentablegrouping.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionspresentablegrouping.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type PresentableGrouping = Array>; +export declare type PresentableGrouping = Array>; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md index ca999322b7a56..30272cdcdc7f8 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md @@ -11,5 +11,5 @@ Signature: ```typescript -readonly addTriggerAction: (triggerId: T, action: ActionDefinition | Action) => void; +readonly addTriggerAction: (triggerId: string, action: ActionDefinition) => void; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md index e95e7e1eb38b6..fd17c76b0ee9f 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly attachAction: (triggerId: T, actionId: string) => void; +readonly attachAction: (triggerId: string, actionId: string) => void; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md index a6ff2489c6f0e..bf9c589e59f60 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly detachAction: (triggerId: TriggerId, actionId: string) => void; +readonly detachAction: (triggerId: string, actionId: string) => void; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md index 8e7fb8b8bbf29..fb1a1ef14d315 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md @@ -12,5 +12,5 @@ Signature: ```typescript -readonly executeTriggerActions: (triggerId: T, context: TriggerContext) => Promise; +readonly executeTriggerActions: (triggerId: string, context: object) => Promise; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md index d540de7637441..32a4fcf8e6f89 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">; +readonly getAction: >(id: string) => Action>; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md index b996620686a28..b8f59e943f38e 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getTrigger: (triggerId: T) => TriggerContract; +readonly getTrigger: (triggerId: string) => TriggerContract; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md index f94b34ecc2d90..c7c0eac755aec 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getTriggerActions: (triggerId: T) => Action[]; +readonly getTriggerActions: (triggerId: string) => Action[]; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md index dff958608ef9e..9e3e38a6ac43d 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; +readonly getTriggerCompatibleActions: (triggerId: string, context: object) => Promise; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md index e35eb503ab62b..fced0bbc3cde2 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md @@ -21,19 +21,19 @@ export declare class UiActionsService | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [actions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.actions.md) | | ActionRegistry | | -| [addTriggerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, action: ActionDefinition<TriggerContextMapping[T]> | Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">) => void | addTriggerAction is similar to attachAction as it attaches action to a trigger, but it also registers the action, if it has not been registered, yet.addTriggerAction also infers better typing of the action argument. | -| [attachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, actionId: string) => void | | +| [addTriggerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md) | | (triggerId: string, action: ActionDefinition) => void | addTriggerAction is similar to attachAction as it attaches action to a trigger, but it also registers the action, if it has not been registered, yet.addTriggerAction also infers better typing of the action argument. | +| [attachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md) | | (triggerId: string, actionId: string) => void | | | [clear](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.clear.md) | | () => void | Removes all registered triggers and actions. | -| [detachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md) | | (triggerId: TriggerId, actionId: string) => void | | -| [executeTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, context: TriggerContext<T>) => Promise<void> | | +| [detachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md) | | (triggerId: string, actionId: string) => void | | +| [executeTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md) | | (triggerId: string, context: object) => Promise<void> | | | [executionService](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.executionservice.md) | | UiActionsExecutionService | | | [fork](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.fork.md) | | () => UiActionsService | "Fork" a separate instance of UiActionsService that inherits all existing triggers and actions, but going forward all new triggers and actions added to this instance of UiActionsService are only available within this instance. | -| [getAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md) | | <T extends ActionDefinition<{}>>(id: string) => Action<ActionContext<T>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV"> | | -| [getTrigger](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T) => TriggerContract<T> | | -| [getTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T) => Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">[] | | -| [getTriggerCompatibleActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "ROW_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, context: TriggerContextMapping[T]) => Promise<Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">[]> | | +| [getAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md) | | <T extends ActionDefinition<object>>(id: string) => Action<ActionContext<T>> | | +| [getTrigger](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md) | | (triggerId: string) => TriggerContract | | +| [getTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md) | | (triggerId: string) => Action[] | | +| [getTriggerCompatibleActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md) | | (triggerId: string, context: object) => Promise<Action[]> | | | [hasAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.hasaction.md) | | (actionId: string) => boolean | | -| [registerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md) | | <A extends ActionDefinition<{}>>(definition: A) => Action<ActionContext<A>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV"> | | +| [registerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md) | | <A extends ActionDefinition<object>>(definition: A) => Action<ActionContext<A>> | | | [registerTrigger](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registertrigger.md) | | (trigger: Trigger) => void | | | [triggers](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.triggers.md) | | TriggerRegistry | | | [triggerToActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.triggertoactions.md) | | TriggerToActionsRegistry | | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md index 6f03777e14552..75289e8f32351 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">; +readonly registerAction: >(definition: A) => Action>; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.value_click_trigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.value_click_trigger.md deleted file mode 100644 index bd8d4dc50b8fd..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.value_click_trigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [VALUE\_CLICK\_TRIGGER](./kibana-plugin-plugins-ui_actions-public.value_click_trigger.md) - -## VALUE\_CLICK\_TRIGGER variable - -Signature: - -```typescript -VALUE_CLICK_TRIGGER = "VALUE_CLICK_TRIGGER" -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.valueclicktrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.valueclicktrigger.md deleted file mode 100644 index 5c4fc284d83b1..0000000000000 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.valueclicktrigger.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-ui\_actions-public](./kibana-plugin-plugins-ui_actions-public.md) > [valueClickTrigger](./kibana-plugin-plugins-ui_actions-public.valueclicktrigger.md) - -## valueClickTrigger variable - -Signature: - -```typescript -valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'> -``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizefieldtrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizefieldtrigger.md index 15510bd3eb4a3..eb62d36df84d8 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizefieldtrigger.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizefieldtrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -visualizeFieldTrigger: Trigger<'VISUALIZE_FIELD_TRIGGER'> +visualizeFieldTrigger: Trigger ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizegeofieldtrigger.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizegeofieldtrigger.md index faec6a69b71f9..c547c33aaccbf 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizegeofieldtrigger.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.visualizegeofieldtrigger.md @@ -7,5 +7,5 @@ Signature: ```typescript -visualizeGeoFieldTrigger: Trigger<'VISUALIZE_GEO_FIELD_TRIGGER'> +visualizeGeoFieldTrigger: Trigger ``` diff --git a/docs/discover/kuery.asciidoc b/docs/discover/kuery.asciidoc index c1d287fca1f44..feb16190cb34b 100644 --- a/docs/discover/kuery.asciidoc +++ b/docs/discover/kuery.asciidoc @@ -111,11 +111,11 @@ tags:(success and info and security) [discrete] === Range queries -KQL supports `>`, `>=`, `<`, and `<=`. For example: +KQL supports `>`, `>=`, `<`, and `<=` on numeric and date types. For example: [source,yaml] ------------------- -account_number >= 100 and items_sold <= 200 +account_number >= 100 and items_sold <= 200 and @timestamp >= now-5m ------------------- [discrete] diff --git a/docs/discover/search.asciidoc b/docs/discover/search.asciidoc index 75c6fddb484ac..45f0df5bd773f 100644 --- a/docs/discover/search.asciidoc +++ b/docs/discover/search.asciidoc @@ -74,7 +74,7 @@ status codes, you could enter `status:[400 TO 499]`. codes and have an extension of `php` or `html`, you could enter `status:[400 TO 499] AND (extension:php OR extension:html)`. -IMPORTANT: When you use the Lucene Query Syntax in the *KQL* search bar, {kib} is unable to search on nested objects and perform aggregations across fields that contain nested objects. +IMPORTANT: When you use the Lucene Query Syntax in the *KQL* search bar, {kib} is unable to search on nested objects and perform aggregations across fields that contain nested objects. Using `include_in_parent` or `copy_to` as a workaround can cause {kib} to fail. For more detailed information about the Lucene query syntax, see the @@ -107,7 +107,8 @@ To save the current search: . Click *Save* in the Kibana toolbar. . Enter a name for the search and click *Save*. -To import, export, and delete saved searches, open the main menu, then click *Stack Management > Saved Ojbects*. +To import, export, and delete saved searches, open the main menu, +then click *Stack Management > Saved Objects*. ==== Open a saved search To load a saved search into Discover: diff --git a/docs/fleet/fleet.asciidoc b/docs/fleet/fleet.asciidoc index aac733ad8468c..4777800ce5d57 100644 --- a/docs/fleet/fleet.asciidoc +++ b/docs/fleet/fleet.asciidoc @@ -24,4 +24,4 @@ image::fleet/images/fleet-start.png[{fleet} app in {kib}] == Get started To get started with {fleet}, refer to the -{ingest-guide}/index.html[{fleet}] docs. +{fleet-guide}/index.html[{fleet}] docs. diff --git a/docs/getting-started/quick-start-guide.asciidoc b/docs/getting-started/quick-start-guide.asciidoc index ccb6e931d69e3..02abde9d03a3b 100644 --- a/docs/getting-started/quick-start-guide.asciidoc +++ b/docs/getting-started/quick-start-guide.asciidoc @@ -140,4 +140,4 @@ For more information, refer to <>. If you are you ready to add your own data, refer to <>. -If you want to ingest your data, refer to {ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack]. +If you want to ingest your data, refer to {fleet-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack]. diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 6244a43b54f72..7e7c8953fd527 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -262,6 +262,10 @@ Hides the "Time" column in *Discover* and in all saved searches on dashboards. Highlights results in *Discover* and saved searches on dashboards. Highlighting slows requests when working on big documents. +[[doctable-legacy]]`doc_table:legacy`:: +Control the way the Discover's table looks and works. Set this property to `true` to revert to the legacy implementation. + + [float] [[kibana-ml-settings]] ==== Machine learning @@ -453,6 +457,9 @@ of buckets to try to represent. ==== Visualization [horizontal] +[[visualization-visualize-chartslibrary]]`visualization:visualize:legacyChartsLibrary`:: +Enables legacy charts library for area, line and bar charts in visualize. Currently, only legacy charts library supports split chart aggregation. + [[visualization-colormapping]]`visualization:colorMapping`:: **This setting is deprecated and will not be supported as of 8.0.** Maps values to specific colors in *Visualize* charts and *TSVB*. This setting does not apply to *Lens*. diff --git a/docs/management/images/tags/bulk-assign-selection.png b/docs/management/images/tags/bulk-assign-selection.png new file mode 100644 index 0000000000000..1c8687226b51f Binary files /dev/null and b/docs/management/images/tags/bulk-assign-selection.png differ diff --git a/docs/management/images/tags/create-tag.png b/docs/management/images/tags/create-tag.png new file mode 100644 index 0000000000000..a88e754457b9f Binary files /dev/null and b/docs/management/images/tags/create-tag.png differ diff --git a/docs/management/images/tags/manage-assignments-flyout.png b/docs/management/images/tags/manage-assignments-flyout.png new file mode 100644 index 0000000000000..a4e0b7a49d96a Binary files /dev/null and b/docs/management/images/tags/manage-assignments-flyout.png differ diff --git a/docs/management/images/tags/tag-management-section.png b/docs/management/images/tags/tag-management-section.png new file mode 100644 index 0000000000000..4aae3ea067820 Binary files /dev/null and b/docs/management/images/tags/tag-management-section.png differ diff --git a/docs/management/managing-tags.asciidoc b/docs/management/managing-tags.asciidoc new file mode 100644 index 0000000000000..3da98b2281fdc --- /dev/null +++ b/docs/management/managing-tags.asciidoc @@ -0,0 +1,75 @@ +[role="xpack"] +[[managing-tags]] +== Tags + +Tags enable you to categorize your saved objects. You can then easily filter for related objects based on shared tags. + +To begin, open the main menu, click *Stack Management*, then click *Tags*. + +[role="screenshot"] +image::images/tags/tag-management-section.png[Tags management section] + +[float] +=== Required permissions + +Access to *Tags* requires the `Tag Management` {kib} privilege. To add the privilege, open the menu, +click *Stack Management*, then click *Roles*. + +In addition: + +* The `read` privilege allows you to assign tags to the saved objects for which you have write permission. +* The `write` privilege enables you to create, edit, and delete tags. + + +NOTE: Having the `Tag Management` {kib} privilege is not required to +view tags assigned on objects the user has `read` access to, or to filter objects by tags +in {kib} applications or from the navigational search. + +[float] +[[settings-create-tag]] +=== Create a tag + +Create a tag to assign to your saved objects. + +. Click *Create tag*. ++ +[role="screenshot"] +image::images/tags/create-tag.png[Tag creation popin] +. Enter a name and select a color for the new tag. ++ +The name can include alphanumeric characters (English letters and digits), `:`, `-`, `_` and the space character, +and cannot be longer than 50 characters. +. Click *Create tag*. + +[float] +[[settings-assign-tag]] +=== Assign a tag to saved objects + +Assign or remove tags to one or more saved objects. You must have `write` permission +on the objects to which you assign the tags. + +. Click the action (...) icon in the tag row, and then select the *Manage assignments* action. ++ +[role="screenshot"] +image::images/tags/manage-assignments-flyout.png[Assign flyout] +. Select the objects to which you want to assign or remove tags. +. Click on *Save tag assignments*. + +TIP: To assign multiple tags to objects at once, select their checkboxes +and then select *Manage tag assignments* from the *selected tags* menu. + +[role="screenshot"] +image::images/tags/bulk-assign-selection.png[Bulk assign tags] + +[float] +[[settings-delete-tag]] +=== Delete a tag + +Delete a tag and remove it from any saved objects. + +. Click the action (...) icon in the tag row, and then select the *Delete* action. + +. Click *Delete tag*. + +TIP: To delete multiple tags at once, select their checkboxes in the list view, +and then select *Delete* action from the *selected tags* menu. \ No newline at end of file diff --git a/docs/maps/connect-to-ems.asciidoc b/docs/maps/connect-to-ems.asciidoc index 45ced2e64aa73..a5b8010f21f97 100644 --- a/docs/maps/connect-to-ems.asciidoc +++ b/docs/maps/connect-to-ems.asciidoc @@ -35,3 +35,188 @@ To disable EMS, change your <> file. . Set `map.includeElasticMapsService` to `false` to turn off the EMS connection. . Set `map.tilemap.url` to the URL of your tile server. This configures the default tile layer of Maps. . (Optional) Set `map.regionmap` to the vector shapes of the administrative boundaries that you want to use. + +[float] +[id=elastic-maps-server] +=== Host Elastic Maps Service locally + +beta::[] + +If you cannot connect to Elastic Maps Service from the {kib} server or browser clients, and your cluster has the appropriate license level, you can opt to host the service on your own infrastructure. + +{hosted-ems} is a self-managed version of Elastic Maps Service offered as a Docker image that provides both the EMS basemaps and EMS boundaries. You must first download and run the image. After connecting it to your {es} cluster for license validation, you're guided to download and configure the basemaps database, which must be retrieved separately. + +IMPORTANT: {hosted-ems} does not serve raster tiles, needed by Vega, coordinate, and region map visualizations. + +You can use +docker pull+ to download the {hosted-ems} image from the Elastic Docker registry. + +ifeval::["{release-state}"=="unreleased"] +Version {version} of {hosted-ems} has not yet been released, so no Docker image is currently available for this version. +endif::[] + +ifeval::["{release-state}"!="unreleased"] + +["source","bash",subs="attributes"] +---------------------------------- +docker pull {ems-docker-image} +---------------------------------- + +Start {hosted-ems} and expose the default port `8080`: + +["source","bash",subs="attributes"] +---------------------------------- +docker run --rm --init --publish 8080:8080 \ + {ems-docker-image} +---------------------------------- + +Once {hosted-ems} is running, follow instructions from the webpage at `localhost:8080` to define a configuration file and download the basemaps database. + +[role="screenshot"] +image::images/elastic-maps-server-instructions.png[Set-up instructions] + +endif::[] + +[float] +[[elastic-maps-server-configuration]] +==== Configuration + +{hosted-ems} reads properties from a configuration file in YAML format that is validated on startup. The location of this file is provided by the `EMS_PATH_CONF` environment variable and defaults to `/usr/src/app/server/config/elastic-maps-server.yml`. + +*General settings* + +[cols="2*<"] +|=== +| [[ems-hostname]]`hostname` + | Specifies the host of the backend server. To allow remote users to connect, set the value to the IP address or DNS name of the {hosted-ems} container. *Default: _your-hostname_*. <>. + +| `port` + | Specifies the port used by the backend server. Default: *`8080`*. <>. + +| `ui` + | Controls the display of the status page and the layer preview. *Default: `true`* + +| `logging.level` + | Verbosity of {hosted-ems} logs. Valid values are `trace`, `debug`, `info`, `warn`, `error`, `fatal`, and `silent`. *Default: `info`* + +| `path.planet` + | Path of the basemaps database. *Default: `/usr/src/app/data/planet.mbtiles`* +|=== + + +*{es} connection and security settings* + +[cols="2*<"] +|=== + +| `elasticsearch.host` + | URL of the {es} instance to use for license validation. + +| `elasticsearch.username` and `elasticsearch.password` + | Credentials of a user with at least the `monitor` role. + +| `elasticsearch.ssl.certificateAuthorities` + | Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates that make up a trusted certificate chain for {hosted-ems}. This chain is used by {hosted-ems} to establish trust when connecting to your {es} cluster. <>. + +| `elasticsearch.ssl.certificate` and `elasticsearch.ssl.key`, and `elasticsearch.ssl.keyPassphrase` + | Optional settings that provide the paths to the PEM-format SSL certificate and key files and the key password. These files are used to verify the identity of {hosted-ems} to {es} and are required when `xpack.security.http.ssl.client_authentication` in {es} is set to `required`. <>. + +| `elasticsearch.ssl.verificationMode` + | Controls the verification of the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to {es}. Valid values are "`full`", "`certificate`", and "`none`". Using "`full`" performs hostname verification, using "`certificate`" skips hostname verification, and using "`none`" skips verification entirely. *Default: `full`*. <>. + +|=== + +*Server security settings* + +[cols="2*<"] +|=== + +| `ssl.enabled` + | Enables SSL/TLS for inbound connections to {hosted-ems}. When set to `true`, a certificate and its corresponding private key must be provided. *Default: `false`*. <>. + +| `ssl.certificateAuthorities` + | Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates that make up a trusted certificate chain for {hosted-ems}. This chain is used by the {hosted-ems} to establish trust when receiving inbound SSL/TLS connections from end users. <>. + +| `ssl.key`, `ssl.certificate`, and `ssl.keyPassphrase` + | Location of yor SSL key and certificate files and the password that decrypts the private key that is specified via `ssl.key`. This password is optional, as the key may not be encrypted. <>. + +| `ssl.supportedProtocols` + | An array of supported protocols with versions. +Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. *Default: `TLSv1.1`, `TLSv1.2`, `TLSv1.3`*. <>. + +| `ssl.cipherSuites` + | Details on the format, and the valid options, are available via the +https://www.openssl.org/docs/man1.1.1/man1/ciphers.html#CIPHER-LIST-FORMAT[OpenSSL cipher list format documentation]. +*Default: `TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA`*. <>. +|=== + +[float] +[[elastic-maps-server-bind-mount-config]] +===== Bind-mounted configuration + +One way to configure {hosted-ems} is to provide `elastic-maps-server.yml` via bind-mounting. With +docker-compose+, the bind-mount can be specified like this: + +["source","yaml",subs="attributes"] +-------------------------------------------- +version: '2' +services: + {hosted-ems}: + image: {ems-docker-image} + volumes: + - ./elastic-maps-server.yml:/usr/src/app/config/elastic-maps-server.yml +-------------------------------------------- + +[float] +[[elastic-maps-server-envvar-config]] +===== Environment variable configuration +All configuration settings can be overridden by environment variables that are named with all uppercase letters and by replacing YAML periods with underscores. For example `elasticsearch.ssl.certificate` could be overridden by the environment variable `ELASTICSEARCH_SSL_CERTIFICATE`. Boolean variables must use the `true` or `false` strings. + +WARNING: All information that you include in environment variables is visible through the `ps` command, including sensitive information. + +These variables can be set with +docker-compose+ like this: + +["source","yaml",subs="attributes"] +---------------------------------------------------------- +version: '2' +services: + {hosted-ems}: + image: {ems-docker-image} + environment: + ELASTICSEARCH_HOST: http://elasticsearch.example.org + ELASTICSEARCH_USERNAME: 'ems' + ELASTICSEARCH_PASSWORD: 'changeme' +---------------------------------------------------------- + +[float] +[[elastic-maps-server-data]] +==== Data + +{hosted-ems} hosts vector layer boundaries and vector tile basemaps for the entire planet. Boundaries include world countries, global administrative regions, and specific country regions. A minimal basemap is provided with {hosted-ems}. This can be used for testing environments but won't be functional for normal operations. The full basemap (around 90GB file) needs to be mounted on the Docker container for {hosted-ems} to run normally. + +TIP: The available basemaps and boundaries can be explored from the `/maps` endpoint in a web page that is your self-managed equivalent to https://maps.elastic.co + + +[float] +[[elastic-maps-server-kibana]] +==== Kibana configuration + +With {hosted-ems} running, add the `map.emsUrl` configuration key in your <> file pointing to the root of the service. This setting will point {kib} to request EMS basemaps and boundaries from {hosted-ems}. Typically this will be the URL to the <> of {hosted-ems}. For example, `map.emsUrl: https://my-ems-server:8080`. + + +[float] +[[elastic-maps-server-check]] +==== Status check + +{hosted-ems} periodically runs a status check that is exposed in three different forms: + +* At the root of {hosted-ems}, a web page will render the status of the different services. +* A JSON representation of {hosted-ems} status is available at the `/status` endpoint. +* The Docker https://docs.docker.com/engine/reference/builder/#healthcheck[`HEALTHCHECK`] instruction is run by default and will inform about the health of the service, running a process equivalent to the `/status` endpoint. + +IMPORTANT: {hosted-ems} won't respond to any data request if the license validation is not fulfilled. + + +[float] +[[elastic-maps-server-logging]] +==== Logging + +Logs are generated in {ecs-ref}[ECS JSON format] and emitted to the standard output and to `/var/log/elastic-maps-server/elastic-maps-server.log`. The server won't rotate the logs automatically but the `logrotate` tool is installed in the image. Mount `/dev/null` to the default log path if you want to disable the output to that file. diff --git a/docs/maps/images/elastic-maps-server-instructions.png b/docs/maps/images/elastic-maps-server-instructions.png new file mode 100644 index 0000000000000..17e9163a845c2 Binary files /dev/null and b/docs/maps/images/elastic-maps-server-instructions.png differ diff --git a/docs/maps/index.asciidoc b/docs/maps/index.asciidoc index 3c3537826a6a8..59b592ba1ec59 100644 --- a/docs/maps/index.asciidoc +++ b/docs/maps/index.asciidoc @@ -1,3 +1,7 @@ +:ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8 +:ems-docker-image: {ems-docker-repo}:{version} +:hosted-ems: Elastic Maps Server + [role="xpack"] [[maps]] = Maps diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 931a783654a91..2f605f3af01b8 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -198,3 +198,8 @@ This page has moved. Refer to <>. === Variables This page has moved. Refer to <>. + +[role="exclude",id="visualize"] +== Visualize + +This page has been removed. Refer to <>. \ No newline at end of file diff --git a/docs/settings/fleet-settings.asciidoc b/docs/settings/fleet-settings.asciidoc index abfd2d3a95bed..2d330445d9ced 100644 --- a/docs/settings/fleet-settings.asciidoc +++ b/docs/settings/fleet-settings.asciidoc @@ -10,7 +10,7 @@ experimental[] You can configure `xpack.fleet` settings in your `kibana.yml`. By default, {fleet} is enabled. To use {fleet}, you also need to configure {kib} and {es} hosts. -See the {ingest-guide}/index.html[{fleet}] docs for more information. +See the {fleet-guide}/index.html[{fleet}] docs for more information. [[general-fleet-settings-kb]] ==== General {fleet} settings diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc index 2d91eb07c5236..8c16c76c62569 100644 --- a/docs/settings/reporting-settings.asciidoc +++ b/docs/settings/reporting-settings.asciidoc @@ -195,11 +195,11 @@ a| `xpack.reporting.capture.browser` Defaults to `false`. a| `xpack.reporting.capture.browser` -.chromium.proxy.server` +`.chromium.proxy.server` | The uri for the proxy server. Providing the username and password for the proxy server via the uri is not supported. a| `xpack.reporting.capture.browser` -.chromium.proxy.bypass` +`.chromium.proxy.bypass` | An array of hosts that should not go through the proxy server and should use a direct connection instead. Examples of valid entries are "elastic.co", "*.elastic.co", ".elastic.co", ".elastic.co:5601". diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc index 0af953ec2cb09..8c0aa12ffc4c6 100644 --- a/docs/setup/connect-to-elasticsearch.asciidoc +++ b/docs/setup/connect-to-elasticsearch.asciidoc @@ -37,7 +37,7 @@ ship with dashboards and visualizations, so you can quickly get insights into your data. To get started, refer to -{ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack]. +{fleet-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack]. [role="screenshot"] image::images/add-data-fleet.png[Add data using Fleet] diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 8b50fc38167d3..febdf707dce9a 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -192,7 +192,7 @@ In addition to this setting, trusted certificates may be specified via <>. If the trust store has no password, leave this as blank. If the trust store has an empty password, set this to `""`. -| `elasticsearch.ssl.verificationMode:` +|[[elasticsearch-ssl-verificationMode]] `elasticsearch.ssl.verificationMode:` | Controls the verification of the server certificate that {kib} receives when making an outbound SSL/TLS connection to {es}. Valid values are `"full"`, `"certificate"`, and `"none"`. Using `"full"` performs hostname verification, @@ -526,7 +526,7 @@ users. If PKI authentication is enabled, this chain is also used by {kib} to ver In addition to this setting, trusted certificates may be specified via <> and/or <>. -| `server.ssl.cipherSuites:` +| [[server-ssl-cipherSuites]] `server.ssl.cipherSuites:` | Details on the format, and the valid options, are available via the https://www.openssl.org/docs/man1.1.1/man1/ciphers.html#CIPHER-LIST-FORMAT[OpenSSL cipher list format documentation]. *Default: `TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA`*. @@ -585,7 +585,7 @@ the trust store has no password, leave this unset. If the trust store has an emp | {kib} binds to this port and redirects all http requests to https over the port configured as <>. -| `server.ssl.supportedProtocols:` +| [[server-ssl-supportedProtocols]] `server.ssl.supportedProtocols:` | An array of supported protocols with versions. Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. *Default: TLSv1.1, TLSv1.2, TLSv1.3* diff --git a/docs/user/alerting/alerting-getting-started.asciidoc b/docs/user/alerting/alerting-getting-started.asciidoc index 4eeecad079348..cb2b9b19a0726 100644 --- a/docs/user/alerting/alerting-getting-started.asciidoc +++ b/docs/user/alerting/alerting-getting-started.asciidoc @@ -123,14 +123,15 @@ image::images/alert-concepts-connectors.svg[Connectors provide a central place t [float] === Summary -An _alert_ consists of conditions, _actions_, and a schedule. When conditions are met, _alert instances_ are created that render _actions_ and invoke them. To make action setup and update easier, actions refer to _connectors_ that centralize the information used to connect with {kib} services and third-party integrations. +An _alert_ consists of conditions, _actions_, and a schedule. When conditions are met, _alert instances_ are created that render _actions_ and invoke them. To make action setup and update easier, actions refer to _connectors_ that centralize the information used to connect with {kib} services and third-party integrations. The following example ties these concepts together: image::images/alert-concepts-summary.svg[Alerts, actions, alert instances and connectors work together to convert detection into action] -* *Alert*: a specification of the conditions to be detected, the schedule for detection, and the response when detection occurs. -* *Action*: the response to a detected condition defined in the alert. Typically actions specify a service or third party integration along with alert details that will be sent to it. -* *Alert instance*: state tracked by {kib} for every occurrence of a detected condition. Actions as well as controls like muting and re-notification are controlled at the instance level. -* *Connector*: centralized configurations for services and third party integration that are referenced by actions. +. Anytime an *alert*'s conditions are met, an *alert instance* is created. This example checks for servers with average CPU > 0.9. Three servers meet the condition, so three instances are created. +. Instances create *actions* as long as they are not muted or throttled. When actions are created, the template that was setup in the alert is filled with actual values. In this example three actions are created, and the template string {{server}} is replaced with the server name for each instance. +. {kib} invokes the actions, sending them to a 3rd party *integration* like an email service. +. If the 3rd party integration has connection parameters or credentials, {kib} will fetch these from the *connector* referenced in the action. + [float] [[alerting-concepts-differences]] diff --git a/docs/user/alerting/defining-alerts.asciidoc b/docs/user/alerting/defining-alerts.asciidoc index 667038739d45f..ffd72cc824336 100644 --- a/docs/user/alerting/defining-alerts.asciidoc +++ b/docs/user/alerting/defining-alerts.asciidoc @@ -59,7 +59,7 @@ Each action type exposes different properties. For example an email action allow [role="screenshot"] image::images/alert-flyout-action-details.png[UI for defining an email action] -Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Available variables differ by alert type, and a list can be accessed using the "add variable" button. +Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Note that using two curly braces will escape any HTML. Should you need to preserve HTML, use three curly braces (`{{{`). Available variables differ by alert type, and a list can be accessed using the "add variable" button. [role="screenshot"] image::images/alert-flyout-action-variables.png[Passing alert values to an action] diff --git a/docs/user/alerting/images/alert-concepts-summary.svg b/docs/user/alerting/images/alert-concepts-summary.svg index 0d63601c0693d..0aed3bf22375f 100644 --- a/docs/user/alerting/images/alert-concepts-summary.svg +++ b/docs/user/alerting/images/alert-concepts-summary.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user/dashboard/edit-dashboards.asciidoc b/docs/user/dashboard/edit-dashboards.asciidoc index 7b712b355b315..d7f7dc2d65c85 100644 --- a/docs/user/dashboard/edit-dashboards.asciidoc +++ b/docs/user/dashboard/edit-dashboards.asciidoc @@ -81,6 +81,21 @@ Put the dashboard in *Edit* mode, then use the following options: * To delete, open the panel menu, then select *Delete from dashboard*. When you delete a panel from the dashboard, the visualization or saved search from the panel is still available in Kibana. +[float] +[[sync-colors]] +=== Synchronize colors + +By default, dashboard panels that share a non-gradient based color palette will synchronize their color assignment to improve readability. +Color assignment is based on the series name, and the total number of colors is based on the number of unique series names. + +The color synchronizing logic can make the dashboard less readable when there are too many unique series names. It is possible to disable the synchronization behavior: + +. Put the dashboard in *Edit* mode. + +. Click the "Options" button in the top navigation bar. + +. Disable "Sync color palettes across panels". + [float] [[clone-panels]] === Clone panels diff --git a/docs/user/dashboard/url-drilldown.asciidoc b/docs/user/dashboard/url-drilldown.asciidoc index df9fa2dca81fd..b292c1ae5e03f 100644 --- a/docs/user/dashboard/url-drilldown.asciidoc +++ b/docs/user/dashboard/url-drilldown.asciidoc @@ -133,6 +133,12 @@ Example: `{{split event.value ","}}` +|encodeURIComponent +a|Escapes string using built in `encodeURIComponent` function. + +|encodeURIQuery +a|Escapes string using built in `encodeURIComponent` function, while keeping "@", ":", "$", ",", and ";" characters as is. + |=== diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index 8933bf64d2736..9d2b0ae593b34 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -139,6 +139,9 @@ a| <> | Copy, edit, delete, import, and export your saved objects. These include dashboards, visualizations, maps, index patterns, Canvas workpads, and more. +| <> +|Create, manage, and assign tags to your saved objects. + | <> | Create spaces to organize your dashboards and other saved objects into categories. A space is isolated from all other spaces, @@ -196,6 +199,8 @@ include::{kib-repo-dir}/management/rollups/create_and_manage_rollups.asciidoc[] include::{kib-repo-dir}/management/managing-saved-objects.asciidoc[] +include::{kib-repo-dir}/management/managing-tags.asciidoc[] + include::security/index.asciidoc[] include::{kib-repo-dir}/management/snapshot-restore/index.asciidoc[] diff --git a/docs/user/ml/images/ml-data-visualizer-sample.jpg b/docs/user/ml/images/ml-data-visualizer-sample.jpg index ce2bb660d7da1..4d77ef3010c3f 100644 Binary files a/docs/user/ml/images/ml-data-visualizer-sample.jpg and b/docs/user/ml/images/ml-data-visualizer-sample.jpg differ diff --git a/docs/user/reporting/images/canvas-full-page-layout.png b/docs/user/reporting/images/canvas-full-page-layout.png new file mode 100644 index 0000000000000..06c94f05531b2 Binary files /dev/null and b/docs/user/reporting/images/canvas-full-page-layout.png differ diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index 224973d3c840c..6ebeafef1013e 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -92,6 +92,16 @@ To create a printer-friendly PDF with multiple A4 portrait pages and two visuali image::user/reporting/images/preserve-layout-switch.png["Share"] +[float] +[[full-page-pdf]] +== Full page PDF layout —Canvas only + +To create a PDF without margins surrounding the Canvas workpad, turn on *Full page layout* before generating the PDF. + +[role="screenshot"] +image::user/reporting/images/canvas-full-page-layout.png["Full Page Layout"] + + [float] [[manage-report-history]] == View and manage report history diff --git a/docs/user/security/audit-logging.asciidoc b/docs/user/security/audit-logging.asciidoc index 4b3512ae3056b..acb0f94cf878c 100644 --- a/docs/user/security/audit-logging.asciidoc +++ b/docs/user/security/audit-logging.asciidoc @@ -47,9 +47,11 @@ For information on how to configure `xpack.security.audit.appender`, refer to Refer to the table of events that can be logged for auditing purposes. -Each event is broken down into `category`, `type`, `action` and `outcome` fields +Each event is broken down into <>, <>, <> and <> fields to make it easy to filter, query and aggregate the resulting logs. +Refer to <> for a table of fields that get logged with audit event. + [NOTE] ============================================================================ To ensure that a record of every operation is persisted even in case of an @@ -58,7 +60,6 @@ authorization checks have passed, but before the response from {es} is received. Refer to the corresponding {es} logs for potential write errors. ============================================================================ - [cols="3*<"] |====== 3+a| @@ -89,9 +90,12 @@ Refer to the corresponding {es} logs for potential write errors. | `failure` | User is not authorized to create a connector. .2+| `alert_create` -| `unknown` | User is creating an alert rule. -| `failure` | User is not authorized to create an alert rule. +| `unknown` | User is creating an alert. +| `failure` | User is not authorized to create an alert. +.2+| `space_create` +| `unknown` | User is creating a space. +| `failure` | User is not authorized to create a space. 3+a| ====== Type: change @@ -121,28 +125,28 @@ Refer to the corresponding {es} logs for potential write errors. | `failure` | User is not authorized to update a connector. .2+| `alert_update` -| `unknown` | User is updating an alert rule. -| `failure` | User is not authorized to update an alert rule. +| `unknown` | User is updating an alert. +| `failure` | User is not authorized to update an alert. .2+| `alert_update_api_key` -| `unknown` | User is updating the API key of an alert rule. -| `failure` | User is not authorized to update the API key of an alert rule. +| `unknown` | User is updating the API key of an alert. +| `failure` | User is not authorized to update the API key of an alert. .2+| `alert_enable` -| `unknown` | User is enabling an alert rule. -| `failure` | User is not authorized to enable an alert rule. +| `unknown` | User is enabling an alert. +| `failure` | User is not authorized to enable an alert. .2+| `alert_disable` -| `unknown` | User is disabling an alert rule. -| `failure` | User is not authorized to disable an alert rule. +| `unknown` | User is disabling an alert. +| `failure` | User is not authorized to disable an alert. .2+| `alert_mute` -| `unknown` | User is muting an alert rule. -| `failure` | User is not authorized to mute an alert rule. +| `unknown` | User is muting an alert. +| `failure` | User is not authorized to mute an alert. .2+| `alert_unmute` -| `unknown` | User is unmuting an alert rule. -| `failure` | User is not authorized to unmute an alert rule. +| `unknown` | User is unmuting an alert. +| `failure` | User is not authorized to unmute an alert. .2+| `alert_instance_mute` | `unknown` | User is muting an alert instance. @@ -152,6 +156,9 @@ Refer to the corresponding {es} logs for potential write errors. | `unknown` | User is unmuting an alert instance. | `failure` | User is not authorized to unmute an alert instance. +.2+| `space_update` +| `unknown` | User is updating a space. +| `failure` | User is not authorized to update a space. 3+a| ====== Type: deletion @@ -169,8 +176,12 @@ Refer to the corresponding {es} logs for potential write errors. | `failure` | User is not authorized to delete a connector. .2+| `alert_delete` -| `unknown` | User is deleting an alert rule. -| `failure` | User is not authorized to delete an alert rule. +| `unknown` | User is deleting an alert. +| `failure` | User is not authorized to delete an alert. + +.2+| `space_delete` +| `unknown` | User is deleting a space. +| `failure` | User is not authorized to delete a space. 3+a| ====== Type: access @@ -196,13 +207,20 @@ Refer to the corresponding {es} logs for potential write errors. | `failure` | User is not authorized to search for connectors. .2+| `alert_get` -| `success` | User has accessed an alert rule. -| `failure` | User is not authorized to access an alert rule. +| `success` | User has accessed an alert. +| `failure` | User is not authorized to access an alert. .2+| `alert_find` -| `success` | User has accessed an alert rule as part of a search operation. -| `failure` | User is not authorized to search for alert rules. +| `success` | User has accessed an alert as part of a search operation. +| `failure` | User is not authorized to search for alerts. +.2+| `space_get` +| `success` | User has accessed a space. +| `failure` | User is not authorized to access a space. + +.2+| `space_find` +| `success` | User has accessed a space as part of a search operation. +| `failure` | User is not authorized to search for spaces. 3+a| ===== Category: web @@ -214,3 +232,188 @@ Refer to the corresponding {es} logs for potential write errors. | `http_request` | `unknown` | User is making an HTTP request. |====== + + +[[xpack-security-ecs-audit-schema]] +==== ECS audit schema + +Audit logs are written in JSON using https://www.elastic.co/guide/en/ecs/1.6/index.html[Elastic Common Schema (ECS)] specification. + +[cols="2*<"] +|====== + +2+a| ===== Base Fields + +| *Field* +| *Description* + +| `@timestamp` +| Time when the event was generated. + +Example: `2016-05-23T08:05:34.853Z` + +| `message` +| Human readable description of the event. + +2+a| ===== Event Fields + +| *Field* +| *Description* + +| [[field-event-action]] `event.action` +| The action captured by the event. + +Refer to <> for a table of possible actions. + +| [[field-event-category]] `event.category` +| High level category associated with the event. + +This field is closely related to `event.type`, which is used as a subcategory. + +Possible values: +`database`, +`web`, +`authentication` + +| [[field-event-type]] `event.type` +| Subcategory associated with the event. + +This field can be used along with the `event.category` field to enable filtering events down to a level appropriate for single visualization. + +Possible values: +`creation`, +`access`, +`change`, +`deletion` + +| [[field-event-outcome]] `event.outcome` +| Denotes whether the event represents a success or failure. + +Possible values: +`success`, +`failure`, +`unknown` + +2+a| ===== User Fields + +| *Field* +| *Description* + +| `user.name` +| Login name of the user. + +Example: `jdoe` + +| `user.roles[]` +| Set of user roles at the time of the event. + +Example: `[kibana_admin, reporting_user]` + +2+a| ===== Kibana Fields + +| *Field* +| *Description* + +| `kibana.space_id` +| ID of the space associated with the event. + +Example: `default` + +| `kibana.session_id` +| ID of the user session associated with the event. + +Each login attempt results in a unique session id. + +| `kibana.saved_object.type` +| Type of saved object associated with the event. + +Example: `dashboard` + +| `kibana.saved_object.id` +| ID of the saved object associated with the event. + +| `kibana.authentication_provider` +| Name of the authentication provider associated with the event. + +Example: `my-saml-provider` + +| `kibana.authentication_type` +| Type of the authentication provider associated with the event. + +Example: `saml` + +| `kibana.authentication_realm` +| Name of the Elasticsearch realm that has authenticated the user. + +Example: `native` + +| `kibana.lookup_realm` +| Name of the Elasticsearch realm where the user details were retrieved from. + +Example: `native` + +| `kibana.add_to_spaces[]` +| Set of space IDs that a saved object is being shared to as part of the event. + +Example: `[default, marketing]` + +| `kibana.delete_from_spaces[]` +| Set of space IDs that a saved object is being removed from as part of the event. + +Example: `[marketing]` + +2+a| ===== Error Fields + +| *Field* +| *Description* + +| `error.code` +| Error code describing the error. + +| `error.message` +| Error message. + +2+a| ===== HTTP and URL Fields + +| *Field* +| *Description* + +| `http.request.method` +| HTTP request method. + +Example: `get`, `post`, `put`, `delete` + +| `url.domain` +| Domain of the url. + +Example: `www.elastic.co` + +| `url.path` +| Path of the request. + +Example: `/search` + +| `url.port` +| Port of the request. + +Example: `443` + +| `url.query` +| The query field describes the query string of the request. + +Example: `q=elasticsearch` + +| `url.scheme` +| Scheme of the request. + +Example: `https` + +2+a| ===== Tracing Fields + +| *Field* +| *Description* + +| `trace.id` +| Unique identifier allowing events of the same transaction from {kib} and {es} to be be correlated. + +|====== diff --git a/docs/user/security/encryption-keys/index.asciidoc b/docs/user/security/encryption-keys/index.asciidoc new file mode 100644 index 0000000000000..58c0c0bb775ca --- /dev/null +++ b/docs/user/security/encryption-keys/index.asciidoc @@ -0,0 +1,44 @@ +[[kibana-encryption-keys]] +=== Set up encryptions keys to protect sensitive information + +The `kibana-encryption-keys` command helps you set up encryption keys that {kib} uses +to protect sensitive information. + +[discrete] +=== Synopsis + +[source,shell] +-------------------------------------------------- +bin/kibana-encryption-keys generate +[-i, --interactive] [-q, --quiet] +[-f, --force] [-h, --help] +-------------------------------------------------- + +[discrete] +=== Description + +{kib} uses encryption keys in several areas, ranging from encrypting data +in {kib} associated indices to storing session information. By defining these +encryption keys in your configuration, you'll ensure consistent operations +across restarts. + +[discrete] +[[encryption-key-parameters]] +=== Parameters + +`generate`:: Randomly generates passwords to the console. + +`-i, --interactive`:: Prompts you for which encryption keys to set and optionally +where to save a sample configuration file. + +`-q, --quiet`:: Outputs the encryption keys without helper information. + +`-f, --force`:: Shows help information. + +[discrete] +=== Examples + +[source,shell] +-------------------------------------------------- +bin/kibana-encryption-keys generate +-------------------------------------------------- diff --git a/docs/user/security/index.asciidoc b/docs/user/security/index.asciidoc index f84e9de87c734..6a5c4a83aa3ad 100644 --- a/docs/user/security/index.asciidoc +++ b/docs/user/security/index.asciidoc @@ -45,5 +45,6 @@ cause Kibana's authorization to behave unexpectedly. include::authorization/index.asciidoc[] include::authorization/kibana-privileges.asciidoc[] include::api-keys/index.asciidoc[] +include::encryption-keys/index.asciidoc[] include::role-mappings/index.asciidoc[] include::rbac_tutorial.asciidoc[] diff --git a/examples/embeddable_examples/public/book/add_book_to_library_action.tsx b/examples/embeddable_examples/public/book/add_book_to_library_action.tsx index 4ae3a545df0d0..b36635feb3dcc 100644 --- a/examples/embeddable_examples/public/book/add_book_to_library_action.tsx +++ b/examples/embeddable_examples/public/book/add_book_to_library_action.tsx @@ -35,6 +35,7 @@ export const createAddBookToLibraryAction = () => i18n.translate('embeddableExamples.book.addToLibrary', { defaultMessage: 'Add Book To Library', }), + id: ACTION_ADD_BOOK_TO_LIBRARY, type: ACTION_ADD_BOOK_TO_LIBRARY, order: 100, getIconType: () => 'folderCheck', diff --git a/examples/embeddable_examples/public/book/edit_book_action.tsx b/examples/embeddable_examples/public/book/edit_book_action.tsx index 877e50560000e..6fa5ff15716a6 100644 --- a/examples/embeddable_examples/public/book/edit_book_action.tsx +++ b/examples/embeddable_examples/public/book/edit_book_action.tsx @@ -53,6 +53,7 @@ export const createEditBookAction = (getStartServices: () => Promise i18n.translate('embeddableExamples.book.edit', { defaultMessage: 'Edit Book' }), + id: ACTION_EDIT_BOOK, type: ACTION_EDIT_BOOK, order: 100, getIconType: () => 'documents', diff --git a/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx b/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx index ebab2c483c625..54857010a1468 100644 --- a/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx +++ b/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx @@ -35,6 +35,7 @@ export const createUnlinkBookFromLibraryAction = () => i18n.translate('embeddableExamples.book.unlinkFromLibrary', { defaultMessage: 'Unlink Book from Library Item', }), + id: ACTION_UNLINK_BOOK_FROM_LIBRARY, type: ACTION_UNLINK_BOOK_FROM_LIBRARY, order: 100, getIconType: () => 'folderExclamation', diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index 9b9770e40611e..8e8f2ddfe2128 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -51,21 +51,15 @@ import { TodoRefEmbeddableFactory, TodoRefEmbeddableFactoryDefinition, } from './todo/todo_ref_embeddable_factory'; -import { ACTION_EDIT_BOOK, createEditBookAction } from './book/edit_book_action'; -import { BookEmbeddable, BOOK_EMBEDDABLE } from './book/book_embeddable'; +import { createEditBookAction } from './book/edit_book_action'; +import { BOOK_EMBEDDABLE } from './book/book_embeddable'; import { BookEmbeddableFactory, BookEmbeddableFactoryDefinition, } from './book/book_embeddable_factory'; import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; -import { - ACTION_ADD_BOOK_TO_LIBRARY, - createAddBookToLibraryAction, -} from './book/add_book_to_library_action'; -import { - ACTION_UNLINK_BOOK_FROM_LIBRARY, - createUnlinkBookFromLibraryAction, -} from './book/unlink_book_from_library_action'; +import { createAddBookToLibraryAction } from './book/add_book_to_library_action'; +import { createUnlinkBookFromLibraryAction } from './book/unlink_book_from_library_action'; export interface EmbeddableExamplesSetupDependencies { embeddable: EmbeddableSetup; @@ -92,14 +86,6 @@ export interface EmbeddableExamplesStart { factories: ExampleEmbeddableFactories; } -declare module '../../../src/plugins/ui_actions/public' { - export interface ActionContextMapping { - [ACTION_EDIT_BOOK]: { embeddable: BookEmbeddable }; - [ACTION_ADD_BOOK_TO_LIBRARY]: { embeddable: BookEmbeddable }; - [ACTION_UNLINK_BOOK_FROM_LIBRARY]: { embeddable: BookEmbeddable }; - } -} - export class EmbeddableExamplesPlugin implements Plugin< diff --git a/examples/ui_action_examples/public/hello_world_action.tsx b/examples/ui_action_examples/public/hello_world_action.tsx index da20f40464516..54e3fbe10095c 100644 --- a/examples/ui_action_examples/public/hello_world_action.tsx +++ b/examples/ui_action_examples/public/hello_world_action.tsx @@ -30,6 +30,7 @@ interface StartServices { export const createHelloWorldAction = (getStartServices: () => Promise) => createAction({ + id: ACTION_HELLO_WORLD, type: ACTION_HELLO_WORLD, getDisplayName: () => 'Hello World!', execute: async () => { diff --git a/examples/ui_action_examples/public/plugin.ts b/examples/ui_action_examples/public/plugin.ts index 3a9f673261e33..1d896d3305661 100644 --- a/examples/ui_action_examples/public/plugin.ts +++ b/examples/ui_action_examples/public/plugin.ts @@ -19,8 +19,8 @@ import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; import { UiActionsSetup, UiActionsStart } from '../../../src/plugins/ui_actions/public'; -import { createHelloWorldAction, ACTION_HELLO_WORLD } from './hello_world_action'; -import { helloWorldTrigger, HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger'; +import { createHelloWorldAction } from './hello_world_action'; +import { helloWorldTrigger } from './hello_world_trigger'; export interface UiActionExamplesSetupDependencies { uiActions: UiActionsSetup; @@ -30,16 +30,6 @@ export interface UiActionExamplesStartDependencies { uiActions: UiActionsStart; } -declare module '../../../src/plugins/ui_actions/public' { - export interface TriggerContextMapping { - [HELLO_WORLD_TRIGGER_ID]: {}; - } - - export interface ActionContextMapping { - [ACTION_HELLO_WORLD]: {}; - } -} - export class UiActionExamplesPlugin implements Plugin { diff --git a/examples/ui_actions_explorer/public/actions/actions.tsx b/examples/ui_actions_explorer/public/actions/actions.tsx index 777bcd9c18119..1d9987ad73a26 100644 --- a/examples/ui_actions_explorer/public/actions/actions.tsx +++ b/examples/ui_actions_explorer/public/actions/actions.tsx @@ -38,7 +38,8 @@ export const ACTION_EDIT_USER = 'ACTION_EDIT_USER'; export const ACTION_TRIGGER_PHONE_USER = 'ACTION_TRIGGER_PHONE_USER'; export const ACTION_SHOWCASE_PLUGGABILITY = 'ACTION_SHOWCASE_PLUGGABILITY'; -export const showcasePluggability = createAction({ +export const showcasePluggability = createAction({ + id: ACTION_SHOWCASE_PLUGGABILITY, type: ACTION_SHOWCASE_PLUGGABILITY, getDisplayName: () => 'This is pluggable! Any plugin can inject their actions here.', execute: async (context: ActionExecutionContext) => @@ -49,13 +50,15 @@ export interface PhoneContext { phone: string; } -export const makePhoneCallAction = createAction({ +export const makePhoneCallAction = createAction({ + id: ACTION_CALL_PHONE_NUMBER, type: ACTION_CALL_PHONE_NUMBER, getDisplayName: () => 'Call phone number', execute: async (context) => alert(`Pretend calling ${context.phone}...`), }); -export const lookUpWeatherAction = createAction({ +export const lookUpWeatherAction = createAction({ + id: ACTION_TRAVEL_GUIDE, type: ACTION_TRAVEL_GUIDE, getIconType: () => 'popout', getDisplayName: () => 'View travel guide', @@ -68,7 +71,8 @@ export interface CountryContext { country: string; } -export const viewInMapsAction = createAction({ +export const viewInMapsAction = createAction({ + id: ACTION_VIEW_IN_MAPS, type: ACTION_VIEW_IN_MAPS, getIconType: () => 'popout', getDisplayName: () => 'View in maps', @@ -109,7 +113,8 @@ function EditUserModal({ } export const createEditUserAction = (getOpenModal: () => Promise) => - createAction({ + createAction({ + id: ACTION_EDIT_USER, type: ACTION_EDIT_USER, getIconType: () => 'pencil', getDisplayName: () => 'Edit user', @@ -126,7 +131,8 @@ export interface UserContext { } export const createTriggerPhoneTriggerAction = (getUiActionsApi: () => Promise) => - createAction({ + createAction({ + id: ACTION_TRIGGER_PHONE_USER, type: ACTION_TRIGGER_PHONE_USER, getDisplayName: () => 'Call phone number', shouldAutoExecute: async () => true, diff --git a/examples/ui_actions_explorer/public/app.tsx b/examples/ui_actions_explorer/public/app.tsx index bc8bdee75047d..38fc4e22b284f 100644 --- a/examples/ui_actions_explorer/public/app.tsx +++ b/examples/ui_actions_explorer/public/app.tsx @@ -77,7 +77,7 @@ const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => { { - const dynamicAction = createAction({ + const dynamicAction = createAction({ id: `${ACTION_HELLO_WORLD}-${name}`, type: ACTION_HELLO_WORLD, getDisplayName: () => `Say hello to ${name}`, diff --git a/examples/ui_actions_explorer/public/plugin.tsx b/examples/ui_actions_explorer/public/plugin.tsx index b28e5e7a9f692..757a2f1dfa865 100644 --- a/examples/ui_actions_explorer/public/plugin.tsx +++ b/examples/ui_actions_explorer/public/plugin.tsx @@ -28,15 +28,6 @@ import { createEditUserAction, makePhoneCallAction, showcasePluggability, - UserContext, - CountryContext, - PhoneContext, - ACTION_EDIT_USER, - ACTION_SHOWCASE_PLUGGABILITY, - ACTION_CALL_PHONE_NUMBER, - ACTION_TRAVEL_GUIDE, - ACTION_VIEW_IN_MAPS, - ACTION_TRIGGER_PHONE_USER, createTriggerPhoneTriggerAction, } from './actions/actions'; import { DeveloperExamplesSetup } from '../../developer_examples/public'; @@ -51,23 +42,6 @@ interface SetupDeps { developerExamples: DeveloperExamplesSetup; } -declare module '../../../src/plugins/ui_actions/public' { - export interface TriggerContextMapping { - [USER_TRIGGER]: UserContext; - [COUNTRY_TRIGGER]: CountryContext; - [PHONE_TRIGGER]: PhoneContext; - } - - export interface ActionContextMapping { - [ACTION_EDIT_USER]: UserContext; - [ACTION_SHOWCASE_PLUGGABILITY]: {}; - [ACTION_CALL_PHONE_NUMBER]: PhoneContext; - [ACTION_TRAVEL_GUIDE]: CountryContext; - [ACTION_VIEW_IN_MAPS]: CountryContext; - [ACTION_TRIGGER_PHONE_USER]: UserContext; - } -} - export class UiActionsExplorerPlugin implements Plugin { public setup(core: CoreSetup, deps: SetupDeps) { deps.uiActions.registerTrigger({ diff --git a/jest.config.oss.js b/jest.config.oss.js index e9235069687e0..874fd1e929a7a 100644 --- a/jest.config.oss.js +++ b/jest.config.oss.js @@ -18,6 +18,7 @@ */ module.exports = { + preset: '@kbn/test', rootDir: '.', projects: [ '/packages/*/jest.config.js', @@ -26,5 +27,4 @@ module.exports = { '/src/plugins/*/jest.config.js', '/test/*/jest.config.js', ], - reporters: ['default', '/packages/kbn-test/target/jest/junit_reporter'], }; diff --git a/package.json b/package.json index 9bc363242a332..b657c8273517a 100644 --- a/package.json +++ b/package.json @@ -73,10 +73,6 @@ "url": "https://github.com/elastic/kibana.git" }, "resolutions": { - "**/@hapi/iron": "^5.1.4", - "**/@types/hapi__boom": "^7.4.1", - "**/@types/hapi__hapi": "^18.2.6", - "**/@types/hapi__mimos": "4.1.0", "**/@types/node": "14.14.14", "**/chokidar": "^3.4.3", "**/cross-fetch/node-fetch": "^2.6.1", @@ -97,16 +93,16 @@ "**/typescript": "4.1.2" }, "engines": { - "node": "14.15.2", + "node": "14.15.4", "yarn": "^1.21.1" }, "dependencies": { "@babel/core": "^7.11.6", "@babel/runtime": "^7.11.2", "@elastic/datemath": "link:packages/elastic-datemath", - "@elastic/elasticsearch": "7.10.0", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary", "@elastic/ems-client": "7.11.0", - "@elastic/eui": "30.6.0", + "@elastic/eui": "31.0.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "^9.0.1-kibana3", "@elastic/node-crypto": "1.2.1", @@ -115,17 +111,17 @@ "@elastic/request-crypto": "1.1.4", "@elastic/safer-lodash-set": "link:packages/elastic-safer-lodash-set", "@elastic/search-ui-app-search-connector": "^1.5.0", - "@hapi/boom": "^7.4.11", - "@hapi/cookie": "^10.1.2", - "@hapi/good-squeeze": "5.2.1", - "@hapi/h2o2": "^8.3.2", - "@hapi/hapi": "^18.4.1", - "@hapi/hoek": "^8.5.1", - "@hapi/inert": "^5.2.2", - "@hapi/podium": "^3.4.3", - "@hapi/statehood": "^6.1.2", - "@hapi/vision": "^5.5.4", - "@hapi/wreck": "^15.0.2", + "@hapi/boom": "^9.1.1", + "@hapi/cookie": "^11.0.2", + "@hapi/good-squeeze": "6.0.0", + "@hapi/h2o2": "^9.0.2", + "@hapi/hapi": "^20.0.3", + "@hapi/hoek": "^9.1.1", + "@hapi/inert": "^6.0.3", + "@hapi/podium": "^4.1.1", + "@hapi/statehood": "^7.0.3", + "@hapi/vision": "^6.0.1", + "@hapi/wreck": "^17.1.0", "@kbn/ace": "link:packages/kbn-ace", "@kbn/analytics": "link:packages/kbn-analytics", "@kbn/apm-config-loader": "link:packages/kbn-apm-config-loader", @@ -381,6 +377,7 @@ "@mapbox/geojson-rewind": "^0.5.0", "@mapbox/mapbox-gl-draw": "^1.2.0", "@mapbox/mapbox-gl-rtl-text": "^0.2.3", + "@mapbox/vector-tile": "1.3.1", "@microsoft/api-documenter": "7.7.2", "@microsoft/api-extractor": "7.7.0", "@octokit/rest": "^16.35.0", @@ -451,14 +448,11 @@ "@types/graphql": "^0.13.2", "@types/gulp": "^4.0.6", "@types/gulp-zip": "^4.0.1", - "@types/hapi__boom": "^7.4.1", "@types/hapi__cookie": "^10.1.1", - "@types/hapi__h2o2": "8.3.0", - "@types/hapi__hapi": "^18.2.6", - "@types/hapi__hoek": "^6.2.0", - "@types/hapi__inert": "^5.2.1", + "@types/hapi__h2o2": "^8.3.2", + "@types/hapi__hapi": "^20.0.2", + "@types/hapi__inert": "^5.2.2", "@types/hapi__podium": "^3.4.1", - "@types/hapi__wreck": "^15.0.1", "@types/has-ansi": "^3.0.0", "@types/he": "^1.1.1", "@types/history": "^4.7.3", @@ -609,7 +603,7 @@ "cpy": "^8.1.1", "cronstrue": "^1.51.0", "css-loader": "^3.4.2", - "cypress": "^6.0.1", + "cypress": "^6.1.0", "cypress-cucumber-preprocessor": "^2.5.2", "cypress-multi-reporters": "^1.4.0", "d3": "3.5.17", @@ -750,6 +744,7 @@ "ora": "^4.0.4", "p-limit": "^3.0.1", "parse-link-header": "^1.0.1", + "pbf": "3.2.1", "pirates": "^4.0.1", "pixelmatch": "^5.1.0", "pkg-up": "^2.0.0", @@ -829,7 +824,7 @@ "url-loader": "^2.2.0", "use-resize-observer": "^6.0.0", "val-loader": "^1.1.1", - "vega": "^5.17.0", + "vega": "^5.17.3", "vega-lite": "^4.17.0", "vega-schema-url-parser": "^2.1.0", "vega-tooltip": "^0.24.2", diff --git a/packages/kbn-apm-config-loader/src/config.ts b/packages/kbn-apm-config-loader/src/config.ts index 6e5a830d04b17..5e3d52cfd27d1 100644 --- a/packages/kbn-apm-config-loader/src/config.ts +++ b/packages/kbn-apm-config-loader/src/config.ts @@ -153,8 +153,8 @@ export class ApmConfiguration { return { globalLabels: { - branch: process.env.ghprbSourceBranch || '', - targetBranch: process.env.ghprbTargetBranch || '', + branch: process.env.GIT_BRANCH || '', + targetBranch: process.env.PR_TARGET_BRANCH || '', ciBuildNumber: process.env.BUILD_NUMBER || '', isPr: process.env.GITHUB_PR_NUMBER ? true : false, prId: process.env.GITHUB_PR_NUMBER || '', diff --git a/packages/kbn-es/src/cluster.js b/packages/kbn-es/src/cluster.js index 68bcc37c65600..eaf353b3e55d0 100644 --- a/packages/kbn-es/src/cluster.js +++ b/packages/kbn-es/src/cluster.js @@ -275,6 +275,15 @@ exports.Cluster = class Cluster { this._log.debug('%s %s', ES_BIN, args.join(' ')); + options.esEnvVars = options.esEnvVars || {}; + + // ES now automatically sets heap size to 50% of the machine's available memory + // so we need to set it to a smaller size for local dev and CI + // especially because we currently run many instances of ES on the same machine during CI + options.esEnvVars.ES_JAVA_OPTS = + (options.esEnvVars.ES_JAVA_OPTS ? `${options.esEnvVars.ES_JAVA_OPTS} ` : '') + + '-Xms1g -Xmx1g'; + this._process = execa(ES_BIN, args, { cwd: installPath, env: { diff --git a/packages/kbn-i18n/GUIDELINE.md b/packages/kbn-i18n/GUIDELINE.md index b7c1371d59ea4..437e73bb27019 100644 --- a/packages/kbn-i18n/GUIDELINE.md +++ b/packages/kbn-i18n/GUIDELINE.md @@ -387,6 +387,50 @@ Splitting sentences into several keys often inadvertently presumes a grammar, a ### Unit tests +#### How to test `FormattedMessage` and `i18n.translate()` components. + +To make `FormattedMessage` component work properly, wrapping it with `I18nProvider` is required. In development/production app, this is done in the ancestor components and developers don't have to worry about that. + +But when unit-testing them, no other component provides that wrapping. That's why `shallowWithI18nProvider` and `mountWithI18nProvider` helpers are created. + +For example, there is a component that has `FormattedMessage` inside, like `SaveModal` component: + +```js +// ... +export const SaveModal = (props) => { + return ( +
+ {/* Other things. */} + + + + {/* More other things. */} +
+ ) +} +``` + +To test `SaveModal` component, it should be wrapped with `I18nProvider` by using `shallowWithI18nProvider`: + +```js +// ... +it('should render normally', async () => { + const component = shallowWithI18nProvider( + + ); + + expect(component).toMatchSnapshot(); +}); +// ... +``` + +If a component uses only `i18n.translate()`, it doesn't need `I18nProvider`. In that case, you can test them with `shallow` and `mount` functions that `enzyme` providers out of the box. + +#### How to test `injectI18n` HOC components. + Testing React component that uses the `injectI18n` higher-order component is more complicated because `injectI18n()` creates a wrapper component around the original component. With shallow rendering only top level component is rendered, that is a wrapper itself, not the original component. Since we want to test the rendering of the original component, we need to access it via the wrapper's `WrappedComponent` property. Its value will be the component we passed into `injectI18n()`. diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index c58d010a1f317..08d883a7cbb4d 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -6,7 +6,7 @@ pageLoadAssetSize: beatsManagement: 188135 bfetch: 41874 canvas: 1066647 - charts: 159211 + charts: 195358 cloud: 21076 console: 46091 core: 692106 @@ -98,7 +98,7 @@ pageLoadAssetSize: visTypeTimeseries: 155203 visTypeVega: 153573 visTypeVislib: 242838 - visTypeXy: 20255 + visTypeXy: 113478 visualizations: 295025 visualize: 57431 watcher: 43598 diff --git a/src/core/server/http/prototype_pollution/__snapshots__/validate_object.test.ts.snap b/packages/kbn-std/src/__snapshots__/ensure_no_unsafe_properties.test.ts.snap similarity index 100% rename from src/core/server/http/prototype_pollution/__snapshots__/validate_object.test.ts.snap rename to packages/kbn-std/src/__snapshots__/ensure_no_unsafe_properties.test.ts.snap diff --git a/src/core/server/http/prototype_pollution/validate_object.test.ts b/packages/kbn-std/src/ensure_no_unsafe_properties.test.ts similarity index 89% rename from src/core/server/http/prototype_pollution/validate_object.test.ts rename to packages/kbn-std/src/ensure_no_unsafe_properties.test.ts index 23d6c4ae3b49f..c12626b8d777e 100644 --- a/src/core/server/http/prototype_pollution/validate_object.test.ts +++ b/packages/kbn-std/src/ensure_no_unsafe_properties.test.ts @@ -17,14 +17,14 @@ * under the License. */ -import { validateObject } from './validate_object'; +import { ensureNoUnsafeProperties } from './ensure_no_unsafe_properties'; test(`fails on circular references`, () => { const foo: Record = {}; foo.myself = foo; expect(() => - validateObject({ + ensureNoUnsafeProperties({ payload: foo, }) ).toThrowErrorMatchingInlineSnapshot(`"circular reference detected"`); @@ -57,7 +57,7 @@ test(`fails on circular references`, () => { [property]: value, }; test(`can submit ${JSON.stringify(obj)}`, () => { - expect(() => validateObject(obj)).not.toThrowError(); + expect(() => ensureNoUnsafeProperties(obj)).not.toThrowError(); }); }); }); @@ -74,6 +74,6 @@ test(`fails on circular references`, () => { JSON.parse(`{ "foo": { "bar": { "constructor": { "prototype" : null } } } }`), ].forEach((value) => { test(`can't submit ${JSON.stringify(value)}`, () => { - expect(() => validateObject(value)).toThrowErrorMatchingSnapshot(); + expect(() => ensureNoUnsafeProperties(value)).toThrowErrorMatchingSnapshot(); }); }); diff --git a/src/core/server/http/prototype_pollution/validate_object.ts b/packages/kbn-std/src/ensure_no_unsafe_properties.ts similarity index 97% rename from src/core/server/http/prototype_pollution/validate_object.ts rename to packages/kbn-std/src/ensure_no_unsafe_properties.ts index cab6ce295ce92..47cbea5ecf3ee 100644 --- a/src/core/server/http/prototype_pollution/validate_object.ts +++ b/packages/kbn-std/src/ensure_no_unsafe_properties.ts @@ -31,7 +31,7 @@ const hasOwnProperty = (obj: any, property: string) => const isObject = (obj: any) => typeof obj === 'object' && obj !== null; // we're using a stack instead of recursion so we aren't limited by the call stack -export function validateObject(obj: any) { +export function ensureNoUnsafeProperties(obj: any) { if (!isObject(obj)) { return; } diff --git a/packages/kbn-std/src/index.ts b/packages/kbn-std/src/index.ts index c111428017539..a5b5088f9105f 100644 --- a/packages/kbn-std/src/index.ts +++ b/packages/kbn-std/src/index.ts @@ -27,4 +27,5 @@ export { withTimeout } from './promise'; export { isRelativeUrl, modifyUrl, getUrlOrigin, URLMeaningfulParts } from './url'; export { unset } from './unset'; export { getFlattenedObject } from './get_flattened_object'; +export { ensureNoUnsafeProperties } from './ensure_no_unsafe_properties'; export * from './rxjs_7'; diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js index 89ed60909aa55..55514da3e231f 100644 --- a/packages/kbn-test/jest-preset.js +++ b/packages/kbn-test/jest-preset.js @@ -111,7 +111,7 @@ module.exports = { // An array of regexp pattern strings that are matched against all source file paths, matched files to include/exclude for code coverage collectCoverageFrom: [ '**/*.{js,mjs,jsx,ts,tsx}', - '!**/{__test__,__snapshots__,__examples__,mocks,tests,test_helpers,integration_tests,types}/**/*', + '!**/{__test__,__snapshots__,__examples__,*mock*,tests,test_helpers,integration_tests,types}/**/*', '!**/*mock*.ts', '!**/*.test.ts', '!**/*.d.ts', diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli.ts index 8f53d6f7cf58b..2dfc9ded66201 100644 --- a/packages/kbn-test/src/functional_test_runner/cli.ts +++ b/packages/kbn-test/src/functional_test_runner/cli.ts @@ -141,22 +141,27 @@ export function runFtrCli() { config: 'test/functional/config.js', }, help: ` - --config=path path to a config file - --bail stop tests after the first failure - --grep pattern used to select which tests to run - --invert invert grep to exclude tests - --include=file a test file to be included, pass multiple times for multiple files - --exclude=file a test file to be excluded, pass multiple times for multiple files - --include-tag=tag a tag to be included, pass multiple times for multiple tags - --exclude-tag=tag a tag to be excluded, pass multiple times for multiple tags - --test-stats print the number of tests (included and excluded) to STDERR - --updateBaselines replace baseline screenshots with whatever is generated from the test - --updateSnapshots replace inline and file snapshots with whatever is generated from the test - -u replace both baseline screenshots and snapshots - --kibana-install-dir directory where the Kibana install being tested resides - --throttle enable network throttling in Chrome browser - --headless run browser in headless mode - `, + --config=path path to a config file + --bail stop tests after the first failure + --grep pattern used to select which tests to run + --invert invert grep to exclude tests + --include=file a test file to be included, pass multiple times for multiple files + --exclude=file a test file to be excluded, pass multiple times for multiple files + --include-tag=tag a tag to be included, pass multiple times for multiple tags. Only + suites which have one of the passed include-tag tags will be executed. + When combined with the --exclude-tag flag both conditions must be met + for a suite to run. + --exclude-tag=tag a tag to be excluded, pass multiple times for multiple tags. Any suite + which has any of the exclude-tags will be excluded. When combined with + the --include-tag flag both conditions must be met for a suite to run. + --test-stats print the number of tests (included and excluded) to STDERR + --updateBaselines replace baseline screenshots with whatever is generated from the test + --updateSnapshots replace inline and file snapshots with whatever is generated from the test + -u replace both baseline screenshots and snapshots + --kibana-install-dir directory where the Kibana install being tested resides + --throttle enable network throttling in Chrome browser + --headless run browser in headless mode + `, }, } ); diff --git a/src/plugins/inspector/common/adapters/data/formatted_data.ts b/scripts/ensure_all_tests_in_ci_group.js similarity index 88% rename from src/plugins/inspector/common/adapters/data/formatted_data.ts rename to scripts/ensure_all_tests_in_ci_group.js index 08c956f27d011..d189aac8f62e8 100644 --- a/src/plugins/inspector/common/adapters/data/formatted_data.ts +++ b/scripts/ensure_all_tests_in_ci_group.js @@ -17,6 +17,5 @@ * under the License. */ -export class FormattedData { - constructor(public readonly raw: any, public readonly formatted: any) {} -} +require('../src/setup_node_env'); +require('../src/dev/run_ensure_all_tests_in_ci_group'); diff --git a/src/core/public/application/capabilities/capabilities_service.test.ts b/src/core/public/application/capabilities/capabilities_service.test.ts index 286a93fdc2398..aa9c10ecfb2b2 100644 --- a/src/core/public/application/capabilities/capabilities_service.test.ts +++ b/src/core/public/application/capabilities/capabilities_service.test.ts @@ -41,11 +41,36 @@ describe('#start', () => { http.post.mockReturnValue(Promise.resolve(mockedCapabilities)); }); + it('requests default capabilities on anonymous paths', async () => { + http.anonymousPaths.isAnonymous.mockReturnValue(true); + const service = new CapabilitiesService(); + const appIds = ['app1', 'app2', 'legacyApp1', 'legacyApp2']; + const { capabilities } = await service.start({ + http, + appIds, + }); + + expect(http.post).toHaveBeenCalledWith('/api/core/capabilities', { + query: { + useDefaultCapabilities: true, + }, + body: JSON.stringify({ applications: appIds }), + }); + + // @ts-expect-error TypeScript knows this shouldn't be possible + expect(() => (capabilities.foo = 'foo')).toThrowError(); + }); + it('only returns capabilities for given appIds', async () => { const service = new CapabilitiesService(); + const appIds = ['app1', 'app2', 'legacyApp1', 'legacyApp2']; const { capabilities } = await service.start({ http, - appIds: ['app1', 'app2', 'legacyApp1', 'legacyApp2'], + appIds, + }); + + expect(http.post).toHaveBeenCalledWith('/api/core/capabilities', { + body: JSON.stringify({ applications: appIds }), }); // @ts-expect-error TypeScript knows this shouldn't be possible diff --git a/src/core/public/application/capabilities/capabilities_service.tsx b/src/core/public/application/capabilities/capabilities_service.tsx index 1164164aec4c5..156b75b2d8abe 100644 --- a/src/core/public/application/capabilities/capabilities_service.tsx +++ b/src/core/public/application/capabilities/capabilities_service.tsx @@ -38,7 +38,9 @@ export interface CapabilitiesStart { */ export class CapabilitiesService { public async start({ appIds, http }: StartDeps): Promise { + const useDefaultCapabilities = http.anonymousPaths.isAnonymous(window.location.pathname); const capabilities = await http.post('/api/core/capabilities', { + query: useDefaultCapabilities ? { useDefaultCapabilities } : undefined, body: JSON.stringify({ applications: appIds }), }); diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index b39aa70c888fe..96d669a7b96f4 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -31,6 +31,7 @@ export { AppNavLinkStatus, AppUpdatableFields, AppUpdater, + AppMeta, AppSearchDeepLink, ApplicationSetup, ApplicationStart, @@ -41,6 +42,7 @@ export { AppLeaveConfirmAction, NavigateToAppOptions, PublicAppInfo, + PublicAppMetaInfo, PublicAppSearchDeepLinkInfo, // Internal types InternalApplicationSetup, diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index c161a7f166541..0a31490ad664c 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -83,7 +83,7 @@ export enum AppNavLinkStatus { */ export type AppUpdatableFields = Pick< App, - 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'searchDeepLinks' + 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'meta' >; /** @@ -237,39 +237,76 @@ export interface App { exactRoute?: boolean; /** - * Array of links that represent secondary in-app locations for the app. + * Meta data for an application that represent additional information for the app. + * See {@link AppMeta} * * @remarks * Used to populate navigational search results (where available). - * Can be updated using the {@link App.updater$} observable. See {@link AppSubLink} for more details. + * Can be updated using the {@link App.updater$} observable. See {@link PublicAppSearchDeepLinkInfo} for more details. * * @example - * The `path` property on deep links should not include the application's `appRoute`: * ```ts * core.application.register({ * id: 'my_app', - * title: 'My App', - * searchDeepLinks: [ - * { id: 'sub1', title: 'Sub1', path: '/sub1' }, + * title: 'Translated title', + * meta: { + * keywords: ['translated keyword1', 'translated keyword2'], + * searchDeepLinks: [ + * { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, * { * id: 'sub2', * title: 'Sub2', * searchDeepLinks: [ - * { id: 'subsub', title: 'SubSub', path: '/sub2/sub' } + * { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } * ] * } * ], - * mount: () => { ... }, + * }, + * mount: () => { ... } * }) * ``` - * - * Will produce deep links on these paths: - * - `/app/my_app/sub1` - * - `/app/my_app/sub2/sub` */ + meta?: AppMeta; +} + +/** + * Input type for meta data for an application. + * + * Meta fields include `keywords` and `searchDeepLinks` + * Keywords is an array of string with which to associate the app, must include at least one unique string as an array. + * `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. + * @public + */ +export interface AppMeta { + /** Keywords to represent this application */ + keywords?: string[]; + /** Array of links that represent secondary in-app locations for the app. */ searchDeepLinks?: AppSearchDeepLink[]; } +/** + * Public information about a registered app's {@link AppMeta | keywords } + * + * @public + */ +export type PublicAppMetaInfo = Omit & { + keywords: string[]; + searchDeepLinks: PublicAppSearchDeepLinkInfo[]; +}; + +/** + * Public information about a registered app's {@link AppSearchDeepLink | searchDeepLinks} + * + * @public + */ +export type PublicAppSearchDeepLinkInfo = Omit< + AppSearchDeepLink, + 'searchDeepLinks' | 'keywords' +> & { + searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + keywords: string[]; +}; + /** * Input type for registering secondary in-app locations for an application. * @@ -289,35 +326,30 @@ export type AppSearchDeepLink = { path: string; /** Optional array of links that are 'underneath' this section in the hierarchy */ searchDeepLinks?: AppSearchDeepLink[]; + /** Optional keywords to match with in deep links search for the page at the path */ + keywords?: string[]; } | { /** Optional path to access this section. Omit if this part of the hierarchy does not have a page URL. */ path?: string; /** Array links that are 'underneath' this section in this hierarchy. */ searchDeepLinks: AppSearchDeepLink[]; + /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ + keywords?: string[]; } ); -/** - * Public information about a registered app's {@link AppSearchDeepLink | searchDeepLinks} - * - * @public - */ -export type PublicAppSearchDeepLinkInfo = Omit & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; -}; - /** * Public information about a registered {@link App | application} * * @public */ -export type PublicAppInfo = Omit & { +export type PublicAppInfo = Omit & { // remove optional on fields populated with default values status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + meta: PublicAppMetaInfo; }; /** diff --git a/src/core/public/application/utils/get_app_info.test.ts b/src/core/public/application/utils/get_app_info.test.ts index ee0bd4f1eadfa..ff09a18c8b655 100644 --- a/src/core/public/application/utils/get_app_info.test.ts +++ b/src/core/public/application/utils/get_app_info.test.ts @@ -43,19 +43,24 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - searchDeepLinks: [], + meta: { + keywords: [], + searchDeepLinks: [], + }, }); }); it('populates default values for nested searchDeepLinks', () => { const app = createApp({ - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], - }, - ], + meta: { + searchDeepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + searchDeepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], + }, + ], + }, }); const info = getAppInfo(app); @@ -65,20 +70,25 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - searchDeepLinks: [], // default empty array added - }, - ], - }, - ], + meta: { + keywords: [], + searchDeepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], + searchDeepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: [], + searchDeepLinks: [], // default empty array added + }, + ], + }, + ], + }, }); }); @@ -108,4 +118,53 @@ describe('getAppInfo', () => { }) ); }); + + it('adds default meta fields to sublinks when needed', () => { + const app = createApp({ + meta: { + searchDeepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + searchDeepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + }, + ], + }, + ], + }, + }); + const info = getAppInfo(app); + + expect(info).toEqual({ + id: 'some-id', + title: 'some-title', + status: AppStatus.accessible, + navLinkStatus: AppNavLinkStatus.visible, + appRoute: `/app/some-id`, + meta: { + keywords: [], + searchDeepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], // default empty array + searchDeepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + searchDeepLinks: [], + }, + ], + }, + ], + }, + }); + }); }); diff --git a/src/core/public/application/utils/get_app_info.ts b/src/core/public/application/utils/get_app_info.ts index 7316080816da7..574696c3bd5f2 100644 --- a/src/core/public/application/utils/get_app_info.ts +++ b/src/core/public/application/utils/get_app_info.ts @@ -39,7 +39,10 @@ export function getAppInfo(app: App): PublicAppInfo { status: app.status!, navLinkStatus, appRoute: app.appRoute!, - searchDeepLinks: getSearchDeepLinkInfos(app, app.searchDeepLinks), + meta: { + keywords: app.meta?.keywords ?? [], + searchDeepLinks: getSearchDeepLinkInfos(app, app.meta?.searchDeepLinks), + }, }; } @@ -57,6 +60,7 @@ function getSearchDeepLinkInfos( id: rawDeepLink.id, title: rawDeepLink.title, path: rawDeepLink.path, + keywords: rawDeepLink.keywords ?? [], searchDeepLinks: getSearchDeepLinkInfos(app, rawDeepLink.searchDeepLinks), }; } diff --git a/src/core/public/chrome/nav_links/to_nav_link.test.ts b/src/core/public/chrome/nav_links/to_nav_link.test.ts index 606370c5afd0a..44feb133cfcec 100644 --- a/src/core/public/chrome/nav_links/to_nav_link.test.ts +++ b/src/core/public/chrome/nav_links/to_nav_link.test.ts @@ -28,7 +28,10 @@ const app = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.default, appRoute: `/app/some-id`, - searchDeepLinks: [], + meta: { + keywords: [], + searchDeepLinks: [], + }, ...props, }); diff --git a/src/core/public/chrome/ui/header/_index.scss b/src/core/public/chrome/ui/header/_index.scss index 44cd864278325..b11e7e47f4ae7 100644 --- a/src/core/public/chrome/ui/header/_index.scss +++ b/src/core/public/chrome/ui/header/_index.scss @@ -1,5 +1,19 @@ @include euiHeaderAffordForFixed; +.euiDataGrid__restrictBody { + .headerGlobalNav, + .kbnQueryBar { + display: none; + } +} + +.euiDataGrid__restrictBody.euiBody--headerIsFixed { + .euiFlyout { + top: 0; + height: 100%; + } +} + .chrHeaderHelpMenu__version { text-transform: none; } diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index b8843b5c85595..a9e55fdc22dc6 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -72,6 +72,7 @@ export class DocLinksService { aggs: { date_histogram: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-datehistogram-aggregation.html`, date_range: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-daterange-aggregation.html`, + date_format_pattern: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-daterange-aggregation.html#date-format-pattern`, filter: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-filter-aggregation.html`, filters: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-filters-aggregation.html`, geohash_grid: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-geohashgrid-aggregation.html`, @@ -101,12 +102,14 @@ export class DocLinksService { sum: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-sum-aggregation.html`, top_hits: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-top-hits-aggregation.html`, }, + runtimeFields: `${ELASTICSEARCH_DOCS}runtime.html`, scriptedFields: { scriptFields: `${ELASTICSEARCH_DOCS}search-request-script-fields.html`, scriptAggs: `${ELASTICSEARCH_DOCS}search-aggregations.html#_values_source`, painless: `${ELASTICSEARCH_DOCS}modules-scripting-painless.html`, painlessApi: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/painless/${DOC_LINK_VERSION}/painless-api-reference.html`, painlessSyntax: `${ELASTICSEARCH_DOCS}modules-scripting-painless-syntax.html`, + painlessLanguage: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/painless/${DOC_LINK_VERSION}/painless-lang-spec.html`, luceneExpressions: `${ELASTICSEARCH_DOCS}modules-scripting-expression.html`, }, indexPatterns: { @@ -115,6 +118,13 @@ export class DocLinksService { }, addData: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/connect-to-elasticsearch.html`, kibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index.html`, + elasticsearch: { + remoteClusters: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html`, + remoteClustersProxy: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html#proxy-mode`, + remoteClusersProxySettings: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html#remote-cluster-proxy-settings`, + scriptParameters: `${ELASTICSEARCH_DOCS}modules-scripting-using.html#prefer-params`, + transportSettings: `${ELASTICSEARCH_DOCS}modules-transport.html`, + }, siem: { guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, gettingStarted: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, @@ -147,16 +157,75 @@ export class DocLinksService { featureImportance: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-feature-importance.html`, outlierDetectionRoc: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-roc`, regressionEvaluation: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-regression-evaluation`, + classificationAucRoc: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-class-aucroc`, }, transforms: { - guide: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/transforms.html`, + guide: `${ELASTICSEARCH_DOCS}transforms.html`, }, visualize: { - guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/visualize.html`, + guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/dashboard.html`, timelionDeprecation: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/dashboard.html#timelion-deprecation`, lens: `${ELASTIC_WEBSITE_URL}what-is/kibana-lens`, maps: `${ELASTIC_WEBSITE_URL}maps`, }, + observability: { + guide: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/index.html`, + }, + alerting: { + guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/managing-alerts-and-actions.html`, + actionTypes: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/action-types.html`, + emailAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/email-action-type.html`, + generalSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-action-settings-kb.html#general-alert-action-settings`, + indexAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index-action-type.html`, + indexThreshold: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-types.html#alert-type-index-threshold`, + pagerDutyAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/pagerduty-action-type.html`, + preconfiguredConnectors: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/pre-configured-action-types-and-connectors.html`, + serviceNowAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/servicenow-action-type.html`, + setupPrerequisites: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alerting-getting-started.html#alerting-setup-prerequisites`, + slackAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/slack-action-type.html`, + teamsAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/teams-action-type.html`, + }, + maps: { + guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/kibana-maps.html`, + }, + monitoring: { + alertsKibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/kibana-alerts.html`, + monitorElasticsearch: `${ELASTICSEARCH_DOCS}configuring-metricbeat.html`, + monitorKibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/monitoring-metricbeat.html`, + }, + security: { + apiKeyServiceSettings: `${ELASTICSEARCH_DOCS}security-settings.html#api-key-service-settings`, + clusterPrivileges: `${ELASTICSEARCH_DOCS}security-privileges.html#privileges-list-cluster`, + elasticsearchSettings: `${ELASTICSEARCH_DOCS}security-settings.html`, + indicesPrivileges: `${ELASTICSEARCH_DOCS}security-privileges.html#privileges-list-indices`, + kibanaTLS: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/configuring-tls.html`, + kibanaPrivileges: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/kibana-privileges.html`, + mappingRoles: `${ELASTICSEARCH_DOCS}mapping-roles.html`, + }, + watcher: { + jiraAction: `${ELASTICSEARCH_DOCS}actions-jira.html`, + pagerDutyAction: `${ELASTICSEARCH_DOCS}actions-pagerduty.html`, + slackAction: `${ELASTICSEARCH_DOCS}actions-slack.html`, + ui: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/watcher-ui.html`, + }, + ccs: { + guide: `${ELASTICSEARCH_DOCS}modules-cross-cluster-search.html`, + }, + apis: { + createIndex: `${ELASTICSEARCH_DOCS}indices-create-index.html`, + createSnapshotLifecylePolicy: `${ELASTICSEARCH_DOCS}slm-api-put-policy.html`, + createRoleMapping: `${ELASTICSEARCH_DOCS}security-api-put-role-mapping.html`, + createApiKey: `${ELASTICSEARCH_DOCS}security-api-create-api-key.html`, + createPipeline: `${ELASTICSEARCH_DOCS}put-pipeline-api.html`, + createTransformRequest: `${ELASTICSEARCH_DOCS}put-transform.html#put-transform-request-body`, + executeWatchActionModes: `${ELASTICSEARCH_DOCS}watcher-api-execute-watch.html#watcher-api-execute-watch-action-mode`, + openIndex: `${ELASTICSEARCH_DOCS}indices-open-close.html`, + putComponentTemplate: `${ELASTICSEARCH_DOCS}indices-component-template.html`, + painlessExecute: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/painless/${DOC_LINK_VERSION}/painless-execute-api.html`, + putComponentTemplateMetadata: `${ELASTICSEARCH_DOCS}indices-component-template.html#component-templates-metadata`, + putWatch: `${ELASTICSEARCH_DOCS}/watcher-api-put-watch.html`, + updateTransform: `${ELASTICSEARCH_DOCS}update-transform.html`, + }, }, }); } @@ -203,6 +272,7 @@ export interface DocLinksStart { readonly aggs: { readonly date_histogram: string; readonly date_range: string; + readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; @@ -232,6 +302,7 @@ export interface DocLinksStart { readonly sum: string; readonly top_hits: string; }; + readonly runtimeFields: string; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; @@ -246,6 +317,7 @@ export interface DocLinksStart { }; readonly addData: string; readonly kibana: string; + readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; @@ -263,5 +335,13 @@ export interface DocLinksStart { readonly ml: Record; readonly transforms: Record; readonly visualize: Record; + readonly apis: Record; + readonly observability: Record; + readonly alerting: Record; + readonly maps: Record; + readonly monitoring: Record; + readonly security: Record; + readonly watcher: Record; + readonly ccs: Record; }; } diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 2e1238df350e0..51375072d3e5a 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -108,10 +108,12 @@ export { AppLeaveConfirmAction, AppStatus, AppNavLinkStatus, + AppMeta, AppUpdatableFields, AppUpdater, AppSearchDeepLink, PublicAppInfo, + PublicAppMetaInfo, PublicAppSearchDeepLinkInfo, ScopedHistory, NavigateToAppOptions, diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index defe43377172c..26ce358cc9ade 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -56,11 +56,10 @@ export interface App { exactRoute?: boolean; icon?: string; id: string; + meta?: AppMeta; mount: AppMount | AppMountDeprecated; navLinkStatus?: AppNavLinkStatus; order?: number; - // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AppSubLink" - searchDeepLinks?: AppSearchDeepLink[]; status?: AppStatus; title: string; tooltip?: string; @@ -137,6 +136,12 @@ export interface ApplicationStart { registerMountContext(contextName: T, provider: IContextProvider): void; } +// @public +export interface AppMeta { + keywords?: string[]; + searchDeepLinks?: AppSearchDeepLink[]; +} + // @public export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; @@ -186,9 +191,11 @@ export type AppSearchDeepLink = { } & ({ path: string; searchDeepLinks?: AppSearchDeepLink[]; + keywords?: string[]; } | { path?: string; searchDeepLinks: AppSearchDeepLink[]; + keywords?: string[]; }); // @public @@ -201,7 +208,7 @@ export enum AppStatus { export type AppUnmount = () => void; // @public -export type AppUpdatableFields = Pick; +export type AppUpdatableFields = Pick; // @public export type AppUpdater = (app: App) => Partial | undefined; @@ -516,6 +523,7 @@ export interface DocLinksStart { readonly aggs: { readonly date_histogram: string; readonly date_range: string; + readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; @@ -545,6 +553,7 @@ export interface DocLinksStart { readonly sum: string; readonly top_hits: string; }; + readonly runtimeFields: string; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; @@ -559,6 +568,7 @@ export interface DocLinksStart { }; readonly addData: string; readonly kibana: string; + readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; @@ -576,6 +586,14 @@ export interface DocLinksStart { readonly ml: Record; readonly transforms: Record; readonly visualize: Record; + readonly apis: Record; + readonly observability: Record; + readonly alerting: Record; + readonly maps: Record; + readonly monitoring: Record; + readonly security: Record; + readonly watcher: Record; + readonly ccs: Record; }; } @@ -1008,16 +1026,23 @@ export interface PluginInitializerContext export type PluginOpaqueId = symbol; // @public -export type PublicAppInfo = Omit & { +export type PublicAppInfo = Omit & { status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; + meta: PublicAppMetaInfo; +}; + +// @public +export type PublicAppMetaInfo = Omit & { + keywords: string[]; searchDeepLinks: PublicAppSearchDeepLinkInfo[]; }; // @public -export type PublicAppSearchDeepLinkInfo = Omit & { +export type PublicAppSearchDeepLinkInfo = Omit & { searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + keywords: string[]; }; // @public diff --git a/src/core/server/capabilities/capabilities_service.ts b/src/core/server/capabilities/capabilities_service.ts index f0be9743d4d60..9af945d17b2ad 100644 --- a/src/core/server/capabilities/capabilities_service.ts +++ b/src/core/server/capabilities/capabilities_service.ts @@ -76,7 +76,19 @@ export interface CapabilitiesSetup { * ```ts * // my-plugin/server/plugin.ts * public setup(core: CoreSetup, deps: {}) { - * core.capabilities.registerSwitcher((request, capabilities) => { + * core.capabilities.registerSwitcher((request, capabilities, useDefaultCapabilities) => { + * // useDefaultCapabilities is a special case that switchers typically don't have to concern themselves with. + * // The default capabilities are typically the ones you provide in your CapabilitiesProvider, but this flag + * // gives each switcher an opportunity to change the default capabilities of other plugins' capabilities. + * // For example, you may decide to flip another plugin's capability to false if today is Tuesday, + * // but you wouldn't want to do this when we are requesting the default set of capabilities. + * if (useDefaultCapabilities) { + * return { + * somePlugin: { + * featureEnabledByDefault: true + * } + * } + * } * if(myPluginApi.shouldRestrictSomePluginBecauseOf(request)) { * return { * somePlugin: { @@ -150,7 +162,7 @@ export class CapabilitiesService { public start(): CapabilitiesStart { return { - resolveCapabilities: (request) => this.resolveCapabilities(request, []), + resolveCapabilities: (request) => this.resolveCapabilities(request, [], false), }; } } diff --git a/src/core/server/capabilities/integration_tests/capabilities_service.test.ts b/src/core/server/capabilities/integration_tests/capabilities_service.test.ts index 17f2c77bbf660..4217dd98ae735 100644 --- a/src/core/server/capabilities/integration_tests/capabilities_service.test.ts +++ b/src/core/server/capabilities/integration_tests/capabilities_service.test.ts @@ -72,17 +72,57 @@ describe('CapabilitiesService', () => { `); }); - it('uses the service capabilities providers', async () => { - serviceSetup.registerProvider(() => ({ + it('uses the service capabilities providers and switchers', async () => { + const getInitialCapabilities = () => ({ catalogue: { something: true, }, - })); + management: {}, + navLinks: {}, + }); + serviceSetup.registerProvider(() => getInitialCapabilities()); + + const switcher = jest.fn((_, capabilities) => capabilities); + serviceSetup.registerSwitcher(switcher); const result = await supertest(httpSetup.server.listener) .post('/api/core/capabilities') .send({ applications: [] }) .expect(200); + + expect(switcher).toHaveBeenCalledTimes(1); + expect(switcher).toHaveBeenCalledWith(expect.anything(), getInitialCapabilities(), false); + expect(result.body).toMatchInlineSnapshot(` + Object { + "catalogue": Object { + "something": true, + }, + "management": Object {}, + "navLinks": Object {}, + } + `); + }); + + it('passes useDefaultCapabilities to registered switchers', async () => { + const getInitialCapabilities = () => ({ + catalogue: { + something: true, + }, + management: {}, + navLinks: {}, + }); + serviceSetup.registerProvider(() => getInitialCapabilities()); + + const switcher = jest.fn((_, capabilities) => capabilities); + serviceSetup.registerSwitcher(switcher); + + const result = await supertest(httpSetup.server.listener) + .post('/api/core/capabilities?useDefaultCapabilities=true') + .send({ applications: [] }) + .expect(200); + + expect(switcher).toHaveBeenCalledTimes(1); + expect(switcher).toHaveBeenCalledWith(expect.anything(), getInitialCapabilities(), true); expect(result.body).toMatchInlineSnapshot(` Object { "catalogue": Object { diff --git a/src/core/server/capabilities/resolve_capabilities.test.ts b/src/core/server/capabilities/resolve_capabilities.test.ts index 372efeff21ae2..21c723ea1ddc3 100644 --- a/src/core/server/capabilities/resolve_capabilities.test.ts +++ b/src/core/server/capabilities/resolve_capabilities.test.ts @@ -36,7 +36,7 @@ describe('resolveCapabilities', () => { }); it('returns the initial capabilities if no switcher are used', async () => { - const result = await resolveCapabilities(defaultCaps, [], request, []); + const result = await resolveCapabilities(defaultCaps, [], request, [], true); expect(result).toEqual(defaultCaps); }); @@ -55,7 +55,7 @@ describe('resolveCapabilities', () => { A: false, }, }); - const result = await resolveCapabilities(caps, [switcher], request, []); + const result = await resolveCapabilities(caps, [switcher], request, [], true); expect(result).toMatchInlineSnapshot(` Object { "catalogue": Object { @@ -83,7 +83,7 @@ describe('resolveCapabilities', () => { A: false, }, }); - await resolveCapabilities(caps, [switcher], request, []); + await resolveCapabilities(caps, [switcher], request, [], true); expect(caps.catalogue).toEqual({ A: true, B: true, @@ -105,7 +105,7 @@ describe('resolveCapabilities', () => { C: false, }, }); - const result = await resolveCapabilities(caps, [switcher], request, []); + const result = await resolveCapabilities(caps, [switcher], request, [], true); expect(result.catalogue).toEqual({ A: true, B: true, @@ -127,7 +127,7 @@ describe('resolveCapabilities', () => { .filter(([key]) => key !== 'B') .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}), }); - const result = await resolveCapabilities(caps, [switcher], request, []); + const result = await resolveCapabilities(caps, [switcher], request, [], true); expect(result.catalogue).toEqual({ A: true, B: true, @@ -153,7 +153,7 @@ describe('resolveCapabilities', () => { record: false, }, }); - const result = await resolveCapabilities(caps, [switcher], request, []); + const result = await resolveCapabilities(caps, [switcher], request, [], true); expect(result.section).toEqual({ boolean: true, record: { diff --git a/src/core/server/capabilities/resolve_capabilities.ts b/src/core/server/capabilities/resolve_capabilities.ts index 1be504d4bc314..6f4eff6b882d0 100644 --- a/src/core/server/capabilities/resolve_capabilities.ts +++ b/src/core/server/capabilities/resolve_capabilities.ts @@ -23,7 +23,8 @@ import { KibanaRequest } from '../http'; export type CapabilitiesResolver = ( request: KibanaRequest, - applications: string[] + applications: string[], + useDefaultCapabilities: boolean ) => Promise; export const getCapabilitiesResolver = ( @@ -31,16 +32,24 @@ export const getCapabilitiesResolver = ( switchers: () => CapabilitiesSwitcher[] ): CapabilitiesResolver => async ( request: KibanaRequest, - applications: string[] + applications: string[], + useDefaultCapabilities: boolean ): Promise => { - return resolveCapabilities(capabilities(), switchers(), request, applications); + return resolveCapabilities( + capabilities(), + switchers(), + request, + applications, + useDefaultCapabilities + ); }; export const resolveCapabilities = async ( capabilities: Capabilities, switchers: CapabilitiesSwitcher[], request: KibanaRequest, - applications: string[] + applications: string[], + useDefaultCapabilities: boolean ): Promise => { const mergedCaps = cloneDeep({ ...capabilities, @@ -54,7 +63,7 @@ export const resolveCapabilities = async ( }); return switchers.reduce(async (caps, switcher) => { const resolvedCaps = await caps; - const changes = await switcher(request, resolvedCaps); + const changes = await switcher(request, resolvedCaps, useDefaultCapabilities); return recursiveApplyChanges(resolvedCaps, changes); }, Promise.resolve(mergedCaps)); }; diff --git a/src/core/server/capabilities/routes/resolve_capabilities.ts b/src/core/server/capabilities/routes/resolve_capabilities.ts index 3fb1bb3d13d0b..3694c4b894684 100644 --- a/src/core/server/capabilities/routes/resolve_capabilities.ts +++ b/src/core/server/capabilities/routes/resolve_capabilities.ts @@ -29,14 +29,18 @@ export function registerCapabilitiesRoutes(router: IRouter, resolver: Capabiliti authRequired: 'optional', }, validate: { + query: schema.object({ + useDefaultCapabilities: schema.boolean({ defaultValue: false }), + }), body: schema.object({ applications: schema.arrayOf(schema.string()), }), }, }, async (ctx, req, res) => { + const { useDefaultCapabilities } = req.query; const { applications } = req.body; - const capabilities = await resolver(req, applications); + const capabilities = await resolver(req, applications, useDefaultCapabilities); return res.ok({ body: capabilities, }); diff --git a/src/core/server/capabilities/types.ts b/src/core/server/capabilities/types.ts index 105233761a437..efef31dcc8417 100644 --- a/src/core/server/capabilities/types.ts +++ b/src/core/server/capabilities/types.ts @@ -34,5 +34,6 @@ export type CapabilitiesProvider = () => Partial; */ export type CapabilitiesSwitcher = ( request: KibanaRequest, - uiCapabilities: Capabilities + uiCapabilities: Capabilities, + useDefaultCapabilities: boolean ) => Partial | Promise>; diff --git a/src/core/server/elasticsearch/legacy/errors.ts b/src/core/server/elasticsearch/legacy/errors.ts index e557e7395fe56..adc1fa0728784 100644 --- a/src/core/server/elasticsearch/legacy/errors.ts +++ b/src/core/server/elasticsearch/legacy/errors.ts @@ -30,7 +30,7 @@ enum ErrorCode { * @deprecated. The new elasticsearch client doesn't wrap errors anymore. * @public * */ -export interface LegacyElasticsearchError extends Boom { +export interface LegacyElasticsearchError extends Boom.Boom { [code]?: string; } @@ -86,7 +86,7 @@ export class LegacyElasticsearchErrorHelpers { const decoratedError = decorate(error, ErrorCode.NOT_AUTHORIZED, 401, reason); const wwwAuthHeader = get(error, 'body.error.header[WWW-Authenticate]') as string; - decoratedError.output.headers['WWW-Authenticate'] = + (decoratedError.output.headers as { [key: string]: string })['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; return decoratedError; diff --git a/src/core/server/http/cookie_session_storage.ts b/src/core/server/http/cookie_session_storage.ts index 1ff0670d78f4e..40bca89c21cb3 100644 --- a/src/core/server/http/cookie_session_storage.ts +++ b/src/core/server/http/cookie_session_storage.ts @@ -19,8 +19,6 @@ import { Request, Server } from '@hapi/hapi'; import hapiAuthCookie from '@hapi/cookie'; -// @ts-expect-error no TS definitions -import Statehood from '@hapi/statehood'; import { KibanaRequest, ensureRawRequest } from './router'; import { SessionStorageFactory, SessionStorage } from './session_storage'; @@ -148,7 +146,7 @@ export async function createCookieSessionStorageFactory( path: basePath === undefined ? '/' : basePath, clearInvalid: false, isHttpOnly: true, - isSameSite: cookieOptions.sameSite === 'None' ? false : cookieOptions.sameSite ?? false, + isSameSite: cookieOptions.sameSite ?? false, }, validateFunc: async (req: Request, session: T | T[]) => { const result = cookieOptions.validate(session); @@ -159,23 +157,6 @@ export async function createCookieSessionStorageFactory( }, }); - // A hack to support SameSite: 'None'. - // Remove it after update Hapi to v19 that supports SameSite: 'None' out of the box. - if (cookieOptions.sameSite === 'None') { - log.debug('Patching Statehood.prepareValue'); - const originalPrepareValue = Statehood.prepareValue; - Statehood.prepareValue = function kibanaStatehoodPrepareValueWrapper( - name: string, - value: unknown, - options: any - ) { - if (name === cookieOptions.name) { - options.isSameSite = cookieOptions.sameSite; - } - return originalPrepareValue(name, value, options); - }; - } - return { asScoped(request: KibanaRequest) { return new ScopedCookieSessionStorage(log, server, ensureRawRequest(request)); diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index 2bd296fe338ab..61a9b5f04b23f 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -195,7 +195,13 @@ export class HttpConfig { rawExternalUrlConfig: ExternalUrlConfig ) { this.autoListen = rawHttpConfig.autoListen; - this.host = rawHttpConfig.host; + // TODO: Consider dropping support for '0' in v8.0.0. This value is passed + // to hapi, which validates it. Prior to hapi v20, '0' was considered a + // valid host, however the validation logic internally in hapi was + // re-written for v20 and hapi no longer considers '0' a valid host. For + // details, see: + // https://github.com/elastic/kibana/issues/86716#issuecomment-749623781 + this.host = rawHttpConfig.host === '0' ? '0.0.0.0' : rawHttpConfig.host; this.port = rawHttpConfig.port; this.cors = rawHttpConfig.cors; this.customResponseHeaders = Object.entries(rawHttpConfig.customResponseHeaders ?? {}).reduce( diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 71040598d34b1..cbb60480c4cf1 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -1214,7 +1214,7 @@ describe('timeout options', () => { router.get( { path: '/', - validate: { body: schema.any() }, + validate: { body: schema.maybe(schema.any()) }, }, (context, req, res) => { return res.ok({ @@ -1247,7 +1247,7 @@ describe('timeout options', () => { router.get( { path: '/', - validate: { body: schema.any() }, + validate: { body: schema.maybe(schema.any()) }, options: { timeout: { idleSocket: 12000 } }, }, (context, req, res) => { diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index 43f5264ff22e3..81f7c9c45ba50 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -176,12 +176,6 @@ export class HttpServer { xsrfRequired: route.options.xsrfRequired ?? !isSafeMethod(route.method), }; - // To work around https://github.com/hapijs/hapi/issues/4122 until v20, set the socket - // timeout on the route to a fake timeout only when the payload timeout is specified. - // Within the onPreAuth lifecycle of the route itself, we'll override the timeout with the - // real socket timeout. - const fakeSocketTimeout = timeout?.payload ? timeout.payload + 1 : undefined; - this.server.route({ handler: route.handler, method: route.method, @@ -189,41 +183,25 @@ export class HttpServer { options: { auth: this.getAuthOption(authRequired), app: kibanaRouteOptions, - ext: { - onPreAuth: { - method: (request, h) => { - // At this point, the socket timeout has only been set to work-around the HapiJS bug. - // We need to either set the real per-route timeout or use the default idle socket timeout - if (timeout?.idleSocket) { - request.raw.req.socket.setTimeout(timeout.idleSocket); - } else if (fakeSocketTimeout) { - // NodeJS uses a socket timeout of `0` to denote "no timeout" - request.raw.req.socket.setTimeout(this.config!.socketTimeout ?? 0); - } - - return h.continue; - }, - }, - }, tags: tags ? Array.from(tags) : undefined, // TODO: This 'validate' section can be removed once the legacy platform is completely removed. // We are telling Hapi that NP routes can accept any payload, so that it can bypass the default // validation applied in ./http_tools#getServerOptions // (All NP routes are already required to specify their own validation in order to access the payload) validate, - payload: [allow, maxBytes, output, parse, timeout?.payload].some( - (v) => typeof v !== 'undefined' - ) + // @ts-expect-error Types are outdated and doesn't allow `payload.multipart` to be `true` + payload: [allow, maxBytes, output, parse, timeout?.payload].some((x) => x !== undefined) ? { allow, maxBytes, output, parse, timeout: timeout?.payload, + multipart: true, } : undefined, timeout: { - socket: fakeSocketTimeout, + socket: timeout?.idleSocket ?? this.config!.socketTimeout, }, }, }); diff --git a/src/core/server/http/http_tools.ts b/src/core/server/http/http_tools.ts index 8bec26f31fa26..f09f3dc2730a1 100644 --- a/src/core/server/http/http_tools.ts +++ b/src/core/server/http/http_tools.ts @@ -29,8 +29,8 @@ import Hoek from '@hapi/hoek'; import type { ServerOptions as TLSOptions } from 'https'; import type { ValidationError } from 'joi'; import uuid from 'uuid'; +import { ensureNoUnsafeProperties } from '@kbn/std'; import { HttpConfig } from './http_config'; -import { validateObject } from './prototype_pollution'; const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; /** @@ -69,7 +69,7 @@ export function getServerOptions(config: HttpConfig, { configureTLS = true } = { // This is a default payload validation which applies to all LP routes which do not specify their own // `validate.payload` handler, in order to reduce the likelyhood of prototype pollution vulnerabilities. // (All NP routes are already required to specify their own validation in order to access the payload) - payload: (value) => Promise.resolve(validateObject(value)), + payload: (value) => Promise.resolve(ensureNoUnsafeProperties(value)), }, }, state: { diff --git a/src/core/server/http/lifecycle/on_pre_response.ts b/src/core/server/http/lifecycle/on_pre_response.ts index 42179374ec672..9efcf46148e1f 100644 --- a/src/core/server/http/lifecycle/on_pre_response.ts +++ b/src/core/server/http/lifecycle/on_pre_response.ts @@ -142,7 +142,11 @@ export function adoptToHapiOnPreResponseFormat(fn: OnPreResponseHandler, log: Lo if (preResponseResult.isNext(result)) { if (result.headers) { if (isBoom(response)) { - findHeadersIntersection(response.output.headers, result.headers, log); + findHeadersIntersection( + response.output.headers as { [key: string]: string }, + result.headers, + log + ); // hapi wraps all error response in Boom object internally response.output.headers = { ...response.output.headers, @@ -157,7 +161,7 @@ export function adoptToHapiOnPreResponseFormat(fn: OnPreResponseHandler, log: Lo const overriddenResponse = responseToolkit.response(result.body).code(statusCode); const originalHeaders = isBoom(response) ? response.output.headers : response.headers; - setHeaders(overriddenResponse, originalHeaders); + setHeaders(overriddenResponse, originalHeaders as { [key: string]: string }); if (result.headers) { setHeaders(overriddenResponse, result.headers); } @@ -178,8 +182,8 @@ export function adoptToHapiOnPreResponseFormat(fn: OnPreResponseHandler, log: Lo }; } -function isBoom(response: any): response is Boom { - return response instanceof Boom; +function isBoom(response: any): response is Boom.Boom { + return response instanceof Boom.Boom; } function setHeaders(response: ResponseObject, headers: ResponseHeaders) { diff --git a/src/core/server/http/router/error_wrapper.ts b/src/core/server/http/router/error_wrapper.ts index 5a4b7e9f77582..7d141e81ddf36 100644 --- a/src/core/server/http/router/error_wrapper.ts +++ b/src/core/server/http/router/error_wrapper.ts @@ -29,7 +29,7 @@ export const wrapErrors: RequestHandlerWrapper = (handler) => { return response.customError({ body: e.output.payload, statusCode: e.output.statusCode, - headers: e.output.headers, + headers: e.output.headers as { [key: string]: string }, }); } throw e; diff --git a/src/core/server/http/router/response_adapter.ts b/src/core/server/http/router/response_adapter.ts index 63acd2207ac3a..d80c21bde8de8 100644 --- a/src/core/server/http/router/response_adapter.ts +++ b/src/core/server/http/router/response_adapter.ts @@ -56,7 +56,7 @@ export class HapiResponseAdapter { } public toInternalError() { - const error = new Boom('', { + const error = new Boom.Boom('', { statusCode: 500, }); @@ -129,7 +129,7 @@ export class HapiResponseAdapter { } // we use for BWC with Boom payload for error responses - {error: string, message: string, statusCode: string} - const error = new Boom('', { + const error = new Boom.Boom('', { statusCode: kibanaResponse.status, }); @@ -142,8 +142,7 @@ export class HapiResponseAdapter { const headers = kibanaResponse.options.headers; if (headers) { - // Hapi typings for header accept only strings, although string[] is a valid value - error.output.headers = headers as any; + error.output.headers = headers; } return error; diff --git a/src/core/server/http/router/router.ts b/src/core/server/http/router/router.ts index b1e092ba5786a..ebc41a793f3b3 100644 --- a/src/core/server/http/router/router.ts +++ b/src/core/server/http/router/router.ts @@ -44,7 +44,10 @@ interface RouterRoute { method: RouteMethod; path: string; options: RouteConfigOptions; - handler: (req: Request, responseToolkit: ResponseToolkit) => Promise>; + handler: ( + req: Request, + responseToolkit: ResponseToolkit + ) => Promise>; } /** diff --git a/src/core/server/logging/layouts/json_layout.ts b/src/core/server/logging/layouts/json_layout.ts index 7573d0b837416..34c3c325e7328 100644 --- a/src/core/server/logging/layouts/json_layout.ts +++ b/src/core/server/logging/layouts/json_layout.ts @@ -18,7 +18,7 @@ */ import moment from 'moment-timezone'; -import { merge } from 'lodash'; +import { merge } from '@kbn/std'; import { schema } from '@kbn/config-schema'; import { LogRecord, Layout } from '@kbn/logging'; @@ -53,22 +53,19 @@ export class JsonLayout implements Layout { } public format(record: LogRecord): string { - return JSON.stringify( - merge( - { - '@timestamp': moment(record.timestamp).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), - message: record.message, - error: JsonLayout.errorToSerializableObject(record.error), - log: { - level: record.level.id.toUpperCase(), - logger: record.context, - }, - process: { - pid: record.pid, - }, - }, - record.meta - ) - ); + const log = { + '@timestamp': moment(record.timestamp).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + message: record.message, + error: JsonLayout.errorToSerializableObject(record.error), + log: { + level: record.level.id.toUpperCase(), + logger: record.context, + }, + process: { + pid: record.pid, + }, + }; + const output = record.meta ? merge(log, record.meta) : log; + return JSON.stringify(output); } } diff --git a/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.test.ts b/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.test.ts index 3186d7456383a..33787e3fce53a 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/catch_retryable_es_client_errors.test.ts @@ -22,14 +22,14 @@ import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { catchRetryableEsClientErrors } from './catch_retryable_es_client_errors'; describe('catchRetryableEsClientErrors', () => { - it('rejects non-retryable response errors', () => { + it('rejects non-retryable response errors', async () => { const error = new esErrors.ResponseError( elasticsearchClientMock.createApiResponse({ body: { error: { type: 'cluster_block_exception' } }, statusCode: 400, }) ); - return expect(Promise.reject(error).catch(catchRetryableEsClientErrors)).rejects.toBe(error); + await expect(Promise.reject(error).catch(catchRetryableEsClientErrors)).rejects.toBe(error); }); describe('returns left retryable_es_client_error for', () => { it('NoLivingConnectionsError', async () => { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts index 8947a5ec2171c..abda7cf82b121 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts @@ -100,8 +100,9 @@ describe('migration actions', () => { describe('fetchIndices', () => { it('resolves right empty record if no indices were found', async () => { + expect.assertions(1); const task = fetchIndices(client, ['no_such_index']); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": Object {}, @@ -109,12 +110,13 @@ describe('migration actions', () => { `); }); it('resolves right record with found indices', async () => { + expect.assertions(1); const res = (await fetchIndices(client, [ 'no_such_index', 'existing_index_with_docs', ])()) as Either.Right; - return expect(res.right).toEqual( + expect(res.right).toEqual( expect.objectContaining({ existing_index_with_docs: { aliases: {}, @@ -131,17 +133,19 @@ describe('migration actions', () => { await createIndex(client, 'new_index_without_write_block', { properties: {} })(); }); it('resolves right when setting the write block succeeds', async () => { + expect.assertions(1); const task = setWriteBlock(client, 'new_index_without_write_block'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "set_write_block_succeeded", } `); }); - it('resolves right when setting a write block on an index that already has one', () => { + it('resolves right when setting a write block on an index that already has one', async () => { + expect.assertions(1); const task = setWriteBlock(client, 'existing_index_with_write_block'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "set_write_block_succeeded", @@ -149,6 +153,7 @@ describe('migration actions', () => { `); }); it('once resolved, prevents further writes to the index', async () => { + expect.assertions(1); const task = setWriteBlock(client, 'new_index_without_write_block'); await task(); const sourceDocs = ([ @@ -157,13 +162,14 @@ describe('migration actions', () => { { _source: { title: 'doc 3' } }, { _source: { title: 'doc 4' } }, ] as unknown) as SavedObjectsRawDoc[]; - return expect( + await expect( bulkOverwriteTransformedDocuments(client, 'new_index_without_write_block', sourceDocs)() ).rejects.toMatchObject(expect.anything()); }); - it('resolves left index_not_found_exception when the index does not exist', () => { + it('resolves left index_not_found_exception when the index does not exist', async () => { + expect.assertions(1); const task = setWriteBlock(client, 'no_such_index'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -180,43 +186,51 @@ describe('migration actions', () => { await createIndex(client, 'existing_index_with_write_block_2', { properties: {} })(); await setWriteBlock(client, 'existing_index_with_write_block_2')(); }); - it('resolves right if successful when an index already has a write block', () => { + it('resolves right if successful when an index already has a write block', async () => { + expect.assertions(1); const task = removeWriteBlock(client, 'existing_index_with_write_block_2'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "remove_write_block_succeeded", } `); }); - it('resolves right if successful when an index does not have a write block', () => { + it('resolves right if successful when an index does not have a write block', async () => { + expect.assertions(1); const task = removeWriteBlock(client, 'existing_index_without_write_block_2'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "remove_write_block_succeeded", } `); }); - it('rejects if there is a non-retryable error', () => { + it('rejects if there is a non-retryable error', async () => { + expect.assertions(1); const task = removeWriteBlock(client, 'no_such_index'); - return expect(task()).rejects.toMatchInlineSnapshot( + await expect(task()).rejects.toMatchInlineSnapshot( `[ResponseError: index_not_found_exception]` ); }); }); describe('cloneIndex', () => { - afterEach(async () => { + afterAll(async () => { try { - await client.indices.delete({ index: 'yellow_then_green_index' }); + await client.indices.delete({ index: 'clone_*' }); } catch (e) { /** ignore */ } }); - it('resolves right if cloning into a new target index', () => { - const task = cloneIndex(client, 'existing_index_with_write_block', 'yellow_then_green_index'); - expect(task()).resolves.toMatchInlineSnapshot(` + it('resolves right if cloning into a new target index', async () => { + expect.assertions(1); + const task = cloneIndex( + client, + 'existing_index_with_write_block', + 'clone_yellow_then_green_index_1' + ); + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": Object { @@ -227,9 +241,10 @@ describe('migration actions', () => { `); }); it('resolves right after waiting for index status to be green if clone target already existed', async () => { + expect.assertions(2); // Create a yellow index await client.indices.create({ - index: 'yellow_then_green_index', + index: 'clone_yellow_then_green_index_2', body: { mappings: { properties: {} }, settings: { @@ -243,7 +258,7 @@ describe('migration actions', () => { const cloneIndexPromise = cloneIndex( client, 'existing_index_with_write_block', - 'yellow_then_green_index' + 'clone_yellow_then_green_index_2' )(); let indexGreen = false; @@ -258,7 +273,7 @@ describe('migration actions', () => { indexGreen = true; }, 10); - return cloneIndexPromise.then((res) => { + await cloneIndexPromise.then((res) => { // Assert that the promise didn't resolve before the index became green expect(indexGreen).toBe(true); expect(res).toMatchInlineSnapshot(` @@ -272,9 +287,10 @@ describe('migration actions', () => { `); }); }); - it('resolves left index_not_found_exception if the source index does not exist', () => { - const task = cloneIndex(client, 'no_such_index', 'yellow_then_green_index'); - expect(task()).resolves.toMatchInlineSnapshot(` + it('resolves left index_not_found_exception if the source index does not exist', async () => { + expect.assertions(1); + const task = cloneIndex(client, 'no_such_index', 'clone_yellow_then_green_index_3'); + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -289,6 +305,7 @@ describe('migration actions', () => { // Reindex doesn't return any errors on it's own, so we have to test // together with waitForReindexTask describe('reindex & waitForReindexTask', () => { + expect.assertions(2); it('resolves right when reindex succeeds without reindex script', async () => { const res = (await reindex( client, @@ -320,6 +337,7 @@ describe('migration actions', () => { `); }); it('resolves right when reindex succeeds with reindex script', async () => { + expect.assertions(2); const res = (await reindex( client, 'existing_index_with_docs', @@ -349,6 +367,7 @@ describe('migration actions', () => { `); }); it('resolves right, ignores version conflicts and does not update existing docs when reindex multiple times', async () => { + expect.assertions(3); // Reindex with a script let res = (await reindex( client, @@ -397,6 +416,7 @@ describe('migration actions', () => { `); }); it('resolves right and proceeds to add missing documents if there are some existing docs conflicts', async () => { + expect.assertions(2); // Simulate a reindex that only adds some of the documents from the // source index into the target index await createIndex(client, 'reindex_target_4', { properties: {} })(); @@ -444,6 +464,7 @@ describe('migration actions', () => { `); }); it('resolves left incompatible_mapping_exception if all reindex failures are due to a strict_dynamic_mapping_exception', async () => { + expect.assertions(1); // Simulates one instance having completed the UPDATE_TARGET_MAPPINGS // step which makes the mappings incompatible with outdated documents. // If another instance then tries a reindex it will get a @@ -479,6 +500,7 @@ describe('migration actions', () => { `); }); it('resolves left incompatible_mapping_exception if all reindex failures are due to a mapper_parsing_exception', async () => { + expect.assertions(1); // Simulates one instance having completed the UPDATE_TARGET_MAPPINGS // step which makes the mappings incompatible with outdated documents. // If another instance then tries a reindex it will get a @@ -512,6 +534,7 @@ describe('migration actions', () => { `); }); it('resolves left index_not_found_exception if source index does not exist', async () => { + expect.assertions(1); const res = (await reindex( client, 'no_such_index', @@ -520,7 +543,7 @@ describe('migration actions', () => { false )()) as Either.Right; const task = waitForReindexTask(client, res.right.taskId, '10s'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -531,6 +554,7 @@ describe('migration actions', () => { `); }); it('resolves left target_index_had_write_block if all failures are due to a write block', async () => { + expect.assertions(1); const res = (await reindex( client, 'existing_index_with_docs', @@ -541,7 +565,7 @@ describe('migration actions', () => { const task = waitForReindexTask(client, res.right.taskId, '10s'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -551,6 +575,7 @@ describe('migration actions', () => { `); }); it('resolves left if requireAlias=true and the target is not an alias', async () => { + expect.assertions(1); const res = (await reindex( client, 'existing_index_with_docs', @@ -561,7 +586,7 @@ describe('migration actions', () => { const task = waitForReindexTask(client, res.right.taskId, '10s'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -575,6 +600,7 @@ describe('migration actions', () => { describe('verifyReindex', () => { it('resolves right if source and target indices have the same amount of documents', async () => { + expect.assertions(1); const res = (await reindex( client, 'existing_index_with_docs', @@ -592,9 +618,10 @@ describe('migration actions', () => { } `); }); - it('resolves left if source and target indices have different amount of documents', () => { + it('resolves left if source and target indices have different amount of documents', async () => { + expect.assertions(1); const task = verifyReindex(client, 'existing_index_with_docs', 'existing_index_2'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -604,6 +631,7 @@ describe('migration actions', () => { `); }); it('rejects if source or target index does not exist', async () => { + expect.assertions(2); let task = verifyReindex(client, 'no_such_index', 'existing_index_2'); await expect(task()).rejects.toMatchInlineSnapshot( `[ResponseError: index_not_found_exception]` @@ -618,6 +646,7 @@ describe('migration actions', () => { describe('searchForOutdatedDocuments', () => { it('only returns documents that match the outdatedDocumentsQuery', async () => { + expect.assertions(2); const resultsWithQuery = ((await searchForOutdatedDocuments( client, 'existing_index_with_docs', @@ -635,6 +664,7 @@ describe('migration actions', () => { expect(resultsWithoutQuery.length).toBe(4); }); it('resolves with _id, _source, _seq_no and _primary_term', async () => { + expect.assertions(1); const results = ((await searchForOutdatedDocuments(client, 'existing_index_with_docs', { match: { title: { query: 'doc' } }, })()) as Either.Right).right.outdatedDocuments; @@ -655,6 +685,7 @@ describe('migration actions', () => { describe('waitForPickupUpdatedMappingsTask', () => { it('rejects if there are failures', async () => { + expect.assertions(1); const res = (await pickupUpdatedMappings( client, 'existing_index_with_write_block' @@ -664,11 +695,12 @@ describe('migration actions', () => { // We can't do a snapshot match because the response includes an index // id which ES assigns dynamically - return expect(task()).rejects.toMatchObject({ + await expect(task()).rejects.toMatchObject({ message: /pickupUpdatedMappings task failed with the following failures:\n\[\{\"index\":\"existing_index_with_write_block\"/, }); }); it('rejects if there is an error', async () => { + expect.assertions(1); const res = (await pickupUpdatedMappings( client, 'no_such_index' @@ -676,12 +708,13 @@ describe('migration actions', () => { const task = waitForPickupUpdatedMappingsTask(client, res.right.taskId, '10s'); - return expect(task()).rejects.toMatchInlineSnapshot(` + await expect(task()).rejects.toMatchInlineSnapshot(` [Error: pickupUpdatedMappings task failed with the following error: {"type":"index_not_found_exception","reason":"no such index [no_such_index]","resource.type":"index_or_alias","resource.id":"no_such_index","index_uuid":"_na_","index":"no_such_index"}] `); }); it('resolves right when successful', async () => { + expect.assertions(1); const res = (await pickupUpdatedMappings( client, 'existing_index_with_docs' @@ -689,7 +722,7 @@ describe('migration actions', () => { const task = waitForPickupUpdatedMappingsTask(client, res.right.taskId, '10s'); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "pickup_updated_mappings_succeeded", @@ -700,6 +733,7 @@ describe('migration actions', () => { describe('updateAndPickupMappings', () => { it('resolves right when mappings were updated and picked up', async () => { + expect.assertions(3); // Create an index without any mappings and insert documents into it await createIndex(client, 'existing_index_without_mappings', { dynamic: false as any, @@ -741,13 +775,14 @@ describe('migration actions', () => { 'existing_index_without_mappings', { match: { title: { query: 'doc' } } } )()) as Either.Right).right.outdatedDocuments; - return expect(pickedUpSearchResults.length).toBe(4); + expect(pickedUpSearchResults.length).toBe(4); }); }); describe('updateAliases', () => { describe('remove', () => { - it('resolves left index_not_found_exception when the index does not exist', () => { + it('resolves left index_not_found_exception when the index does not exist', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove: { @@ -757,7 +792,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -769,6 +804,7 @@ describe('migration actions', () => { }); describe('with must_exist=false', () => { it('resolves left alias_not_found_exception when alias does not exist', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove: { @@ -778,7 +814,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -790,6 +826,7 @@ describe('migration actions', () => { }); describe('with must_exist=true', () => { it('resolves left alias_not_found_exception when alias does not exist on specified index', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove: { @@ -799,7 +836,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -809,6 +846,7 @@ describe('migration actions', () => { `); }); it('resolves left alias_not_found_exception when alias does not exist', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove: { @@ -818,7 +856,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -830,7 +868,8 @@ describe('migration actions', () => { }); }); describe('remove_index', () => { - it('left index_not_found_exception if index does not exist', () => { + it('left index_not_found_exception if index does not exist', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove_index: { @@ -838,7 +877,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -848,7 +887,8 @@ describe('migration actions', () => { } `); }); - it('left remove_index_not_a_concrete_index when remove_index targets an alias', () => { + it('left remove_index_not_a_concrete_index when remove_index targets an alias', async () => { + expect.assertions(1); const task = updateAliases(client, [ { remove_index: { @@ -856,7 +896,7 @@ describe('migration actions', () => { }, }, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", "left": Object { @@ -868,11 +908,13 @@ describe('migration actions', () => { }); }); - describe('createIndex', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/87160 + describe.skip('createIndex', () => { afterAll(async () => { await client.indices.delete({ index: 'yellow_then_green_index' }); }); it('resolves right after waiting for an index status to be green if the index already existed', async () => { + expect.assertions(2); // Create a yellow index await client.indices.create( { @@ -903,7 +945,7 @@ describe('migration actions', () => { indexGreen = true; }, 10); - return createIndexPromise.then((res) => { + await createIndexPromise.then((res) => { // Assert that the promise didn't resolve before the index became green expect(indexGreen).toBe(true); expect(res).toMatchInlineSnapshot(` @@ -914,24 +956,26 @@ describe('migration actions', () => { `); }); }); - it('rejects when there is an unexpected error creating the index', () => { + it('rejects when there is an unexpected error creating the index', async () => { + expect.assertions(1); // Creating an index with the same name as an existing alias to induce // failure - expect( + await expect( createIndex(client, 'existing_index_2_alias', undefined as any)() ).rejects.toMatchInlineSnapshot(`[ResponseError: invalid_index_name_exception]`); }); }); describe('bulkOverwriteTransformedDocuments', () => { - it('resolves right when documents do not yet exist in the index', () => { + it('resolves right when documents do not yet exist in the index', async () => { + expect.assertions(1); const newDocs = ([ { _source: { title: 'doc 5' } }, { _source: { title: 'doc 6' } }, { _source: { title: 'doc 7' } }, ] as unknown) as SavedObjectsRawDoc[]; const task = bulkOverwriteTransformedDocuments(client, 'existing_index_with_docs', newDocs); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "bulk_index_succeeded", @@ -939,6 +983,7 @@ describe('migration actions', () => { `); }); it('resolves right even if there were some version_conflict_engine_exception', async () => { + expect.assertions(1); const existingDocs = ((await searchForOutdatedDocuments( client, 'existing_index_with_docs', @@ -949,20 +994,21 @@ describe('migration actions', () => { ...existingDocs, ({ _source: { title: 'doc 8' } } as unknown) as SavedObjectsRawDoc, ]); - return expect(task()).resolves.toMatchInlineSnapshot(` + await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", "right": "bulk_index_succeeded", } `); }); - it('rejects if there are errors', () => { + it('rejects if there are errors', async () => { + expect.assertions(1); const newDocs = ([ { _source: { title: 'doc 5' } }, { _source: { title: 'doc 6' } }, { _source: { title: 'doc 7' } }, ] as unknown) as SavedObjectsRawDoc[]; - return expect( + await expect( bulkOverwriteTransformedDocuments(client, 'existing_index_with_write_block', newDocs)() ).rejects.toMatchObject(expect.anything()); }); 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 6dbb986e868ee..2baf27e94edb3 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 @@ -142,8 +142,8 @@ describe('migrationsStateActionMachine', () => { } `); }); - it('resolves when reaching the DONE state', () => { - return expect( + it('resolves when reaching the DONE state', async () => { + await expect( migrationStateActionMachine({ initialState, logger: mockLogger.get(), @@ -152,8 +152,8 @@ describe('migrationsStateActionMachine', () => { }) ).resolves.toEqual(expect.anything()); }); - it('resolves with migrated status if some sourceIndex in the DONE state', () => { - return expect( + it('resolves with migrated status if some sourceIndex in the DONE state', async () => { + await expect( migrationStateActionMachine({ initialState: { ...initialState, ...{ sourceIndex: Option.some('source-index') } }, logger: mockLogger.get(), @@ -162,8 +162,8 @@ describe('migrationsStateActionMachine', () => { }) ).resolves.toEqual(expect.objectContaining({ status: 'migrated' })); }); - it('resolves with patched status if none sourceIndex in the DONE state', () => { - return expect( + it('resolves with patched status if none sourceIndex in the DONE state', async () => { + await expect( migrationStateActionMachine({ initialState: { ...initialState, ...{ sourceIndex: Option.none } }, logger: mockLogger.get(), @@ -172,8 +172,8 @@ describe('migrationsStateActionMachine', () => { }) ).resolves.toEqual(expect.objectContaining({ status: 'patched' })); }); - it('rejects with error message when reaching the FATAL state', () => { - return expect( + it('rejects with error message when reaching the FATAL state', async () => { + await expect( migrationStateActionMachine({ initialState: { ...initialState, reason: 'the fatal reason' } as State, logger: mockLogger.get(), diff --git a/src/core/server/saved_objects/migrationsv2/state_action_machine.test.ts b/src/core/server/saved_objects/migrationsv2/state_action_machine.test.ts index 15dde10eb21ec..3760b92591346 100644 --- a/src/core/server/saved_objects/migrationsv2/state_action_machine.test.ts +++ b/src/core/server/saved_objects/migrationsv2/state_action_machine.test.ts @@ -86,14 +86,14 @@ describe('state action machine', () => { }); }); - test('rejects if an exception is throw from inside an action', () => { - return expect( + test('rejects if an exception is throw from inside an action', async () => { + await expect( stateActionMachine({ ...state, controlState: 'THROW' }, next, countUntilThree) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Invalid control state"`); }); - test('resolve with the final state once all steps are completed', () => { - return expect(finalStateP).resolves.toMatchInlineSnapshot(` + test('resolve with the final state once all steps are completed', async () => { + await expect(finalStateP).resolves.toMatchInlineSnapshot(` Object { "controlState": "DONE", "count": 3, @@ -101,8 +101,8 @@ describe('state action machine', () => { `); }); - test("rejects if control state doesn't change after 50 steps", () => { - return expect( + test("rejects if control state doesn't change after 50 steps", async () => { + await expect( stateActionMachine(state, next, countUntilModel(51)) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Control state didn't change after 50 steps aborting."` diff --git a/src/core/server/saved_objects/service/lib/errors.ts b/src/core/server/saved_objects/service/lib/errors.ts index e8836dbd8f7a1..c6c8eee003e4e 100644 --- a/src/core/server/saved_objects/service/lib/errors.ts +++ b/src/core/server/saved_objects/service/lib/errors.ts @@ -44,7 +44,7 @@ const CODE_GENERAL_ERROR = 'SavedObjectsClient/generalError'; const code = Symbol('SavedObjectsClientErrorCode'); -export interface DecoratedError extends Boom { +export interface DecoratedError extends Boom.Boom { [code]?: string; } diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 5f07a4b523056..848cd3a657e9c 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -310,7 +310,7 @@ export interface CapabilitiesStart { } // @public -export type CapabilitiesSwitcher = (request: KibanaRequest, uiCapabilities: Capabilities) => Partial | Promise>; +export type CapabilitiesSwitcher = (request: KibanaRequest, uiCapabilities: Capabilities, useDefaultCapabilities: boolean) => Partial | Promise>; // @alpha export const config: { @@ -1541,7 +1541,7 @@ export type LegacyElasticsearchClientConfig = Pick" \ --shell /sbin/nologin \ --comment "kibana service user" \ - "<%= user %>" \ + "<%= user %>" echo " OK" fi diff --git a/src/dev/cli_dev_mode/log.ts b/src/dev/cli_dev_mode/log.ts index f349026ca9cab..3a5d60e65c3f1 100644 --- a/src/dev/cli_dev_mode/log.ts +++ b/src/dev/cli_dev_mode/log.ts @@ -25,7 +25,7 @@ export interface Log { good(label: string, ...args: any[]): void; warn(label: string, ...args: any[]): void; bad(label: string, ...args: any[]): void; - write(label: string, ...args: any[]): void; + write(...args: any[]): void; } export class CliLog implements Log { @@ -58,9 +58,9 @@ export class CliLog implements Log { console.log(Chalk.white.bgRed(` ${label.trim()} `), ...args); } - write(label: string, ...args: any[]) { + write(...args: any[]) { // eslint-disable-next-line no-console - console.log(` ${label.trim()} `, ...args); + console.log(...args); } } @@ -88,10 +88,10 @@ export class TestLog implements Log { }); } - write(label: string, ...args: any[]) { + write(...args: any[]) { this.messages.push({ type: 'write', - args: [label, ...args], + args, }); } } diff --git a/src/dev/cli_dev_mode/optimizer.test.ts b/src/dev/cli_dev_mode/optimizer.test.ts index 8a82012499b33..6017ab2c35d0f 100644 --- a/src/dev/cli_dev_mode/optimizer.test.ts +++ b/src/dev/cli_dev_mode/optimizer.test.ts @@ -191,8 +191,8 @@ it('is ready when optimizer phase is success or issue and logs in familiar forma const lines = await linesPromise; expect(lines).toMatchInlineSnapshot(` Array [ - "np bld log [timestamp] [success][@kbn/optimizer] 0 bundles compiled successfully after 0 sec", - "np bld log [timestamp] [error][@kbn/optimizer] webpack compile errors", + " np bld log [timestamp] [success][@kbn/optimizer] 0 bundles compiled successfully after 0 sec", + " np bld log [timestamp] [error][@kbn/optimizer] webpack compile errors", ] `); }); diff --git a/src/dev/cli_dev_mode/optimizer.ts b/src/dev/cli_dev_mode/optimizer.ts index 9aac414f02b29..f618a0fdbe72f 100644 --- a/src/dev/cli_dev_mode/optimizer.ts +++ b/src/dev/cli_dev_mode/optimizer.ts @@ -105,7 +105,7 @@ export class Optimizer { ToolingLogTextWriter.write( options.writeLogTo ?? process.stdout, - `${dim} log [${time()}] [${level(msg.type)}][${name}] `, + ` ${dim} log [${time()}] [${level(msg.type)}][${name}] `, msg ); return true; diff --git a/src/dev/code_coverage/nyc_config/nyc.functional.config.js b/src/dev/code_coverage/nyc_config/nyc.functional.config.js index 20d266ab9e2c3..9c025c6a98458 100644 --- a/src/dev/code_coverage/nyc_config/nyc.functional.config.js +++ b/src/dev/code_coverage/nyc_config/nyc.functional.config.js @@ -18,7 +18,7 @@ */ const defaultExclude = require('@istanbuljs/schema/default-exclude'); -const extraExclude = ['data/optimize/**', 'src/core/server/**', '**/test/**']; +const extraExclude = ['data/optimize/**', 'src/core/server/**', '**/{test, types}/**/*']; const path = require('path'); module.exports = { diff --git a/src/dev/code_coverage/shell_scripts/extract_archives.sh b/src/dev/code_coverage/shell_scripts/extract_archives.sh index 32b4ccd6abccb..376467f9f2e55 100644 --- a/src/dev/code_coverage/shell_scripts/extract_archives.sh +++ b/src/dev/code_coverage/shell_scripts/extract_archives.sh @@ -6,7 +6,7 @@ EXTRACT_DIR=/tmp/extracted_coverage mkdir -p $EXTRACT_DIR echo "### Extracting downloaded artifacts" -for x in kibana-intake kibana-oss-tests kibana-xpack-tests; do #x-pack-intake skipping due to failures +for x in kibana-intake x-pack-intake kibana-oss-tests kibana-xpack-tests; do tar -xzf $DOWNLOAD_DIR/coverage/${x}/kibana-coverage.tar.gz -C $EXTRACT_DIR || echo "### Error 'tarring': ${x}" done diff --git a/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh b/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh index 5d983828394bf..62b81929ae79b 100644 --- a/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh +++ b/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh @@ -32,7 +32,7 @@ TEAM_ASSIGN_PATH=$5 # Build team assignments dat file node scripts/generate_team_assignments.js --verbose --src .github/CODEOWNERS --dest $TEAM_ASSIGN_PATH -for x in functional; do #jest skip due to failures +for x in jest functional; do echo "### Ingesting coverage for ${x}" COVERAGE_SUMMARY_FILE=target/kibana-coverage/${x}-combined/coverage-summary.json diff --git a/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh b/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh index a8952f987b419..707c6de3f88a0 100644 --- a/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh +++ b/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh @@ -4,6 +4,6 @@ COVERAGE_TEMP_DIR=/tmp/extracted_coverage/target/kibana-coverage/ export COVERAGE_TEMP_DIR echo "### Merge coverage reports" -for x in functional; do # jest skip due to failures +for x in jest functional; do yarn nyc report --nycrc-path src/dev/code_coverage/nyc_config/nyc.${x}.config.js done diff --git a/tasks/function_test_groups.js b/src/dev/run_ensure_all_tests_in_ci_group.js similarity index 65% rename from tasks/function_test_groups.js rename to src/dev/run_ensure_all_tests_in_ci_group.js index 0b456dcb0da13..b5d36c405cbbb 100644 --- a/tasks/function_test_groups.js +++ b/src/dev/run_ensure_all_tests_in_ci_group.js @@ -21,32 +21,28 @@ import { readFileSync } from 'fs'; import { resolve } from 'path'; import execa from 'execa'; -import grunt from 'grunt'; import { safeLoad } from 'js-yaml'; -const JOBS_YAML = readFileSync(resolve(__dirname, '../.ci/jobs.yml'), 'utf8'); +import { run } from '@kbn/dev-utils'; + +const JOBS_YAML = readFileSync(resolve(__dirname, '../../.ci/jobs.yml'), 'utf8'); const TEST_TAGS = safeLoad(JOBS_YAML) .JOB.filter((id) => id.startsWith('kibana-ciGroup')) .map((id) => id.replace(/^kibana-/, '')); -grunt.registerTask( - 'functionalTests:ensureAllTestsInCiGroup', - 'Check that all of the functional tests are in a CI group', - async function () { - const done = this.async(); - - try { - const result = await execa(process.execPath, [ - 'scripts/functional_test_runner', - ...TEST_TAGS.map((tag) => `--include-tag=${tag}`), - '--config', - 'test/functional/config.js', - '--test-stats', - ]); - const stats = JSON.parse(result.stderr); - - if (stats.excludedTests.length > 0) { - grunt.fail.fatal(` +run(async ({ log }) => { + try { + const result = await execa(process.execPath, [ + 'scripts/functional_test_runner', + ...TEST_TAGS.map((tag) => `--include-tag=${tag}`), + '--config', + 'test/functional/config.js', + '--test-stats', + ]); + const stats = JSON.parse(result.stderr); + + if (stats.excludedTests.length > 0) { + log.error(` ${stats.excludedTests.length} tests are excluded by the ciGroup tags, make sure that all test suites have a "ciGroup{X}" tag and that "tasks/functional_test_groups.js" knows about the tag that you are using. @@ -55,12 +51,11 @@ grunt.registerTask( - ${stats.excludedTests.join('\n - ')} `); - return; - } - - done(); - } catch (error) { - grunt.fail.fatal(error.stack); + process.exitCode = 1; + return; } + } catch (error) { + log.error(error.stack); + process.exitCode = 1; } -); +}); diff --git a/src/dev/run_find_plugins_with_circular_deps.ts b/src/dev/run_find_plugins_with_circular_deps.ts index f4662820a1fb0..5afb8df8502df 100644 --- a/src/dev/run_find_plugins_with_circular_deps.ts +++ b/src/dev/run_find_plugins_with_circular_deps.ts @@ -31,15 +31,7 @@ interface Options { type CircularDepList = Set; const allowedList: CircularDepList = new Set([ - 'src/plugins/charts -> src/plugins/expressions', - 'src/plugins/charts -> src/plugins/vis_default_editor', - 'src/plugins/data -> src/plugins/embeddable', - 'src/plugins/data -> src/plugins/expressions', - 'src/plugins/data -> src/plugins/ui_actions', - 'src/plugins/embeddable -> src/plugins/ui_actions', - 'src/plugins/expressions -> src/plugins/visualizations', 'src/plugins/vis_default_editor -> src/plugins/visualizations', - 'src/plugins/vis_default_editor -> src/plugins/visualize', 'src/plugins/visualizations -> src/plugins/visualize', 'x-pack/plugins/actions -> x-pack/plugins/case', 'x-pack/plugins/case -> x-pack/plugins/security_solution', diff --git a/src/plugins/apm_oss/server/tutorial/index_pattern.json b/src/plugins/apm_oss/server/tutorial/index_pattern.json index b9f3b43b67b84..6eb040f2758af 100644 --- a/src/plugins/apm_oss/server/tutorial/index_pattern.json +++ b/src/plugins/apm_oss/server/tutorial/index_pattern.json @@ -1,7 +1,7 @@ { "attributes": { "fieldFormatMap": "{\"client.bytes\":{\"id\":\"bytes\"},\"client.nat.port\":{\"id\":\"string\"},\"client.port\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.nat.port\":{\"id\":\"string\"},\"destination.port\":{\"id\":\"string\"},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"log.syslog.facility.code\":{\"id\":\"string\"},\"log.syslog.priority\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"package.size\":{\"id\":\"string\"},\"process.parent.pgid\":{\"id\":\"string\"},\"process.parent.pid\":{\"id\":\"string\"},\"process.parent.ppid\":{\"id\":\"string\"},\"process.parent.thread.id\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"server.bytes\":{\"id\":\"bytes\"},\"server.nat.port\":{\"id\":\"string\"},\"server.port\":{\"id\":\"string\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.nat.port\":{\"id\":\"string\"},\"source.port\":{\"id\":\"string\"},\"system.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.memory.actual.free\":{\"id\":\"bytes\"},\"system.memory.total\":{\"id\":\"bytes\"},\"system.process.cgroup.memory.mem.limit.bytes\":{\"id\":\"bytes\"},\"system.process.cgroup.memory.mem.usage.bytes\":{\"id\":\"bytes\"},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\"},\"system.process.memory.size\":{\"id\":\"bytes\"},\"url.port\":{\"id\":\"string\"},\"view spans\":{\"id\":\"url\",\"params\":{\"labelTemplate\":\"View Spans\"}}}", - "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.build.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"error.stack_trace.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.ingested\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reason\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.url\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.attributes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.drive_letter\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"file.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.build_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.strings\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.hive\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.value\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hosts\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.user\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.author\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.ruleset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.uuid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.cipher\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.ja3\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.server_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.supported_ciphers\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"tls.client.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.established\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.next_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.resumed\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.ja3s\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"tls.server.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.classification\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.enumeration\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.report_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.scanner.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.base\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.environmental\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.temporal\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.root\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cgroup.memory.mem.limit.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cgroup.memory.mem.usage.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"child.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.rows_affected\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.resource\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.cls\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.fid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.tbt\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.sum\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.max\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.histogram\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"metricset.period\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.response_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.response_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", + "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.build.original\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.original_file_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.ingested\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reason\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.url\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.attributes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.drive_letter\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.original_file_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"file.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.file.path\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.build_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.original_file_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.original_file_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.imphash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.original_file_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.strings\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.hive\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.key\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.path\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.value\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hosts\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.user\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.author\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.ruleset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.uuid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.subtechnique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.subtechnique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.subtechnique.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.subtechnique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.cipher\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.issuer\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.ja3\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.server_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.subject\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.supported_ciphers\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"tls.client.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.established\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.next_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.resumed\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.issuer\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.ja3s\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.subject\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"tls.server.x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.changes.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.effective.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.email\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.full_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.target.roles\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.classification\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.enumeration\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.report_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.scanner.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.base\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.environmental\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.temporal\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.alternative_names\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.issuer.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":false,\"name\":\"x509.public_key_exponent\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.public_key_size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.signature_algorithm\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.common_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.country\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.distinguished_name\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.locality\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.organization\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.organizational_unit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.subject.state_or_province\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"x509.version_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.root\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cgroup.memory.mem.limit.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cgroup.memory.mem.usage.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"child.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.rows_affected\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.resource\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.cls\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.fid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.tbt\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.sum\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.experience.longtask.max\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.histogram\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"metricset.period\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.response_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.response_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", "sourceFilters": "[{\"value\":\"sourcemap.sourcemap\"}]", "timeFieldName": "@timestamp" }, diff --git a/src/plugins/charts/kibana.json b/src/plugins/charts/kibana.json index a6d4dbba7238f..4510a1ea7d065 100644 --- a/src/plugins/charts/kibana.json +++ b/src/plugins/charts/kibana.json @@ -3,6 +3,5 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["expressions"], - "requiredBundles": ["visDefaultEditor"] + "requiredPlugins": ["expressions"] } diff --git a/src/plugins/charts/public/services/legacy_colors/colors.test.ts b/src/plugins/charts/public/services/legacy_colors/colors.test.ts index 89cf7a4817377..b94918426c525 100644 --- a/src/plugins/charts/public/services/legacy_colors/colors.test.ts +++ b/src/plugins/charts/public/services/legacy_colors/colors.test.ts @@ -62,14 +62,17 @@ describe('Vislib Color Service', () => { it('should throw an error if input is not an array', () => { expect(() => { + // @ts-expect-error colors.createColorLookupFunction(200); }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction('help'); }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(true); }).toThrowError(); @@ -78,10 +81,12 @@ describe('Vislib Color Service', () => { }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(nullValue); }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(emptyObject); }).toThrowError(); }); @@ -89,14 +94,17 @@ describe('Vislib Color Service', () => { describe('when array is not composed of numbers, strings, or undefined values', () => { it('should throw an error', () => { expect(() => { + // @ts-expect-error colors.createColorLookupFunction(arrayOfObjects); }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(arrayOfBooleans); }).toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(arrayOfNullValues); }).toThrowError(); }); @@ -113,6 +121,7 @@ describe('Vislib Color Service', () => { }).not.toThrowError(); expect(() => { + // @ts-expect-error colors.createColorLookupFunction(arrayOfUndefinedValues); }).not.toThrowError(); }); diff --git a/src/plugins/charts/public/services/legacy_colors/colors.ts b/src/plugins/charts/public/services/legacy_colors/colors.ts index e1342a114f8df..e367a780fb292 100644 --- a/src/plugins/charts/public/services/legacy_colors/colors.ts +++ b/src/plugins/charts/public/services/legacy_colors/colors.ts @@ -48,7 +48,7 @@ export class LegacyColorsService { } createColorLookupFunction( - arrayOfStringsOrNumbers?: any, + arrayOfStringsOrNumbers?: Array, colorMapping: Partial> = {} ) { if (!Array.isArray(arrayOfStringsOrNumbers)) { @@ -67,7 +67,7 @@ export class LegacyColorsService { this.mappedColors.mapKeys(arrayOfStringsOrNumbers); - return (value: string) => { + return (value: string | number) => { return colorMapping[value] || this.mappedColors.get(value); }; } diff --git a/src/plugins/charts/public/services/mapped_colors/mapped_colors.ts b/src/plugins/charts/public/services/mapped_colors/mapped_colors.ts index 2934d4208d22c..7848cdd3f3140 100644 --- a/src/plugins/charts/public/services/mapped_colors/mapped_colors.ts +++ b/src/plugins/charts/public/services/mapped_colors/mapped_colors.ts @@ -37,15 +37,15 @@ export class MappedColors { private _mapping: any; constructor( - private uiSettings: CoreSetup['uiSettings'], + private uiSettings?: CoreSetup['uiSettings'], private colorPaletteFn: (num: number) => string[] = createColorPalette ) { this._oldMap = {}; this._mapping = {}; } - private getConfigColorMapping() { - return _.mapValues(this.uiSettings.get(COLOR_MAPPING_SETTING), standardizeColor); + private getConfigColorMapping(): Record { + return _.mapValues(this.uiSettings?.get(COLOR_MAPPING_SETTING) || {}, standardizeColor); } public get oldMap(): any { diff --git a/src/plugins/charts/public/services/palettes/palettes.test.tsx b/src/plugins/charts/public/services/palettes/palettes.test.tsx index 5d9337f1ee683..7356f13fddf9f 100644 --- a/src/plugins/charts/public/services/palettes/palettes.test.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.test.tsx @@ -18,9 +18,11 @@ */ import { coreMock } from '../../../../../core/public/mocks'; +import { createColorPalette as createLegacyColorPalette } from '../../../../../../src/plugins/charts/public'; import { PaletteDefinition } from './types'; import { buildPalettes } from './palettes'; import { colorsServiceMock } from '../legacy_colors/mock'; +import { euiPaletteColorBlind, euiPaletteColorBlindBehindText } from '@elastic/eui'; describe('palettes', () => { const palettes: Record = buildPalettes( @@ -28,79 +30,257 @@ describe('palettes', () => { colorsServiceMock ); describe('default palette', () => { - it('should return different colors based on behind text flag', () => { - const palette = palettes.default; + describe('syncColors: false', () => { + it('should return different colors based on behind text flag', () => { + const palette = palettes.default; - const color1 = palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 5, - }, - ]); - const color2 = palette.getColor( - [ + const color1 = palette.getColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 5, }, - ], - { - behindText: true, - } - ); - expect(color1).not.toEqual(color2); - }); + ]); + const color2 = palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + behindText: true, + } + ); + expect(color1).not.toEqual(color2); + }); - it('should return different colors based on rank at current series', () => { - const palette = palettes.default; + it('should return different colors based on rank at current series', () => { + const palette = palettes.default; - const color1 = palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 5, - }, - ]); - const color2 = palette.getColor([ - { - name: 'abc', - rankAtDepth: 1, - totalSeriesAtDepth: 5, - }, - ]); - expect(color1).not.toEqual(color2); + const color1 = palette.getColor([ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ]); + const color2 = palette.getColor([ + { + name: 'abc', + rankAtDepth: 1, + totalSeriesAtDepth: 5, + }, + ]); + expect(color1).not.toEqual(color2); + }); + + it('should return the same color for different positions on outer series layers', () => { + const palette = palettes.default; + + const color1 = palette.getColor([ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 2, + }, + ]); + const color2 = palette.getColor([ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + { + name: 'ghj', + rankAtDepth: 1, + totalSeriesAtDepth: 1, + }, + ]); + expect(color1).toEqual(color2); + }); }); - it('should return the same color for different positions on outer series layers', () => { - const palette = palettes.default; + describe('syncColors: true', () => { + it('should return different colors based on behind text flag', () => { + const palette = palettes.default; - const color1 = palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 5, - }, - { - name: 'def', - rankAtDepth: 0, - totalSeriesAtDepth: 2, - }, - ]); - const color2 = palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 5, - }, - { - name: 'ghj', - rankAtDepth: 1, - totalSeriesAtDepth: 1, - }, - ]); - expect(color1).toEqual(color2); + const color1 = palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + syncColors: true, + } + ); + const color2 = palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + behindText: true, + syncColors: true, + } + ); + expect(color1).not.toEqual(color2); + }); + + it('should return different colors for different keys', () => { + const palette = palettes.default; + + const color1 = palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + syncColors: true, + } + ); + const color2 = palette.getColor( + [ + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + syncColors: true, + } + ); + expect(color1).not.toEqual(color2); + }); + + it('should return the same color for the same key, irregardless of rank', () => { + const palette = palettes.default; + + const color1 = palette.getColor( + [ + { + name: 'hij', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + ], + { + syncColors: true, + } + ); + const color2 = palette.getColor( + [ + { + name: 'hij', + rankAtDepth: 5, + totalSeriesAtDepth: 5, + }, + ], + { + syncColors: true, + } + ); + expect(color1).toEqual(color2); + }); + + it('should return the same color for different positions on outer series layers', () => { + const palette = palettes.default; + + const color1 = palette.getColor( + [ + { + name: 'klm', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 2, + }, + ], + { + syncColors: true, + } + ); + const color2 = palette.getColor( + [ + { + name: 'klm', + rankAtDepth: 3, + totalSeriesAtDepth: 5, + }, + { + name: 'ghj', + rankAtDepth: 1, + totalSeriesAtDepth: 1, + }, + ], + { + syncColors: true, + } + ); + expect(color1).toEqual(color2); + }); + + it('should return the same index of the behind text palette for same key', () => { + const palette = palettes.default; + + const color1 = palette.getColor( + [ + { + name: 'klm', + rankAtDepth: 0, + totalSeriesAtDepth: 5, + }, + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 2, + }, + ], + { + syncColors: true, + } + ); + const color2 = palette.getColor( + [ + { + name: 'klm', + rankAtDepth: 3, + totalSeriesAtDepth: 5, + }, + { + name: 'ghj', + rankAtDepth: 1, + totalSeriesAtDepth: 1, + }, + ], + { + syncColors: true, + behindText: true, + } + ); + const color1Index = euiPaletteColorBlind({ rotations: 2 }).indexOf(color1!); + const color2Index = euiPaletteColorBlindBehindText({ rotations: 2 }).indexOf(color2!); + expect(color1Index).toEqual(color2Index); + }); }); }); @@ -136,35 +316,87 @@ describe('palettes', () => { (colorsServiceMock.mappedColors.get as jest.Mock).mockClear(); }); - it('should query legacy color service', () => { - palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 10, - }, - ]); - expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']); - expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc'); + describe('syncColors: false', () => { + it('should not query legacy color service', () => { + palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 10, + }, + ], + { + syncColors: false, + } + ); + expect(colorsServiceMock.mappedColors.mapKeys).not.toHaveBeenCalled(); + expect(colorsServiceMock.mappedColors.get).not.toHaveBeenCalled(); + }); + + it('should return a color from the legacy palette based on position of first series', () => { + const result = palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 2, + totalSeriesAtDepth: 10, + }, + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 10, + }, + ], + { + syncColors: false, + } + ); + expect(result).toEqual(createLegacyColorPalette(20)[2]); + }); }); - it('should always use root series', () => { - palette.getColor([ - { - name: 'abc', - rankAtDepth: 0, - totalSeriesAtDepth: 10, - }, - { - name: 'def', - rankAtDepth: 0, - totalSeriesAtDepth: 10, - }, - ]); - expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledTimes(1); - expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']); - expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledTimes(1); - expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc'); + describe('syncColors: true', () => { + it('should query legacy color service', () => { + palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 10, + }, + ], + { + syncColors: true, + } + ); + expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']); + expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc'); + }); + + it('should always use root series', () => { + palette.getColor( + [ + { + name: 'abc', + rankAtDepth: 0, + totalSeriesAtDepth: 10, + }, + { + name: 'def', + rankAtDepth: 0, + totalSeriesAtDepth: 10, + }, + ], + { + syncColors: true, + } + ); + expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledTimes(1); + expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']); + expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledTimes(1); + expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc'); + }); }); }); diff --git a/src/plugins/charts/public/services/palettes/palettes.tsx b/src/plugins/charts/public/services/palettes/palettes.tsx index c1fd7c3cc739f..ffb237904b36c 100644 --- a/src/plugins/charts/public/services/palettes/palettes.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.tsx @@ -28,26 +28,45 @@ import { euiPaletteNegative, euiPalettePositive, euiPaletteWarm, - euiPaletteColorBlindBehindText, euiPaletteForStatus, euiPaletteForTemperature, euiPaletteComplimentary, + euiPaletteColorBlindBehindText, } from '@elastic/eui'; -import { ChartsPluginSetup } from '../../../../../../src/plugins/charts/public'; +import { flatten, zip } from 'lodash'; +import { + ChartsPluginSetup, + createColorPalette as createLegacyColorPalette, +} from '../../../../../../src/plugins/charts/public'; import { lightenColor } from './lighten_color'; import { ChartColorConfiguration, PaletteDefinition, SeriesLayer } from './types'; import { LegacyColorsService } from '../legacy_colors'; +import { MappedColors } from '../mapped_colors'; function buildRoundRobinCategoricalWithMappedColors(): Omit { const colors = euiPaletteColorBlind({ rotations: 2 }); const behindTextColors = euiPaletteColorBlindBehindText({ rotations: 2 }); + const behindTextColorMap: Record = Object.fromEntries( + zip(colors, behindTextColors) + ); + const mappedColors = new MappedColors(undefined, (num: number) => { + return flatten(new Array(Math.ceil(num / 10)).fill(colors)).map((color) => color.toLowerCase()); + }); function getColor( series: SeriesLayer[], chartConfiguration: ChartColorConfiguration = { behindText: false } ) { - const outputColor = chartConfiguration.behindText - ? behindTextColors[series[0].rankAtDepth % behindTextColors.length] - : colors[series[0].rankAtDepth % colors.length]; + let outputColor: string; + if (chartConfiguration.syncColors) { + const colorKey = series[0].name; + mappedColors.mapKeys([colorKey]); + const mappedColor = mappedColors.get(colorKey); + outputColor = chartConfiguration.behindText ? behindTextColorMap[mappedColor] : mappedColor; + } else { + outputColor = chartConfiguration.behindText + ? behindTextColors[series[0].rankAtDepth % behindTextColors.length] + : colors[series[0].rankAtDepth % colors.length]; + } if (!chartConfiguration.maxDepth || chartConfiguration.maxDepth === 1) { return outputColor; @@ -115,9 +134,15 @@ function buildGradient( function buildSyncedKibanaPalette( colors: ChartsPluginSetup['legacyColors'] ): Omit { + const staticColors = createLegacyColorPalette(20); function getColor(series: SeriesLayer[], chartConfiguration: ChartColorConfiguration = {}) { - colors.mappedColors.mapKeys([series[0].name]); - const outputColor = colors.mappedColors.get(series[0].name); + let outputColor: string; + if (chartConfiguration.syncColors) { + colors.mappedColors.mapKeys([series[0].name]); + outputColor = colors.mappedColors.get(series[0].name); + } else { + outputColor = staticColors[series[0].rankAtDepth % staticColors.length]; + } if (!chartConfiguration.maxDepth || chartConfiguration.maxDepth === 1) { return outputColor; diff --git a/src/plugins/charts/public/services/palettes/types.ts b/src/plugins/charts/public/services/palettes/types.ts index f92bcb4bd0824..15989578518f5 100644 --- a/src/plugins/charts/public/services/palettes/types.ts +++ b/src/plugins/charts/public/services/palettes/types.ts @@ -55,6 +55,11 @@ export interface ChartColorConfiguration { * adjust colors for better a11y. Might be ignored depending on the palette. */ behindText?: boolean; + /** + * Flag whether a color assignment to a given key should be remembered and re-used the next time the key shows up. + * This setting might be ignored based on the palette. + */ + syncColors?: boolean; } /** diff --git a/src/plugins/charts/public/static/components/collections.ts b/src/plugins/charts/public/static/components/collections.ts index 9dde50f2b44c9..16d875836a202 100644 --- a/src/plugins/charts/public/static/components/collections.ts +++ b/src/plugins/charts/public/static/components/collections.ts @@ -18,17 +18,22 @@ */ import { $Values } from '@kbn/utility-types'; +import { i18n } from '@kbn/i18n'; -export const ColorModes = Object.freeze({ - BACKGROUND: 'Background' as 'Background', - LABELS: 'Labels' as 'Labels', - NONE: 'None' as 'None', +export const ColorMode = Object.freeze({ + Background: 'Background' as 'Background', + Labels: 'Labels' as 'Labels', + None: 'None' as 'None', }); -export type ColorModes = $Values; +export type ColorMode = $Values; -export const Rotates = Object.freeze({ - HORIZONTAL: 0, - VERTICAL: 90, - ANGLED: 75, +export const LabelRotation = Object.freeze({ + Horizontal: 0, + Vertical: 90, + Angled: 75, +}); +export type LabelRotation = $Values; + +export const defaultCountLabel = i18n.translate('charts.countText', { + defaultMessage: 'Count', }); -export type Rotates = $Values; diff --git a/src/plugins/charts/public/static/components/color_picker.scss b/src/plugins/charts/public/static/components/color_picker.scss new file mode 100644 index 0000000000000..85bfefca41a09 --- /dev/null +++ b/src/plugins/charts/public/static/components/color_picker.scss @@ -0,0 +1,18 @@ +$visColorPickerWidth: $euiSizeL * 8; // 8 columns + +.visColorPicker__value { + width: $visColorPickerWidth; +} + +.visColorPicker__valueDot { + cursor: pointer; + + &:hover { + transform: scale(1.4); + } + + &-isSelected { + border: $euiSizeXS solid; + border-radius: 100%; + } +} diff --git a/src/plugins/charts/public/static/components/color_picker.tsx b/src/plugins/charts/public/static/components/color_picker.tsx new file mode 100644 index 0000000000000..d785a9c9ad4b7 --- /dev/null +++ b/src/plugins/charts/public/static/components/color_picker.tsx @@ -0,0 +1,138 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import classNames from 'classnames'; +import React, { BaseSyntheticEvent } from 'react'; + +import { EuiButtonEmpty, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import './color_picker.scss'; + +export const legendColors: string[] = [ + '#3F6833', + '#967302', + '#2F575E', + '#99440A', + '#58140C', + '#052B51', + '#511749', + '#3F2B5B', + '#508642', + '#CCA300', + '#447EBC', + '#C15C17', + '#890F02', + '#0A437C', + '#6D1F62', + '#584477', + '#629E51', + '#E5AC0E', + '#64B0C8', + '#E0752D', + '#BF1B00', + '#0A50A1', + '#962D82', + '#614D93', + '#7EB26D', + '#EAB839', + '#6ED0E0', + '#EF843C', + '#E24D42', + '#1F78C1', + '#BA43A9', + '#705DA0', + '#9AC48A', + '#F2C96D', + '#65C5DB', + '#F9934E', + '#EA6460', + '#5195CE', + '#D683CE', + '#806EB7', + '#B7DBAB', + '#F4D598', + '#70DBED', + '#F9BA8F', + '#F29191', + '#82B5D8', + '#E5A8E2', + '#AEA2E0', + '#E0F9D7', + '#FCEACA', + '#CFFAFF', + '#F9E2D2', + '#FCE2DE', + '#BADFF4', + '#F9D9F9', + '#DEDAF7', +]; + +interface ColorPickerProps { + id?: string; + label: string | number | null; + onChange: (color: string | null, event: BaseSyntheticEvent) => void; + color: string; +} + +export const ColorPicker = ({ onChange, color: selectedColor, id, label }: ColorPickerProps) => ( +
+ + + +
+ {legendColors.map((color) => ( + onChange(color, e)} + onKeyPress={(e) => onChange(color, e)} + className={classNames('visColorPicker__valueDot', { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'visColorPicker__valueDot-isSelected': color === selectedColor, + })} + style={{ color }} + data-test-subj={`visColorPickerColor-${color}`} + /> + ))} +
+ {legendColors.some((c) => c === selectedColor) && ( + + onChange(null, e)} + onKeyPress={(e: any) => onChange(null, e)} + > + + + + )} +
+); diff --git a/src/plugins/charts/public/static/components/current_time.tsx b/src/plugins/charts/public/static/components/current_time.tsx new file mode 100644 index 0000000000000..00c1a74a7bfd8 --- /dev/null +++ b/src/plugins/charts/public/static/components/current_time.tsx @@ -0,0 +1,64 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import moment, { Moment } from 'moment'; +import React, { FC } from 'react'; + +import { LineAnnotation, AnnotationDomainTypes, LineAnnotationStyle } from '@elastic/charts'; +import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; +import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; + +interface CurrentTimeProps { + isDarkMode: boolean; + domainEnd?: number | Moment; +} + +/** + * Render current time line annotation on @elastic/charts `Chart` + */ +export const CurrentTime: FC = ({ isDarkMode, domainEnd }) => { + const lineAnnotationStyle: Partial = { + line: { + strokeWidth: 2, + stroke: isDarkMode ? darkEuiTheme.euiColorDanger : lightEuiTheme.euiColorDanger, + opacity: 0.7, + }, + }; + + // Domain end of 'now' will be milliseconds behind current time, so we extend time by 1 minute and check if + // the annotation is within this range; if so, the line annotation uses the domainEnd as its value + const now = moment(); + const isAnnotationAtEdge = domainEnd + ? moment(domainEnd).add(1, 'm').isAfter(now) && now.isAfter(domainEnd) + : false; + const lineAnnotationData = [ + { + dataValue: isAnnotationAtEdge ? domainEnd : now.valueOf(), + }, + ]; + + return ( + + ); +}; diff --git a/src/plugins/charts/public/static/components/endzones.tsx b/src/plugins/charts/public/static/components/endzones.tsx new file mode 100644 index 0000000000000..db68f72c18c05 --- /dev/null +++ b/src/plugins/charts/public/static/components/endzones.tsx @@ -0,0 +1,197 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { FC } from 'react'; +import moment, { unitOfTime } from 'moment'; + +import { + TooltipValue, + RectAnnotation, + RectAnnotationDatum, + RectAnnotationStyle, +} from '@elastic/charts'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; +import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; +import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; + +interface EndzonesProps { + isDarkMode: boolean; + domainStart: number; + domainEnd: number; + interval: number; + domainMin: number; + domainMax: number; + hideTooltips?: boolean; + /** + * used to toggle full bin endzones for multiple non-stacked bars + */ + isFullBin?: boolean; +} + +export const Endzones: FC = ({ + isDarkMode, + domainStart, + domainEnd, + interval, + domainMin, + domainMax, + hideTooltips = true, + isFullBin = false, +}) => { + const rectAnnotationStyle: Partial = { + stroke: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, + strokeWidth: 0, + opacity: isDarkMode ? 0.6 : 0.2, + fill: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, + }; + + const rectAnnotations: RectAnnotationDatum[] = []; + + if (domainStart > domainMin) { + rectAnnotations.push({ + coordinates: { + x1: isFullBin ? domainMin : domainStart, + }, + }); + } + + if (domainEnd - interval < domainMax) { + rectAnnotations.push({ + coordinates: { + x0: isFullBin ? domainMax : domainEnd, + }, + }); + } + + return ( + + ); +}; + +const findIntervalFromDuration = ( + dateValue: number, + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +) => { + const date = moment.tz(dateValue, timeZone); + const startOfDate = moment.tz(date, timeZone).startOf(esUnit); + const endOfDate = moment.tz(date, timeZone).startOf(esUnit).add(esValue, esUnit); + return endOfDate.valueOf() - startOfDate.valueOf(); +}; + +const getIntervalInMs = ( + value: number, + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +): number => { + switch (esUnit) { + case 's': + return 1000 * esValue; + case 'ms': + return 1 * esValue; + default: + return findIntervalFromDuration(value, esValue, esUnit, timeZone); + } +}; + +/** + * Returns the adjusted interval based on the data + * + * @param xValues sorted and unquie x values + * @param esValue + * @param esUnit + * @param timeZone + */ +export const getAdjustedInterval = ( + xValues: number[], + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +): number => { + const newInterval = xValues.reduce((minInterval, currentXvalue, index) => { + let currentDiff = minInterval; + + if (index > 0) { + currentDiff = Math.abs(xValues[index - 1] - currentXvalue); + } + + const singleUnitInterval = getIntervalInMs(currentXvalue, esValue, esUnit, timeZone); + return Math.min(minInterval, singleUnitInterval, currentDiff); + }, Number.MAX_SAFE_INTEGER); + + return newInterval > 0 ? newInterval : moment.duration(esValue, esUnit).asMilliseconds(); +}; + +const partialDataText = i18n.translate('charts.partialData.bucketTooltipText', { + defaultMessage: + 'The selected time range does not include this entire bucket. It might contain partial data.', +}); + +const Prompt = () => ( + + + + + {partialDataText} + +); + +export const renderEndzoneTooltip = ( + xInterval?: number, + domainStart?: number, + domainEnd?: number, + formatter?: (v: any) => string, + renderValue = true +) => (headerData: TooltipValue): JSX.Element | string => { + const headerDataValue = headerData.value; + const formattedValue = formatter ? formatter(headerDataValue) : headerDataValue; + + if ( + (domainStart !== undefined && domainStart > headerDataValue) || + (domainEnd !== undefined && xInterval !== undefined && domainEnd - xInterval < headerDataValue) + ) { + return ( + <> + + {renderValue && ( + <> + +

{formattedValue}

+ + )} + + ); + } + + return renderValue ? formattedValue : null; +}; diff --git a/src/plugins/charts/public/static/components/index.ts b/src/plugins/charts/public/static/components/index.ts index 48c9e40145481..0d5d7bf3ba277 100644 --- a/src/plugins/charts/public/static/components/index.ts +++ b/src/plugins/charts/public/static/components/index.ts @@ -17,14 +17,9 @@ * under the License. */ -export { BasicOptions } from './basic_options'; -export { ColorModes, Rotates } from './collections'; -export { ColorRanges, SetColorRangeValue } from './color_ranges'; -export { ColorSchemaOptions, SetColorSchemaOptionsValue } from './color_schema'; +export { ColorMode, LabelRotation, defaultCountLabel } from './collections'; export { ColorSchemaParams, Labels, Style } from './types'; -export { NumberInputOption } from './number_input'; -export { RangeOption } from './range'; -export { RequiredNumberInputOption } from './required_number_input'; -export { SelectOption } from './select'; -export { SwitchOption } from './switch'; -export { TextInputOption } from './text_input'; +export { LegendToggle } from './legend_toggle'; +export { ColorPicker } from './color_picker'; +export { CurrentTime } from './current_time'; +export * from './endzones'; diff --git a/src/plugins/charts/public/static/components/legend_toggle.scss b/src/plugins/charts/public/static/components/legend_toggle.scss new file mode 100644 index 0000000000000..7eb85a5e08ec0 --- /dev/null +++ b/src/plugins/charts/public/static/components/legend_toggle.scss @@ -0,0 +1,20 @@ +.echLegend__toggle { + position: absolute; + bottom: 0; + left: 0; + z-index: 1; + margin: $euiSizeXS; + + &--isOpen { + background-color: $euiColorLightestShade; + } + + &--position-left, + &--position-bottom { + left: auto; + bottom: auto; + right: 0; + top: 0; + } +} + diff --git a/src/plugins/charts/public/static/components/legend_toggle.tsx b/src/plugins/charts/public/static/components/legend_toggle.tsx new file mode 100644 index 0000000000000..12742b6da6e6b --- /dev/null +++ b/src/plugins/charts/public/static/components/legend_toggle.tsx @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { memo, useMemo } from 'react'; +import classNames from 'classnames'; + +import { i18n } from '@kbn/i18n'; +import { htmlIdGenerator, EuiButtonIcon } from '@elastic/eui'; +import { Position } from '@elastic/charts'; + +import './legend_toggle.scss'; + +interface LegendToggleProps { + onClick: () => void; + showLegend: boolean; + legendPosition: Position; +} + +const LegendToggleComponent = ({ onClick, showLegend, legendPosition }: LegendToggleProps) => { + const legendId = useMemo(() => htmlIdGenerator()('legend'), []); + + return ( + + ); +}; + +export const LegendToggle = memo(LegendToggleComponent); diff --git a/src/plugins/charts/public/static/components/types.ts b/src/plugins/charts/public/static/components/types.ts index 196eb60b06aec..a4c384141dafb 100644 --- a/src/plugins/charts/public/static/components/types.ts +++ b/src/plugins/charts/public/static/components/types.ts @@ -18,7 +18,7 @@ */ import { ColorSchemas } from '../color_maps'; -import { Rotates } from './collections'; +import { LabelRotation } from './collections'; export interface ColorSchemaParams { colorSchema: ColorSchemas; @@ -29,8 +29,8 @@ export interface Labels { color?: string; filter?: boolean; overwriteColor?: boolean; - rotate?: Rotates; - show: boolean; + rotate?: LabelRotation; + show?: boolean; truncate?: number | null; } diff --git a/src/plugins/charts/public/static/index.ts b/src/plugins/charts/public/static/index.ts index b8a8406c375dd..638e119d8be49 100644 --- a/src/plugins/charts/public/static/index.ts +++ b/src/plugins/charts/public/static/index.ts @@ -20,3 +20,4 @@ export * from './color_maps'; export * from './colors'; export * from './components'; +export * from './utils'; diff --git a/src/core/server/http/prototype_pollution/index.ts b/src/plugins/charts/public/static/utils/index.ts similarity index 93% rename from src/core/server/http/prototype_pollution/index.ts rename to src/plugins/charts/public/static/utils/index.ts index e1a33ffba155e..777deb326125e 100644 --- a/src/core/server/http/prototype_pollution/index.ts +++ b/src/plugins/charts/public/static/utils/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { validateObject } from './validate_object'; +export * from './transform_click_event'; diff --git a/src/plugins/charts/public/static/utils/transform_click_event.ts b/src/plugins/charts/public/static/utils/transform_click_event.ts new file mode 100644 index 0000000000000..21460eb51e3fb --- /dev/null +++ b/src/plugins/charts/public/static/utils/transform_click_event.ts @@ -0,0 +1,238 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + XYChartSeriesIdentifier, + GeometryValue, + XYBrushArea, + Accessor, + AccessorFn, + Datum, +} from '@elastic/charts'; + +import { RangeSelectContext, ValueClickContext } from '../../../../embeddable/public'; +import { Datatable } from '../../../../expressions/public'; + +export interface ClickTriggerEvent { + name: 'filterBucket'; + data: ValueClickContext['data']; +} + +export interface BrushTriggerEvent { + name: 'brush'; + data: RangeSelectContext['data']; +} + +type AllSeriesAccessors = Array<[accessor: Accessor | AccessorFn, value: string | number]>; + +/** + * returns accessor value from string or function accessor + * @param datum + * @param accessor + */ +function getAccessorValue(datum: Datum, accessor: Accessor | AccessorFn) { + if (typeof accessor === 'function') { + return accessor(datum); + } + + return datum[accessor]; +} + +/** + * This is a little unorthodox, but using functional accessors makes it + * difficult to match the correct column. This creates a test object to throw + * an error when the target id is accessed, thus matcing the target column. + */ +function validateAccessorId(id: string, accessor: Accessor | AccessorFn) { + if (typeof accessor !== 'function') { + return id === accessor; + } + + const matchedMessage = 'validateAccessorId matched'; + + try { + accessor({ + get [id]() { + throw new Error(matchedMessage); + }, + }); + return false; + } catch ({ message }) { + return message === matchedMessage; + } +} + +/** + * Groups split accessors by their accessor string or function and related value + * + * @param splitAccessors + * @param splitSeriesAccessorFnMap + */ +const getAllSplitAccessors = ( + splitAccessors: Map, + splitSeriesAccessorFnMap?: Map +): Array<[accessor: Accessor | AccessorFn, value: string | number]> => + [...splitAccessors.entries()].map(([key, value]) => [ + splitSeriesAccessorFnMap?.get?.(key) ?? key, + value, + ]); + +/** + * Reduces matching column indexes + * + * @param xAccessor + * @param yAccessor + * @param splitAccessors + */ +const columnReducer = ( + xAccessor: Accessor | AccessorFn | null, + yAccessor: Accessor | AccessorFn | null, + splitAccessors: AllSeriesAccessors +) => ( + acc: Array<[index: number, id: string]>, + { id }: Datatable['columns'][number], + index: number +): Array<[index: number, id: string]> => { + if ( + (xAccessor !== null && validateAccessorId(id, xAccessor)) || + (yAccessor !== null && validateAccessorId(id, yAccessor)) || + splitAccessors.some(([accessor]) => validateAccessorId(id, accessor)) + ) { + acc.push([index, id]); + } + + return acc; +}; + +/** + * Finds matching row index for given accessors and geometry values + * + * @param geometry + * @param xAccessor + * @param yAccessor + * @param splitAccessors + */ +const rowFindPredicate = ( + geometry: GeometryValue | null, + xAccessor: Accessor | AccessorFn | null, + yAccessor: Accessor | AccessorFn | null, + splitAccessors: AllSeriesAccessors +) => (row: Datatable['rows'][number]): boolean => + (geometry === null || + (xAccessor !== null && + getAccessorValue(row, xAccessor) === geometry.x && + yAccessor !== null && + getAccessorValue(row, yAccessor) === geometry.y)) && + [...splitAccessors].every(([accessor, value]) => getAccessorValue(row, accessor) === value); + +/** + * Helper function to transform `@elastic/charts` click event into filter action event + * + * @param table + * @param xAccessor + * @param splitSeriesAccessorFnMap needed when using `splitSeriesAccessors` as `AccessorFn` + * @param negate + */ +export const getFilterFromChartClickEventFn = ( + table: Datatable, + xAccessor: Accessor | AccessorFn, + splitSeriesAccessorFnMap?: Map, + negate: boolean = false +) => (points: Array<[GeometryValue, XYChartSeriesIdentifier]>): ClickTriggerEvent => { + const data: ValueClickContext['data']['data'] = []; + + points.forEach((point) => { + const [geometry, { yAccessor, splitAccessors }] = point; + const allSplitAccessors = getAllSplitAccessors(splitAccessors, splitSeriesAccessorFnMap); + const columns = table.columns.reduce>( + columnReducer(xAccessor, yAccessor, allSplitAccessors), + [] + ); + const row = table.rows.findIndex( + rowFindPredicate(geometry, xAccessor, yAccessor, allSplitAccessors) + ); + const newData = columns.map(([column, id]) => ({ + table, + column, + row, + value: table.rows?.[row]?.[id] ?? null, + })); + + data.push(...newData); + }); + + return { + name: 'filterBucket', + data: { + negate, + data, + }, + }; +}; + +/** + * Helper function to get filter action event from series + */ +export const getFilterFromSeriesFn = (table: Datatable) => ( + { splitAccessors }: XYChartSeriesIdentifier, + splitSeriesAccessorFnMap?: Map, + negate = false +): ClickTriggerEvent => { + const allSplitAccessors = getAllSplitAccessors(splitAccessors, splitSeriesAccessorFnMap); + const columns = table.columns.reduce>( + columnReducer(null, null, allSplitAccessors), + [] + ); + const row = table.rows.findIndex(rowFindPredicate(null, null, null, allSplitAccessors)); + const data: ValueClickContext['data']['data'] = columns.map(([column, id]) => ({ + table, + column, + row, + value: table.rows?.[row]?.[id] ?? null, + })); + + return { + name: 'filterBucket', + data: { + negate, + data, + }, + }; +}; + +/** + * Helper function to transform `@elastic/charts` brush event into brush action event + */ +export const getBrushFromChartBrushEventFn = ( + table: Datatable, + xAccessor: Accessor | AccessorFn +) => ({ x: selectedRange }: XYBrushArea): BrushTriggerEvent => { + const [start, end] = selectedRange ?? [0, 0]; + const range: [number, number] = [start, end]; + const column = table.columns.findIndex(({ id }) => validateAccessorId(id, xAccessor)); + + return { + data: { + table, + column, + range, + }, + name: 'brush', + }; +}; diff --git a/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx b/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx index 880d40cc3c612..e0d59ef2a17b6 100644 --- a/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx +++ b/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx @@ -19,7 +19,7 @@ import _ from 'lodash'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { ViewMode, PanelState, @@ -39,7 +39,7 @@ export interface AddToLibraryActionContext { embeddable: IEmbeddable; } -export class AddToLibraryAction implements ActionByType { +export class AddToLibraryAction implements Action { public readonly type = ACTION_ADD_TO_LIBRARY; public readonly id = ACTION_ADD_TO_LIBRARY; public order = 15; diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx index d27e2d6dce651..e59cefed598e8 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -21,7 +21,7 @@ import _ from 'lodash'; import uuid from 'uuid'; import { CoreStart } from 'src/core/public'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { SavedObject } from '../../services/saved_objects'; import { ViewMode, @@ -45,7 +45,7 @@ export interface ClonePanelActionContext { embeddable: IEmbeddable; } -export class ClonePanelAction implements ActionByType { +export class ClonePanelAction implements Action { public readonly type = ACTION_CLONE_PANEL; public readonly id = ACTION_CLONE_PANEL; public order = 45; diff --git a/src/plugins/dashboard/public/application/actions/expand_panel_action.tsx b/src/plugins/dashboard/public/application/actions/expand_panel_action.tsx index fe14ce13d44bc..3336f8dc5915c 100644 --- a/src/plugins/dashboard/public/application/actions/expand_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/expand_panel_action.tsx @@ -19,7 +19,7 @@ import { dashboardExpandPanelAction } from '../../dashboard_strings'; import { IEmbeddable } from '../../services/embeddable'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { DASHBOARD_CONTAINER_TYPE, DashboardContainer, @@ -46,7 +46,7 @@ export interface ExpandPanelActionContext { embeddable: IEmbeddable; } -export class ExpandPanelAction implements ActionByType { +export class ExpandPanelAction implements Action { public readonly type = ACTION_EXPAND_PANEL; public readonly id = ACTION_EXPAND_PANEL; public order = 7; diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx index 4f78a738095d2..1048ce2189744 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx @@ -24,7 +24,7 @@ import { FormatFactory } from '../../../../data/common/field_formats/utils'; import { DataPublicPluginStart, exporters } from '../../services/data'; import { downloadMultipleAs } from '../../services/share'; import { Adapters, IEmbeddable } from '../../services/embeddable'; -import { ActionByType } from '../../services/ui_actions'; +import { Action } from '../../services/ui_actions'; import { dashboardExportCsvAction } from '../../dashboard_strings'; export const ACTION_EXPORT_CSV = 'ACTION_EXPORT_CSV'; @@ -44,7 +44,7 @@ export interface ExportContext { * This is "Export CSV" action which appears in the context * menu of a dashboard panel. */ -export class ExportCSVAction implements ActionByType { +export class ExportCSVAction implements Action { public readonly id = ACTION_EXPORT_CSV; public readonly type = ACTION_EXPORT_CSV; @@ -65,7 +65,7 @@ export class ExportCSVAction implements ActionByType { } private hasDatatableContent = (adapters: Adapters | undefined) => { - return Object.keys(adapters?.tables || {}).length > 0; + return Object.keys(adapters?.tables || {}).length > 0 && adapters!.tables.allowCsvExport; }; private getFormatter = (): FormatFactory | undefined => { @@ -76,7 +76,7 @@ export class ExportCSVAction implements ActionByType { private getDataTableContent = (adapters: Adapters | undefined) => { if (this.hasDatatableContent(adapters)) { - return adapters?.tables; + return adapters?.tables.tables; } return; }; diff --git a/src/plugins/dashboard/public/application/actions/library_notification_action.tsx b/src/plugins/dashboard/public/application/actions/library_notification_action.tsx index 13ccb279df821..a6d718846b9fe 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_action.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_action.tsx @@ -19,7 +19,7 @@ import React from 'react'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { reactToUiComponent } from '../../services/kibana_react'; import { IEmbeddable, @@ -38,7 +38,7 @@ export interface LibraryNotificationActionContext { embeddable: IEmbeddable; } -export class LibraryNotificationAction implements ActionByType { +export class LibraryNotificationAction implements Action { public readonly id = ACTION_LIBRARY_NOTIFICATION; public readonly type = ACTION_LIBRARY_NOTIFICATION; public readonly order = 1; diff --git a/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx b/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx index 553a0b9770d01..909b758c511a9 100644 --- a/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx @@ -20,7 +20,7 @@ import { CoreStart } from 'src/core/public'; import { IEmbeddable, ViewMode, EmbeddableStart } from '../../services/embeddable'; import { DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '../embeddable'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { openReplacePanelFlyout } from './open_replace_panel_flyout'; import { dashboardReplacePanelAction } from '../../dashboard_strings'; @@ -34,7 +34,7 @@ export interface ReplacePanelActionContext { embeddable: IEmbeddable; } -export class ReplacePanelAction implements ActionByType { +export class ReplacePanelAction implements Action { public readonly type = ACTION_REPLACE_PANEL; public readonly id = ACTION_REPLACE_PANEL; public order = 3; diff --git a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx index 93ceb72624259..901367b6af833 100644 --- a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { ActionByType, IncompatibleActionError } from '../../services/ui_actions'; +import { Action, IncompatibleActionError } from '../../services/ui_actions'; import { ViewMode, PanelState, @@ -38,7 +38,7 @@ export interface UnlinkFromLibraryActionContext { embeddable: IEmbeddable; } -export class UnlinkFromLibraryAction implements ActionByType { +export class UnlinkFromLibraryAction implements Action { public readonly type = ACTION_UNLINK_FROM_LIBRARY; public readonly id = ACTION_UNLINK_FROM_LIBRARY; public order = 15; diff --git a/src/plugins/dashboard/public/application/dashboard_app.tsx b/src/plugins/dashboard/public/application/dashboard_app.tsx index 8eff48251b371..845d64c16500d 100644 --- a/src/plugins/dashboard/public/application/dashboard_app.tsx +++ b/src/plugins/dashboard/public/application/dashboard_app.tsx @@ -45,6 +45,7 @@ import { removeQueryParam } from '../services/kibana_utils'; import { IndexPattern } from '../services/data'; import { EmbeddableRenderer } from '../services/embeddable'; import { DashboardContainerInput } from '.'; +import { leaveConfirmStrings } from '../dashboard_strings'; export interface DashboardAppProps { history: History; @@ -64,8 +65,9 @@ export function DashboardApp({ core, onAppLeave, uiSettings, - indexPatterns: indexPatternService, + embeddable, dashboardCapabilities, + indexPatterns: indexPatternService, } = useKibana().services; const [lastReloadTime, setLastReloadTime] = useState(0); @@ -196,9 +198,14 @@ export function DashboardApp({ return; } onAppLeave((actions) => { - if (dashboardStateManager?.getIsDirty()) { - // TODO: Finish App leave handler with overrides when redirecting to an editor. - // return actions.confirm(leaveConfirmStrings.leaveSubtitle, leaveConfirmStrings.leaveTitle); + if ( + dashboardStateManager?.getIsDirty() && + !embeddable.getStateTransfer().isTransferInProgress + ) { + return actions.confirm( + leaveConfirmStrings.getLeaveSubtitle(), + leaveConfirmStrings.getLeaveTitle() + ); } return actions.default(); }); @@ -206,7 +213,7 @@ export function DashboardApp({ // reset on app leave handler so leaving from the listing page doesn't trigger a confirmation onAppLeave((actions) => actions.default()); }; - }, [dashboardStateManager, dashboardContainer, onAppLeave]); + }, [dashboardStateManager, dashboardContainer, onAppLeave, embeddable]); // Refresh the dashboard container when lastReloadTime changes useEffect(() => { diff --git a/src/plugins/dashboard/public/application/dashboard_app_functions.ts b/src/plugins/dashboard/public/application/dashboard_app_functions.ts index 0381fdb2e55b5..af7a485296ea0 100644 --- a/src/plugins/dashboard/public/application/dashboard_app_functions.ts +++ b/src/plugins/dashboard/public/application/dashboard_app_functions.ts @@ -151,6 +151,7 @@ export const getDashboardContainerInput = ({ description: dashboardStateManager.getDescription(), id: dashboardStateManager.savedDashboard.id || '', useMargins: dashboardStateManager.getUseMargins(), + syncColors: dashboardStateManager.getSyncColors(), viewMode: dashboardStateManager.getViewMode(), filters: query.filterManager.getFilters(), query: dashboardStateManager.getQuery(), diff --git a/src/plugins/dashboard/public/application/dashboard_router.tsx b/src/plugins/dashboard/public/application/dashboard_router.tsx index 9673737372478..1ea6355b9c558 100644 --- a/src/plugins/dashboard/public/application/dashboard_router.tsx +++ b/src/plugins/dashboard/public/application/dashboard_router.tsx @@ -22,7 +22,7 @@ import React from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { parse, ParsedQuery } from 'query-string'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Switch, Route, RouteComponentProps, HashRouter } from 'react-router-dom'; +import { Switch, Route, RouteComponentProps, HashRouter, Redirect } from 'react-router-dom'; import { DashboardListing } from './listing'; import { DashboardApp } from './dashboard_app'; @@ -202,6 +202,9 @@ export async function mountApp({ render={renderDashboard} /> + + + diff --git a/src/plugins/dashboard/public/application/dashboard_state.test.ts b/src/plugins/dashboard/public/application/dashboard_state.test.ts index b07ea762f35e0..f31ed30f8eb80 100644 --- a/src/plugins/dashboard/public/application/dashboard_state.test.ts +++ b/src/plugins/dashboard/public/application/dashboard_state.test.ts @@ -68,6 +68,7 @@ describe('DashboardState', function () { query: {} as DashboardContainerInput['query'], timeRange: {} as DashboardContainerInput['timeRange'], useMargins: true, + syncColors: false, title: 'ultra awesome test dashboard', isFullScreenMode: false, panels: {} as DashboardContainerInput['panels'], diff --git a/src/plugins/dashboard/public/application/dashboard_state_manager.ts b/src/plugins/dashboard/public/application/dashboard_state_manager.ts index daa0bbdfc9f8a..dfcbfcafd3db1 100644 --- a/src/plugins/dashboard/public/application/dashboard_state_manager.ts +++ b/src/plugins/dashboard/public/application/dashboard_state_manager.ts @@ -404,6 +404,15 @@ export class DashboardStateManager { this.stateContainer.transitions.setOption('useMargins', useMargins); } + public getSyncColors() { + // Existing dashboards that don't define this should default to true. + return this.appState.options.syncColors === undefined ? true : this.appState.options.syncColors; + } + + public setSyncColors(syncColors: boolean) { + this.stateContainer.transitions.setOption('syncColors', syncColors); + } + public getHidePanelTitles() { return this.appState.options.hidePanelTitles; } diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx index 01b4e81fc484c..a3b67ede9f3f9 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx @@ -59,6 +59,7 @@ export interface DashboardContainerInput extends ContainerInput { timeRange: TimeRange; description?: string; useMargins: boolean; + syncColors?: boolean; viewMode: ViewMode; filters: Filter[]; title: string; @@ -93,6 +94,7 @@ export interface InheritedChildInput extends IndexSignature { hidePanelTitles?: boolean; id: string; searchSessionId?: string; + syncColors?: boolean; } export type DashboardReactContextValue = KibanaReactContextValue; @@ -269,6 +271,7 @@ export class DashboardContainer extends Container
{ (async function loadSavedDashboard() { @@ -46,7 +46,7 @@ export const useSavedDashboard = (savedDashboardId: string | undefined, history: pathname: DashboardConstants.CREATE_NEW_DASHBOARD_URL, }); - showWarningToast(getDashboard60Warning()); + toasts.addWarning(getDashboard60Warning()); return; } @@ -63,7 +63,7 @@ export const useSavedDashboard = (savedDashboardId: string | undefined, history: setSavedDashboard(dashboard); } catch (error) { // E.g. a corrupt or deleted dashboard - showDangerToast(error.message); + toasts.addDanger(error.message); history.push(DashboardConstants.LANDING_PAGE_PATH); } })(); @@ -75,8 +75,7 @@ export const useSavedDashboard = (savedDashboardId: string | undefined, history: recentlyAccessedPaths, savedDashboardId, savedDashboards, - showDangerToast, - showWarningToast, + toasts, ]); return savedDashboard; diff --git a/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap index fad7d8ddaabfe..bce8a661634f6 100644 --- a/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap +++ b/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap @@ -126,7 +126,7 @@ exports[`after fetch When given a title that matches multiple dashboards, filter restrictWidth={true} >
@@ -218,7 +218,7 @@ exports[`after fetch hideWriteControls 1`] = ` restrictWidth={true} >
@@ -358,7 +358,7 @@ exports[`after fetch initialFilter 1`] = ` restrictWidth={true} >
@@ -497,7 +497,7 @@ exports[`after fetch renders all table rows 1`] = ` restrictWidth={true} >
@@ -636,7 +636,7 @@ exports[`after fetch renders call to action when no dashboards exist 1`] = ` restrictWidth={true} >
@@ -775,7 +775,7 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = ` restrictWidth={true} >
diff --git a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx index 937e6737d2716..87ccbf29b99f7 100644 --- a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx @@ -27,6 +27,7 @@ import { useKibana } from '../../services/kibana_react'; import { IndexPattern, SavedQuery, TimefilterContract } from '../../services/data'; import { EmbeddableFactoryNotFoundError, + EmbeddableInput, isErrorEmbeddable, openAddPanelFlyout, ViewMode, @@ -56,10 +57,12 @@ import { showOptionsPopover } from './show_options_popover'; import { TopNavIds } from './top_nav_ids'; import { ShowShareModal } from './show_share_modal'; import { PanelToolbar } from './panel_toolbar'; +import { OverlayRef } from '../../../../../core/public'; import { DashboardContainer } from '..'; export interface DashboardTopNavState { chromeIsVisible: boolean; + addPanelOverlay?: OverlayRef; savedQuery?: SavedQuery; } @@ -110,14 +113,17 @@ export function DashboardTopNav({ const addFromLibrary = useCallback(() => { if (!isErrorEmbeddable(dashboardContainer)) { - openAddPanelFlyout({ - embeddable: dashboardContainer, - getAllFactories: embeddable.getEmbeddableFactories, - getFactory: embeddable.getEmbeddableFactory, - notifications: core.notifications, - overlays: core.overlays, - SavedObjectFinder: getSavedObjectFinder(core.savedObjects, uiSettings), - }); + setState((s) => ({ + ...s, + addPanelOverlay: openAddPanelFlyout({ + embeddable: dashboardContainer, + getAllFactories: embeddable.getEmbeddableFactories, + getFactory: embeddable.getEmbeddableFactory, + notifications: core.notifications, + overlays: core.overlays, + SavedObjectFinder: getSavedObjectFinder(core.savedObjects, uiSettings), + }), + })); } }, [ embeddable.getEmbeddableFactories, @@ -135,14 +141,19 @@ export function DashboardTopNav({ if (!factory) { throw new EmbeddableFactoryNotFoundError(type); } - const explicitInput = await factory.getExplicitInput(); - if (dashboardContainer) { - await dashboardContainer.addNewEmbeddable(type, explicitInput); - } + await factory.create({} as EmbeddableInput, dashboardContainer); }, [dashboardContainer, embeddable]); + const clearAddPanel = useCallback(() => { + if (state.addPanelOverlay) { + state.addPanelOverlay.close(); + setState((s) => ({ ...s, addPanelOverlay: undefined })); + } + }, [state.addPanelOverlay]); + const onChangeViewMode = useCallback( (newMode: ViewMode) => { + clearAddPanel(); const isPageRefresh = newMode === dashboardStateManager.getViewMode(); const isLeavingEditMode = !isPageRefresh && newMode === ViewMode.VIEW; const willLoseChanges = isLeavingEditMode && dashboardStateManager.getIsDirty(timefilter); @@ -180,7 +191,7 @@ export function DashboardTopNav({ } }); }, - [redirectTo, timefilter, core.overlays, savedDashboard.id, dashboardStateManager] + [redirectTo, timefilter, core.overlays, savedDashboard.id, dashboardStateManager, clearAddPanel] ); /** @@ -303,8 +314,16 @@ export function DashboardTopNav({ showCopyOnSave={lastDashboardId ? true : false} /> ); + clearAddPanel(); showSaveModal(dashboardSaveModal, core.i18n.Context); - }, [save, core.i18n.Context, savedObjectsTagging, dashboardStateManager, lastDashboardId]); + }, [ + save, + clearAddPanel, + lastDashboardId, + core.i18n.Context, + savedObjectsTagging, + dashboardStateManager, + ]); const runClone = useCallback(() => { const currentTitle = dashboardStateManager.getTitle(); @@ -350,6 +369,10 @@ export function DashboardTopNav({ onUseMarginsChange: (isChecked: boolean) => { dashboardStateManager.setUseMargins(isChecked); }, + syncColors: dashboardStateManager.getSyncColors(), + onSyncColorsChange: (isChecked: boolean) => { + dashboardStateManager.setSyncColors(isChecked); + }, hidePanelTitles: dashboardStateManager.getHidePanelTitles(), onHidePanelTitlesChange: (isChecked: boolean) => { dashboardStateManager.setHidePanelTitles(isChecked); diff --git a/src/plugins/dashboard/public/application/top_nav/options.tsx b/src/plugins/dashboard/public/application/top_nav/options.tsx index 3398696ff40db..86409cdeba74f 100644 --- a/src/plugins/dashboard/public/application/top_nav/options.tsx +++ b/src/plugins/dashboard/public/application/top_nav/options.tsx @@ -27,17 +27,21 @@ interface Props { onUseMarginsChange: (useMargins: boolean) => void; hidePanelTitles: boolean; onHidePanelTitlesChange: (hideTitles: boolean) => void; + syncColors: boolean; + onSyncColorsChange: (syncColors: boolean) => void; } interface State { useMargins: boolean; hidePanelTitles: boolean; + syncColors: boolean; } export class OptionsMenu extends Component { state = { useMargins: this.props.useMargins, hidePanelTitles: this.props.hidePanelTitles, + syncColors: this.props.syncColors, }; constructor(props: Props) { @@ -56,6 +60,12 @@ export class OptionsMenu extends Component { this.setState({ hidePanelTitles: isChecked }); }; + handleSyncColorsChange = (evt: any) => { + const isChecked = evt.target.checked; + this.props.onSyncColorsChange(isChecked); + this.setState({ syncColors: isChecked }); + }; + render() { return ( @@ -80,6 +90,17 @@ export class OptionsMenu extends Component { data-test-subj="dashboardPanelTitlesCheckbox" /> + + + + ); } diff --git a/src/plugins/dashboard/public/application/top_nav/show_options_popover.tsx b/src/plugins/dashboard/public/application/top_nav/show_options_popover.tsx index 7c23e4808fbea..6c519ccad327f 100644 --- a/src/plugins/dashboard/public/application/top_nav/show_options_popover.tsx +++ b/src/plugins/dashboard/public/application/top_nav/show_options_popover.tsx @@ -39,10 +39,14 @@ export function showOptionsPopover({ onUseMarginsChange, hidePanelTitles, onHidePanelTitlesChange, + syncColors, + onSyncColorsChange, }: { anchorElement: HTMLElement; useMargins: boolean; onUseMarginsChange: (useMargins: boolean) => void; + syncColors: boolean; + onSyncColorsChange: (syncColors: boolean) => void; hidePanelTitles: boolean; onHidePanelTitlesChange: (hideTitles: boolean) => void; }) { @@ -62,6 +66,8 @@ export function showOptionsPopover({ onUseMarginsChange={onUseMarginsChange} hidePanelTitles={hidePanelTitles} onHidePanelTitlesChange={onHidePanelTitlesChange} + syncColors={syncColors} + onSyncColorsChange={onSyncColorsChange} /> diff --git a/src/plugins/dashboard/public/dashboard_strings.ts b/src/plugins/dashboard/public/dashboard_strings.ts index 4aa552893ab9b..9bede02c75b94 100644 --- a/src/plugins/dashboard/public/dashboard_strings.ts +++ b/src/plugins/dashboard/public/dashboard_strings.ts @@ -134,7 +134,7 @@ export const dashboardExportCsvAction = { }), getUntitledFilename: () => i18n.translate('dashboard.actions.downloadOptionsUnsavedFilename', { - defaultMessage: 'unsaved', + defaultMessage: 'untitled', }), }; diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 4dff423098c5a..166f4eaf39997 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -62,27 +62,15 @@ import { } from './services/kibana_react'; import { - ACTION_CLONE_PANEL, - ACTION_EXPAND_PANEL, - ACTION_REPLACE_PANEL, ClonePanelAction, - ClonePanelActionContext, createDashboardContainerByValueRenderer, DASHBOARD_CONTAINER_TYPE, DashboardContainerFactory, DashboardContainerFactoryDefinition, ExpandPanelAction, - ExpandPanelActionContext, ReplacePanelAction, - ReplacePanelActionContext, - ACTION_UNLINK_FROM_LIBRARY, - UnlinkFromLibraryActionContext, UnlinkFromLibraryAction, - ACTION_ADD_TO_LIBRARY, - AddToLibraryActionContext, AddToLibraryAction, - ACTION_LIBRARY_NOTIFICATION, - LibraryNotificationActionContext, LibraryNotificationAction, } from './application'; import { @@ -94,11 +82,7 @@ import { createSavedDashboardLoader } from './saved_dashboards'; import { DashboardConstants } from './dashboard_constants'; import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder'; import { UrlGeneratorState } from '../../share/public'; -import { - ACTION_EXPORT_CSV, - ExportContext, - ExportCSVAction, -} from './application/actions/export_csv_action'; +import { ExportCSVAction } from './application/actions/export_csv_action'; import { dashboardFeatureCatalog } from './dashboard_strings'; declare module '../../share/public' { @@ -147,18 +131,6 @@ export interface DashboardStart { DashboardContainerByValueRenderer: ReturnType; } -declare module '../../../plugins/ui_actions/public' { - export interface ActionContextMapping { - [ACTION_EXPAND_PANEL]: ExpandPanelActionContext; - [ACTION_REPLACE_PANEL]: ReplacePanelActionContext; - [ACTION_CLONE_PANEL]: ClonePanelActionContext; - [ACTION_ADD_TO_LIBRARY]: AddToLibraryActionContext; - [ACTION_UNLINK_FROM_LIBRARY]: UnlinkFromLibraryActionContext; - [ACTION_LIBRARY_NOTIFICATION]: LibraryNotificationActionContext; - [ACTION_EXPORT_CSV]: ExportContext; - } -} - export class DashboardPlugin implements Plugin { diff --git a/src/plugins/dashboard/public/services/ui_actions.ts b/src/plugins/dashboard/public/services/ui_actions.ts index 4c9ac590191f6..81bdad35d464c 100644 --- a/src/plugins/dashboard/public/services/ui_actions.ts +++ b/src/plugins/dashboard/public/services/ui_actions.ts @@ -18,7 +18,7 @@ */ export { - ActionByType, + Action, IncompatibleActionError, UiActionsSetup, UiActionsStart, diff --git a/src/plugins/dashboard/public/types.ts b/src/plugins/dashboard/public/types.ts index 7e859a81d9d4d..882c5b4286263 100644 --- a/src/plugins/dashboard/public/types.ts +++ b/src/plugins/dashboard/public/types.ts @@ -78,6 +78,7 @@ export interface DashboardAppState { options: { hidePanelTitles: boolean; useMargins: boolean; + syncColors?: boolean; }; query: Query | string; filters: Filter[]; diff --git a/src/plugins/data/common/es_query/kuery/index.ts b/src/plugins/data/common/es_query/kuery/index.ts index 4184dea62ef2c..5b6cfab030acb 100644 --- a/src/plugins/data/common/es_query/kuery/index.ts +++ b/src/plugins/data/common/es_query/kuery/index.ts @@ -18,7 +18,7 @@ */ export { KQLSyntaxError } from './kuery_syntax_error'; -export { nodeTypes } from './node_types'; +export { nodeTypes, nodeBuilder } from './node_types'; export * from './ast'; export * from './types'; diff --git a/src/plugins/data/common/es_query/kuery/node_types/index.ts b/src/plugins/data/common/es_query/kuery/node_types/index.ts index 22e73e791df9a..bec42f89c5b71 100644 --- a/src/plugins/data/common/es_query/kuery/node_types/index.ts +++ b/src/plugins/data/common/es_query/kuery/node_types/index.ts @@ -24,6 +24,7 @@ import * as wildcard from './wildcard'; import { NodeTypes } from './types'; export { NodeTypes }; +export { nodeBuilder } from './node_builder'; export const nodeTypes: NodeTypes = { // This requires better typing of the different typings and their return types. diff --git a/src/plugins/ui_actions/public/triggers/value_click_trigger.ts b/src/plugins/data/common/es_query/kuery/node_types/node_builder.ts similarity index 52% rename from src/plugins/ui_actions/public/triggers/value_click_trigger.ts rename to src/plugins/data/common/es_query/kuery/node_types/node_builder.ts index f1aff6322522a..4b77566dbc32b 100644 --- a/src/plugins/ui_actions/public/triggers/value_click_trigger.ts +++ b/src/plugins/data/common/es_query/kuery/node_types/node_builder.ts @@ -17,16 +17,22 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { Trigger } from '.'; +import { KueryNode, nodeTypes } from '../types'; -export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; -export const valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'> = { - id: VALUE_CLICK_TRIGGER, - title: i18n.translate('uiActions.triggers.valueClickTitle', { - defaultMessage: 'Single click', - }), - description: i18n.translate('uiActions.triggers.valueClickDescription', { - defaultMessage: 'A data point click on the visualization', - }), +export const nodeBuilder = { + is: (fieldName: string, value: string | KueryNode) => { + return nodeTypes.function.buildNodeWithArgumentNodes('is', [ + nodeTypes.literal.buildNode(fieldName), + typeof value === 'string' ? nodeTypes.literal.buildNode(value) : value, + nodeTypes.literal.buildNode(false), + ]); + }, + or: ([first, ...args]: KueryNode[]): KueryNode => { + return args.length ? nodeTypes.function.buildNode('or', [first, nodeBuilder.or(args)]) : first; + }, + and: ([first, ...args]: KueryNode[]): KueryNode => { + return args.length + ? nodeTypes.function.buildNode('and', [first, nodeBuilder.and(args)]) + : first; + }, }; diff --git a/src/plugins/data/common/index_patterns/index_pattern.stub.ts b/src/plugins/data/common/index_patterns/index_pattern.stub.ts index e7384e09494aa..c47a8b605ada3 100644 --- a/src/plugins/data/common/index_patterns/index_pattern.stub.ts +++ b/src/plugins/data/common/index_patterns/index_pattern.stub.ts @@ -25,6 +25,7 @@ export const stubIndexPattern: IIndexPattern = { fields: stubFields, title: 'logstash-*', timeFieldName: '@timestamp', + getTimeField: () => ({ name: '@timestamp', type: 'date' }), }; export const stubIndexPatternWithFields: IIndexPattern = { diff --git a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap index 19ec286307a09..76de2b2662bb0 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap +++ b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap @@ -2,6 +2,7 @@ exports[`IndexPattern toSpec should match snapshot 1`] = ` Object { + "allowNoIndex": false, "fieldAttrs": Object {}, "fieldFormats": Object {}, "fields": Object { diff --git a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_patterns.test.ts.snap b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_patterns.test.ts.snap index c020e7595c565..bad74430b8966 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_patterns.test.ts.snap +++ b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_patterns.test.ts.snap @@ -2,6 +2,7 @@ exports[`IndexPatterns savedObjectToSpec 1`] = ` Object { + "allowNoIndex": undefined, "fieldAttrs": Object {}, "fieldFormats": Object { "field": Object {}, diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts index 4c89cbeb446a0..590ff872f3bf9 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts @@ -74,6 +74,10 @@ export class IndexPattern implements IIndexPattern { private fieldFormats: FieldFormatsStartCommon; // make private once manual field refresh is removed public fieldAttrs: FieldAttrs; + /** + * prevents errors when index pattern exists before indices + */ + public readonly allowNoIndex: boolean = false; constructor({ spec = {}, @@ -110,6 +114,7 @@ export class IndexPattern implements IIndexPattern { this.typeMeta = spec.typeMeta; this.fieldAttrs = spec.fieldAttrs || {}; this.intervalName = spec.intervalName; + this.allowNoIndex = spec.allowNoIndex || false; } /** @@ -204,6 +209,7 @@ export class IndexPattern implements IIndexPattern { fieldFormats: this.fieldFormatMap, fieldAttrs: this.fieldAttrs, intervalName: this.intervalName, + allowNoIndex: this.allowNoIndex, }; } @@ -309,6 +315,7 @@ export class IndexPattern implements IIndexPattern { fieldFormatMap, type: this.type, typeMeta: this.typeMeta ? JSON.stringify(this.typeMeta) : undefined, + allowNoIndex: this.allowNoIndex ? this.allowNoIndex : undefined, }; } diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts index 2a203b57d201b..3d32742c168ad 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts @@ -114,6 +114,21 @@ describe('IndexPatterns', () => { SOClientGetDelay = 0; }); + test('allowNoIndex flag preserves existing fields when index is missing', async () => { + const id = '2'; + setDocsourcePayload(id, { + id: 'foo', + version: 'foo', + attributes: { + title: 'something', + allowNoIndex: true, + fields: '[{"name":"field"}]', + }, + }); + + expect((await indexPatterns.get(id)).fields.length).toBe(1); + }); + test('savedObjectCache pre-fetches only title', async () => { expect(await indexPatterns.getIds()).toEqual(['id']); expect(savedObjectsClient.find).toHaveBeenCalledWith({ diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index 0235f748ec1e0..3333dba36fe69 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -222,6 +222,7 @@ export class IndexPatternsService { metaFields, type: options.type, rollupIndex: options.rollupIndex, + allowNoIndex: options.allowNoIndex, }); }; @@ -281,10 +282,21 @@ export class IndexPatternsService { options: GetFieldsOptions, fieldAttrs: FieldAttrs = {} ) => { - const scriptedFields = Object.values(fields).filter((field) => field.scripted); + const fieldsAsArr = Object.values(fields); + const scriptedFields = fieldsAsArr.filter((field) => field.scripted); try { + let updatedFieldList: FieldSpec[]; const newFields = (await this.getFieldsForWildcard(options)) as FieldSpec[]; - return this.fieldArrayToMap([...newFields, ...scriptedFields], fieldAttrs); + + // If allowNoIndex, only update field list if field caps finds fields. To support + // beats creating index pattern and dashboard before docs + if (!options.allowNoIndex || (newFields && newFields.length > 5)) { + updatedFieldList = [...newFields, ...scriptedFields]; + } else { + updatedFieldList = fieldsAsArr; + } + + return this.fieldArrayToMap(updatedFieldList, fieldAttrs); } catch (err) { if (err instanceof IndexPatternMissingIndices) { this.onNotification({ title: (err as any).message, color: 'danger', iconType: 'alert' }); @@ -334,6 +346,7 @@ export class IndexPatternsService { typeMeta, type, fieldAttrs, + allowNoIndex, }, } = savedObject; @@ -355,6 +368,7 @@ export class IndexPatternsService { type, fieldFormats: parsedFieldFormatMap, fieldAttrs: parsedFieldAttrs, + allowNoIndex, }; }; @@ -384,6 +398,7 @@ export class IndexPatternsService { metaFields: await this.config.get(UI_SETTINGS.META_FIELDS), type, rollupIndex: typeMeta?.params?.rollup_index, + allowNoIndex: spec.allowNoIndex, }, spec.fieldAttrs ); diff --git a/src/plugins/data/common/index_patterns/types.ts b/src/plugins/data/common/index_patterns/types.ts index 8d9b29175162e..12496b07d3482 100644 --- a/src/plugins/data/common/index_patterns/types.ts +++ b/src/plugins/data/common/index_patterns/types.ts @@ -49,6 +49,10 @@ export interface IndexPatternAttributes { sourceFilters?: string; fieldFormatMap?: string; fieldAttrs?: string; + /** + * prevents errors when index pattern exists before indices + */ + allowNoIndex?: boolean; } export interface FieldAttrs { @@ -101,6 +105,7 @@ export interface GetFieldsOptions { lookBack?: boolean; metaFields?: string[]; rollupIndex?: string; + allowNoIndex?: boolean; } export interface GetFieldsOptionsTimePattern { @@ -193,6 +198,7 @@ export interface IndexPatternSpec { type?: string; fieldFormats?: Record; fieldAttrs?: FieldAttrs; + allowNoIndex?: boolean; } export interface SourceFilter { diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts index 160860bcce591..eeaebecfe7f76 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts @@ -203,11 +203,12 @@ describe('Aggs service', () => { describe('start()', () => { test('exposes proper contract', () => { const start = service.start(startDeps); - expect(Object.keys(start).length).toBe(4); + expect(Object.keys(start).length).toBe(5); expect(start).toHaveProperty('calculateAutoTimeExpression'); expect(start).toHaveProperty('getDateMetaByDatatableColumn'); expect(start).toHaveProperty('createAggConfigs'); expect(start).toHaveProperty('types'); + expect(start).toHaveProperty('datatableUtilities'); }); test('types registry returns uninitialized type providers', () => { diff --git a/src/plugins/data/common/search/aggs/aggs_service.ts b/src/plugins/data/common/search/aggs/aggs_service.ts index b6afa708f9e6f..4b1756fabf1a7 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.ts @@ -18,7 +18,7 @@ */ import { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; -import { IndexPattern, UI_SETTINGS } from '../../../common'; +import { CreateAggConfigParams, IndexPattern, UI_SETTINGS } from '../../../common'; import { GetConfigFn } from '../../types'; import { AggConfigs, @@ -29,6 +29,7 @@ import { } from './'; import { AggsCommonSetup, AggsCommonStart } from './types'; import { getDateMetaByDatatableColumn } from './utils/time_column_meta'; +import { getDatatableColumnUtilities } from './utils/datatable_column_meta'; /** @internal */ export const aggsRequiredUiSettings = [ @@ -88,6 +89,15 @@ export class AggsCommonService { const aggTypesStart = this.aggTypesRegistry.start(); const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig); + const createAggConfigs = ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[] + ) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: aggTypesStart, + }); + }; + return { calculateAutoTimeExpression, getDateMetaByDatatableColumn: getDateMetaByDatatableColumn({ @@ -96,11 +106,12 @@ export class AggsCommonService { getConfig, isDefaultTimezone, }), - createAggConfigs: (indexPattern, configStates = [], schemas) => { - return new AggConfigs(indexPattern, configStates, { - typesRegistry: aggTypesStart, - }); - }, + datatableUtilities: getDatatableColumnUtilities({ + getIndexPattern, + createAggConfigs, + aggTypesStart, + }), + createAggConfigs, types: aggTypesStart, }; } diff --git a/src/plugins/data/common/search/aggs/buckets/date_histogram.ts b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts index ba79a4264d603..6b7f1522d19ad 100644 --- a/src/plugins/data/common/search/aggs/buckets/date_histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts @@ -149,7 +149,7 @@ export const getDateHistogramBucketAgg = ({ type: 'field', filterFieldTypes: KBN_FIELD_TYPES.DATE, default(agg: IBucketDateHistogramAggConfig) { - return agg.getIndexPattern().timeFieldName; + return agg.getIndexPattern().getTimeField?.()?.name; }, onChange(agg: IBucketDateHistogramAggConfig) { if (isAutoInterval(get(agg, 'params.interval')) && !agg.fieldIsTimeField()) { diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts index f3ae7d66dca96..1055777396f5f 100644 --- a/src/plugins/data/common/search/aggs/types.ts +++ b/src/plugins/data/common/search/aggs/types.ts @@ -94,6 +94,7 @@ import { CreateAggConfigParams, getCalculateAutoTimeExpression, METRIC_TYPES, + AggConfig, } from './'; export { IAggConfig, AggConfigSerialized } from './agg_config'; @@ -127,10 +128,14 @@ export interface AggsCommonStart { getDateMetaByDatatableColumn: ( column: DatatableColumn ) => Promise; + datatableUtilities: { + getIndexPattern: (column: DatatableColumn) => Promise; + getAggConfig: (column: DatatableColumn) => Promise; + isFilterable: (column: DatatableColumn) => boolean; + }; createAggConfigs: ( indexPattern: IndexPattern, - configStates?: CreateAggConfigParams[], - schemas?: Record + configStates?: CreateAggConfigParams[] ) => InstanceType; types: ReturnType; } diff --git a/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts b/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts new file mode 100644 index 0000000000000..38865f05727a9 --- /dev/null +++ b/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { DatatableColumn } from 'src/plugins/expressions/common'; +import { IndexPattern } from '../../../index_patterns'; +import { AggConfigs, CreateAggConfigParams } from '../agg_configs'; +import { AggTypesRegistryStart } from '../agg_types_registry'; +import { IAggType } from '../agg_type'; + +export interface MetaByColumnDeps { + getIndexPattern: (id: string) => Promise; + createAggConfigs: ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[] + ) => InstanceType; + aggTypesStart: AggTypesRegistryStart; +} + +export const getDatatableColumnUtilities = (deps: MetaByColumnDeps) => { + const { getIndexPattern, createAggConfigs, aggTypesStart } = deps; + + const getIndexPatternFromDatatableColumn = async (column: DatatableColumn) => { + if (!column.meta.index) return; + + return await getIndexPattern(column.meta.index); + }; + + const getAggConfigFromDatatableColumn = async (column: DatatableColumn) => { + const indexPattern = await getIndexPatternFromDatatableColumn(column); + + if (!indexPattern) return; + + const aggConfigs = await createAggConfigs(indexPattern, [column.meta.sourceParams as any]); + return aggConfigs.aggs[0]; + }; + + const isFilterableAggDatatableColumn = (column: DatatableColumn) => { + if (column.meta.source !== 'esaggs') { + return false; + } + const aggType = (aggTypesStart.get(column.meta.sourceParams?.type as string) as any)( + {} + ) as IAggType; + return Boolean(aggType.createFilter); + }; + + return { + getIndexPattern: getIndexPatternFromDatatableColumn, + getAggConfig: getAggConfigFromDatatableColumn, + isFilterable: isFilterableAggDatatableColumn, + }; +}; diff --git a/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts b/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts deleted file mode 100644 index 2db3694884e2c..0000000000000 --- a/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { set } from '@elastic/safer-lodash-set'; -import { - FormattedData, - TabularData, - TabularDataValue, -} from '../../../../../../plugins/inspector/common'; -import { Filter } from '../../../es_query'; -import { FormatFactory } from '../../../field_formats/utils'; -import { TabbedTable } from '../../tabify'; -import { createFilter } from './create_filter'; - -/** - * Type borrowed from the client-side FilterManager['addFilters']. - * - * We need to use a custom type to make this isomorphic since FilterManager - * doesn't exist on the server. - * - * @internal - */ -export type AddFilters = (filters: Filter[] | Filter, pinFilterStatus?: boolean) => void; - -/** - * This function builds tabular data from the response and attaches it to the - * inspector. It will only be called when the data view in the inspector is opened. - * - * @internal - */ -export async function buildTabularInspectorData( - table: TabbedTable, - { - addFilters, - deserializeFieldFormat, - }: { - addFilters?: AddFilters; - deserializeFieldFormat: FormatFactory; - } -): Promise { - const aggConfigs = table.columns.map((column) => column.aggConfig); - const rows = table.rows.map((row) => { - return table.columns.reduce>((prev, cur, colIndex) => { - const value = row[cur.id]; - - let format = cur.aggConfig.toSerializedFieldFormat(); - if (Object.keys(format).length < 1) { - // If no format exists, fall back to string as a default - format = { id: 'string' }; - } - const fieldFormatter = deserializeFieldFormat(format); - - prev[`col-${colIndex}-${cur.aggConfig.id}`] = new FormattedData( - value, - fieldFormatter.convert(value) - ); - return prev; - }, {}); - }); - - const columns = table.columns.map((col, colIndex) => { - const field = col.aggConfig.getField(); - const isCellContentFilterable = col.aggConfig.isFilterable() && (!field || field.filterable); - return { - name: col.name, - field: `col-${colIndex}-${col.aggConfig.id}`, - filter: - addFilters && - isCellContentFilterable && - ((value: TabularDataValue) => { - const rowIndex = rows.findIndex( - (row) => row[`col-${colIndex}-${col.aggConfig.id}`].raw === value.raw - ); - const filter = createFilter(aggConfigs, table, colIndex, rowIndex, value.raw); - - if (filter) { - addFilters(filter); - } - }), - filterOut: - addFilters && - isCellContentFilterable && - ((value: TabularDataValue) => { - const rowIndex = rows.findIndex( - (row) => row[`col-${colIndex}-${col.aggConfig.id}`].raw === value.raw - ); - const filter = createFilter(aggConfigs, table, colIndex, rowIndex, value.raw); - - if (filter) { - const notOther = value.raw !== '__other__'; - const notMissing = value.raw !== '__missing__'; - if (Array.isArray(filter)) { - filter.forEach((f) => set(f, 'meta.negate', notOther && notMissing)); - } else { - set(filter, 'meta.negate', notOther && notMissing); - } - addFilters(filter); - } - }), - }; - }); - - return { columns, rows }; -} diff --git a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts index 6c53a8a09274a..2274fcfd6b8d5 100644 --- a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts +++ b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts @@ -34,7 +34,6 @@ import { AggsStart, AggExpressionType } from '../../aggs'; import { ISearchStartSearchSource } from '../../search_source'; import { KibanaContext } from '../kibana_context_type'; -import { AddFilters } from './build_tabular_inspector_data'; import { handleRequest, RequestHandlerParams } from './request_handler'; const name = 'esaggs'; @@ -59,7 +58,6 @@ export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition< /** @internal */ export interface EsaggsStartDependencies { - addFilters?: AddFilters; aggs: AggsStart; deserializeFieldFormat: FormatFactory; indexPatterns: IndexPatternsContract; diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts index aba498f720ec1..9d0c63a8dc7aa 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts @@ -39,7 +39,6 @@ describe('esaggs expression function - public', () => { jest.clearAllMocks(); mockParams = { abortSignal: (jest.fn() as unknown) as jest.Mocked, - addFilters: jest.fn(), aggs: ({ aggs: [{ type: { name: 'terms', postFlightRequest: jest.fn().mockResolvedValue({}) } }], setTimeRange: jest.fn(), @@ -151,7 +150,8 @@ describe('esaggs expression function - public', () => { }); }); - test('calls agg.postFlightRequest if it exiests', async () => { + test('calls agg.postFlightRequest if it exiests and agg is enabled', async () => { + mockParams.aggs.aggs[0].enabled = true; await handleRequest(mockParams); expect(mockParams.aggs.aggs[0].type.postFlightRequest).toHaveBeenCalledTimes(1); @@ -161,6 +161,12 @@ describe('esaggs expression function - public', () => { expect(async () => await handleRequest(mockParams)).not.toThrowError(); }); + test('should skip agg.postFlightRequest call if the agg is disabled', async () => { + mockParams.aggs.aggs[0].enabled = false; + await handleRequest(mockParams); + expect(mockParams.aggs.aggs[0].type.postFlightRequest).toHaveBeenCalledTimes(0); + }); + test('tabifies response data', async () => { await handleRequest(mockParams); expect(tabifyAggResponse).toHaveBeenCalledWith( diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts index 3c1745409ebcd..b773aad67c3f8 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts @@ -36,13 +36,9 @@ import { ISearchStartSearchSource } from '../../search_source'; import { tabifyAggResponse } from '../../tabify'; import { getRequestInspectorStats, getResponseInspectorStats } from '../utils'; -import type { AddFilters } from './build_tabular_inspector_data'; -import { buildTabularInspectorData } from './build_tabular_inspector_data'; - /** @internal */ export interface RequestHandlerParams { abortSignal?: AbortSignal; - addFilters?: AddFilters; aggs: IAggConfigs; deserializeFieldFormat: FormatFactory; filters?: Filter[]; @@ -59,7 +55,6 @@ export interface RequestHandlerParams { export const handleRequest = async ({ abortSignal, - addFilters, aggs, deserializeFieldFormat, filters, @@ -175,7 +170,7 @@ export const handleRequest = async ({ // response data incorrectly in the inspector. let response = (searchSource as any).rawResponse; for (const agg of aggs.aggs) { - if (typeof agg.type.postFlightRequest === 'function') { + if (agg.enabled && typeof agg.type.postFlightRequest === 'function') { response = await agg.type.postFlightRequest( response, aggs, @@ -199,16 +194,5 @@ export const handleRequest = async ({ const tabifiedResponse = tabifyAggResponse(aggs, response, tabifyParams); - if (inspectorAdapters.data) { - inspectorAdapters.data.setTabularLoader( - () => - buildTabularInspectorData(tabifiedResponse, { - addFilters, - deserializeFieldFormat, - }), - { returnsFormattedValues: true } - ); - } - return tabifiedResponse; }; diff --git a/src/plugins/data/common/search/types.ts b/src/plugins/data/common/search/types.ts index 695ee34d3b468..34e411aa85c80 100644 --- a/src/plugins/data/common/search/types.ts +++ b/src/plugins/data/common/search/types.ts @@ -29,10 +29,22 @@ export type ISearchGeneric = < ) => Observable; export type ISearchCancelGeneric = (id: string, options?: ISearchOptions) => Promise; +export type ISearchExtendGeneric = ( + id: string, + keepAlive: string, + options?: ISearchOptions +) => Promise; export interface ISearchClient { search: ISearchGeneric; + /** + * Used to cancel an in-progress search request. + */ cancel: ISearchCancelGeneric; + /** + * Used to extend the TTL of an in-progress search request. + */ + extend: ISearchExtendGeneric; } export interface IKibanaSearchResponse { diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index 06b083e0ff3aa..a09ab12f0c6f0 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -7,7 +7,8 @@ "bfetch", "expressions", "uiActions", - "share" + "share", + "inspector" ], "optionalPlugins": ["usageCollection"], "extraPublicDirs": ["common"], diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index 944da72bd11d1..909d6e97c221c 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -19,10 +19,9 @@ import { i18n } from '@kbn/i18n'; import { toMountPoint } from '../../../kibana_react/public'; -import { ActionByType, createAction, IncompatibleActionError } from '../../../ui_actions/public'; +import { Action, createAction, IncompatibleActionError } from '../../../ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; -import type { IEmbeddable } from '../../../embeddable/public'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; @@ -30,7 +29,9 @@ export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; export interface ApplyGlobalFilterActionContext { filters: Filter[]; timeFieldName?: string; - embeddable?: IEmbeddable; + // Need to make this unknown to prevent circular dependencies. + // Apps using this property will need to cast to `IEmbeddable`. + embeddable?: unknown; } async function isCompatible(context: ApplyGlobalFilterActionContext) { @@ -40,8 +41,8 @@ async function isCompatible(context: ApplyGlobalFilterActionContext) { export function createFilterAction( filterManager: FilterManager, timeFilter: TimefilterContract -): ActionByType { - return createAction({ +): Action { + return createAction({ type: ACTION_GLOBAL_APPLY_FILTER, id: ACTION_GLOBAL_APPLY_FILTER, order: 100, diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index 6dcfa4d02bcb2..9830bf5b7ba83 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -29,12 +29,16 @@ import { } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns, setSearchService } from '../../../public/services'; -import { TriggerContextMapping } from '../../../../ui_actions/public'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; - let baseEvent: TriggerContextMapping['SELECT_RANGE_TRIGGER']['data']; + let baseEvent: { + table: any; + column: number; + range: number[]; + timeFieldName?: string; + }; const mockField = { name: 'time', diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts index 2d7aeff79a689..2b0911b72abd5 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts @@ -19,12 +19,20 @@ import { last } from 'lodash'; import moment from 'moment'; +import { Datatable } from 'src/plugins/expressions'; import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns, getSearchService } from '../../../public/services'; -import { RangeSelectContext } from '../../../../embeddable/public'; import { AggConfigSerialized } from '../../../common/search/aggs'; -export async function createFiltersFromRangeSelectAction(event: RangeSelectContext['data']) { +/** @internal */ +export interface RangeSelectDataContext { + table: Datatable; + column: number; + range: number[]; + timeFieldName?: string; +} + +export async function createFiltersFromRangeSelectAction(event: RangeSelectDataContext) { const column: Record = event.table.columns[event.column]; if (!column || !column.meta) { diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts index 23d2ab080d75e..04801a5ee1cea 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts @@ -25,8 +25,10 @@ import { } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns, setSearchService } from '../../../public/services'; -import { createFiltersFromValueClickAction } from './create_filters_from_value_click'; -import { ValueClickContext } from '../../../../embeddable/public'; +import { + createFiltersFromValueClickAction, + ValueClickDataContext, +} from './create_filters_from_value_click'; const mockField = { name: 'bytes', @@ -34,7 +36,7 @@ const mockField = { }; describe('createFiltersFromValueClick', () => { - let dataPoints: ValueClickContext['data']['data']; + let dataPoints: ValueClickDataContext['data']; beforeEach(() => { dataPoints = [ diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index ce7ecf434056a..30fef7e3a7c66 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -20,9 +20,20 @@ import { Datatable } from '../../../../../plugins/expressions/public'; import { esFilters, Filter } from '../../../public'; import { getIndexPatterns, getSearchService } from '../../../public/services'; -import { ValueClickContext } from '../../../../embeddable/public'; import { AggConfigSerialized } from '../../../common/search/aggs'; +/** @internal */ +export interface ValueClickDataContext { + data: Array<{ + table: Pick; + column: number; + row: number; + value: any; + }>; + timeFieldName?: string; + negate?: boolean; +} + /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter * terms based on a specific cell in the tabified data. @@ -120,7 +131,7 @@ const createFilter = async ( export const createFiltersFromValueClickAction = async ({ data, negate, -}: ValueClickContext['data']) => { +}: ValueClickDataContext) => { const filters: Filter[] = []; await Promise.all( diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 1781da980dc30..c6d234665c05e 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -17,23 +17,29 @@ * under the License. */ -import { - ActionByType, - APPLY_FILTER_TRIGGER, - createAction, - UiActionsStart, -} from '../../../../plugins/ui_actions/public'; +import { Datatable } from 'src/plugins/expressions/public'; +import { Action, createAction, UiActionsStart } from '../../../../plugins/ui_actions/public'; +import { APPLY_FILTER_TRIGGER } from '../triggers'; import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; -import type { RangeSelectContext } from '../../../embeddable/public'; -export type SelectRangeActionContext = RangeSelectContext; +export interface SelectRangeActionContext { + // Need to make this unknown to prevent circular dependencies. + // Apps using this property will need to cast to `IEmbeddable`. + embeddable?: unknown; + data: { + table: Datatable; + column: number; + range: number[]; + timeFieldName?: string; + }; +} export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; export function createSelectRangeAction( getStartServices: () => { uiActions: UiActionsStart } -): ActionByType { - return createAction({ +): Action { + return createAction({ type: ACTION_SELECT_RANGE, id: ACTION_SELECT_RANGE, shouldAutoExecute: async () => true, diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 81e62380eacfb..41c2943a6a5bb 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -17,23 +17,35 @@ * under the License. */ -import { - ActionByType, - APPLY_FILTER_TRIGGER, - createAction, - UiActionsStart, -} from '../../../../plugins/ui_actions/public'; +import { Datatable } from 'src/plugins/expressions/public'; +import { Action, createAction, UiActionsStart } from '../../../../plugins/ui_actions/public'; +import { APPLY_FILTER_TRIGGER } from '../triggers'; import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; import type { Filter } from '../../common/es_query/filters'; -import type { ValueClickContext } from '../../../embeddable/public'; export type ValueClickActionContext = ValueClickContext; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; +export interface ValueClickContext { + // Need to make this unknown to prevent circular dependencies. + // Apps using this property will need to cast to `IEmbeddable`. + embeddable?: unknown; + data: { + data: Array<{ + table: Pick; + column: number; + row: number; + value: any; + }>; + timeFieldName?: string; + negate?: boolean; + }; +} + export function createValueClickAction( getStartServices: () => { uiActions: UiActionsStart } -): ActionByType { - return createAction({ +): Action { + return createAction({ type: ACTION_VALUE_CLICK, id: ACTION_VALUE_CLICK, shouldAutoExecute: async () => true, diff --git a/src/plugins/data/public/index.scss b/src/plugins/data/public/index.scss index a51fde079f10b..467efa98934ec 100644 --- a/src/plugins/data/public/index.scss +++ b/src/plugins/data/public/index.scss @@ -1 +1,2 @@ @import './ui/index'; +@import './utils/table_inspector_view/index'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 3dda04d738c96..7b15e2576e704 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -483,6 +483,7 @@ export { export { isTimeRange, isQuery, isFilter, isFilters } from '../common'; export { ACTION_GLOBAL_APPLY_FILTER, ApplyGlobalFilterActionContext } from './actions'; +export { APPLY_FILTER_TRIGGER } from './triggers'; /* * Plugin setup diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts index ca0f35d6612b2..36a193a4f6f94 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts @@ -64,12 +64,13 @@ export class IndexPatternsApiClient implements IIndexPatternsApiClient { }).then((resp: any) => resp.fields); } - getFieldsForWildcard({ pattern, metaFields, type, rollupIndex }: GetFieldsOptions) { + getFieldsForWildcard({ pattern, metaFields, type, rollupIndex, allowNoIndex }: GetFieldsOptions) { return this._request(this._getUrl(['_fields_for_wildcard']), { pattern, meta_fields: metaFields, type, rollup_index: rollupIndex, - }).then((resp: any) => resp.fields); + allow_no_index: allowNoIndex, + }).then((resp: any) => resp.fields || []); } } diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 458024151c585..43abe84950fdb 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -48,36 +48,19 @@ import { setUiSettings, } from './services'; import { createSearchBar } from './ui/search_bar/create_search_bar'; -import { - SELECT_RANGE_TRIGGER, - VALUE_CLICK_TRIGGER, - APPLY_FILTER_TRIGGER, -} from '../../ui_actions/public'; import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromValueClickAction, createFiltersFromRangeSelectAction, - ApplyGlobalFilterActionContext, - ACTION_SELECT_RANGE, - ACTION_VALUE_CLICK, - SelectRangeActionContext, - ValueClickActionContext, createValueClickAction, createSelectRangeAction, } from './actions'; - +import { APPLY_FILTER_TRIGGER, applyFilterTrigger } from './triggers'; import { SavedObjectsClientPublicToCommon } from './index_patterns'; import { getIndexPatternLoad } from './index_patterns/expressions'; import { UsageCollectionSetup } from '../../usage_collection/public'; - -declare module '../../ui_actions/public' { - export interface ActionContextMapping { - [ACTION_GLOBAL_APPLY_FILTER]: ApplyGlobalFilterActionContext; - [ACTION_SELECT_RANGE]: SelectRangeActionContext; - [ACTION_VALUE_CLICK]: ValueClickActionContext; - } -} +import { getTableViewDescription } from './utils/table_inspector_view'; export class DataPublicPlugin implements @@ -104,7 +87,7 @@ export class DataPublicPlugin public setup( core: CoreSetup, - { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies + { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies ): DataPublicPluginSetup { const startServices = createStartServicesGetter(core.getStartServices); @@ -117,19 +100,21 @@ export class DataPublicPlugin storage: this.storage, }); + uiActions.registerTrigger(applyFilterTrigger); + uiActions.registerAction( createFilterAction(queryService.filterManager, queryService.timefilter.timefilter) ); uiActions.addTriggerAction( - SELECT_RANGE_TRIGGER, + 'SELECT_RANGE_TRIGGER', createSelectRangeAction(() => ({ uiActions: startServices().plugins.uiActions, })) ); uiActions.addTriggerAction( - VALUE_CLICK_TRIGGER, + 'VALUE_CLICK_TRIGGER', createValueClickAction(() => ({ uiActions: startServices().plugins.uiActions, })) @@ -141,6 +126,15 @@ export class DataPublicPlugin expressions, }); + inspector.registerView( + getTableViewDescription(() => ({ + uiActions: startServices().plugins.uiActions, + uiSettings: startServices().core.uiSettings, + fieldFormats: startServices().self.fieldFormats, + isFilterable: startServices().self.search.aggs.datatableUtilities.isFilterable, + })) + ); + return { autocomplete: this.autocomplete.setup(core, { timefilter: queryService.timefilter }), search: searchService, diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 373aa4dee53fd..3493844a71ac1 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -20,6 +20,7 @@ import { CoreSetup } from 'src/core/public'; import { CoreSetup as CoreSetup_2 } from 'kibana/public'; import { CoreStart } from 'kibana/public'; import { CoreStart as CoreStart_2 } from 'src/core/public'; +import * as CSS from 'csstype'; import { Datatable as Datatable_2 } from 'src/plugins/expressions'; import { Datatable as Datatable_3 } from 'src/plugins/expressions/common'; import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions'; @@ -66,11 +67,12 @@ import { Plugin as Plugin_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_3 } from 'kibana/public'; import { PopoverAnchorPosition } from '@elastic/eui'; +import * as PropTypes from 'prop-types'; import { PublicContract } from '@kbn/utility-types'; import { PublicMethodsOf } from '@kbn/utility-types'; import { PublicUiSettingsParams } from 'src/core/server/types'; import React from 'react'; -import * as React_2 from 'react'; +import * as React_3 from 'react'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Reporter } from '@kbn/analytics'; import { RequestAdapter } from 'src/plugins/inspector/common'; @@ -462,14 +464,17 @@ export type AggsStart = Assign; +// Warning: (ae-missing-release-tag) "APPLY_FILTER_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const APPLY_FILTER_TRIGGER = "FILTER_TRIGGER"; + // Warning: (ae-missing-release-tag) "ApplyGlobalFilterActionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface ApplyGlobalFilterActionContext { - // Warning: (ae-forgotten-export) The symbol "IEmbeddable" needs to be exported by the entry point index.d.ts - // // (undocumented) - embeddable?: IEmbeddable; + embeddable?: unknown; // (undocumented) filters: Filter[]; // (undocumented) @@ -1251,6 +1256,7 @@ export class IndexPattern implements IIndexPattern { // Warning: (ae-forgotten-export) The symbol "IndexPatternDeps" needs to be exported by the entry point index.d.ts constructor({ spec, fieldFormats, shortDotsEnable, metaFields, }: IndexPatternDeps); addScriptedField(name: string, script: string, fieldType?: string): Promise; + readonly allowNoIndex: boolean; // (undocumented) readonly deleteFieldFormat: (fieldName: string) => void; // Warning: (ae-forgotten-export) The symbol "FieldAttrs" needs to be exported by the entry point index.d.ts @@ -1291,6 +1297,7 @@ export class IndexPattern implements IIndexPattern { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }; // (undocumented) getComputedFields(): { @@ -1383,6 +1390,7 @@ export type IndexPatternAggRestrictions = Record, 'isLo // // @public (undocumented) export interface IndexPatternSpec { + // (undocumented) + allowNoIndex?: boolean; // (undocumented) fieldAttrs?: FieldAttrs; // (undocumented) @@ -1888,7 +1898,7 @@ export class Plugin implements Plugin_2); // (undocumented) - setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; + setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies): DataPublicPluginSetup; // (undocumented) start(core: CoreStart_2, { uiActions }: DataStartDependencies): DataPublicPluginStart; // (undocumented) @@ -2559,8 +2569,8 @@ export const UI_SETTINGS: { // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:64:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts -// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:128:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts -// src/plugins/data/common/search/aggs/types.ts:145:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts +// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:133:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts +// src/plugins/data/common/search/aggs/types.ts:150:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts // src/plugins/data/common/search/search_source/search_source.ts:197:7 - (ae-forgotten-export) The symbol "SearchFieldValue" needs to be exported by the entry point index.d.ts // src/plugins/data/public/field_formats/field_formats_service.ts:67:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts index de747d234b441..bc4992384b0c2 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts @@ -88,11 +88,12 @@ describe('AggsService - public', () => { describe('start()', () => { test('exposes proper contract', () => { const start = service.start(startDeps); - expect(Object.keys(start).length).toBe(4); + expect(Object.keys(start).length).toBe(5); expect(start).toHaveProperty('calculateAutoTimeExpression'); expect(start).toHaveProperty('getDateMetaByDatatableColumn'); expect(start).toHaveProperty('createAggConfigs'); expect(start).toHaveProperty('types'); + expect(start).toHaveProperty('datatableUtilities'); }); test('types registry returns initialized agg types', () => { diff --git a/src/plugins/data/public/search/aggs/aggs_service.ts b/src/plugins/data/public/search/aggs/aggs_service.ts index 85e0f604bb8b5..7b5edac0280d9 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.ts @@ -102,6 +102,7 @@ export class AggsService { const { calculateAutoTimeExpression, getDateMetaByDatatableColumn, + datatableUtilities, types, } = this.aggsCommonService.start({ getConfig: this.getConfig!, @@ -148,7 +149,8 @@ export class AggsService { return { calculateAutoTimeExpression, getDateMetaByDatatableColumn, - createAggConfigs: (indexPattern, configStates = [], schemas) => { + datatableUtilities, + createAggConfigs: (indexPattern, configStates = []) => { return new AggConfigs(indexPattern, configStates, { typesRegistry }); }, types: typesRegistry, diff --git a/src/plugins/data/public/search/aggs/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts index abc930f00b594..bc02b48d67f7b 100644 --- a/src/plugins/data/public/search/aggs/mocks.ts +++ b/src/plugins/data/public/search/aggs/mocks.ts @@ -68,6 +68,11 @@ export const searchAggsSetupMock = (): AggsSetup => ({ export const searchAggsStartMock = (): AggsStart => ({ calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), getDateMetaByDatatableColumn: jest.fn(), + datatableUtilities: { + isFilterable: jest.fn(), + getAggConfig: jest.fn(), + getIndexPattern: jest.fn(), + }, createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), diff --git a/src/plugins/data/public/search/expressions/esaggs.test.ts b/src/plugins/data/public/search/expressions/esaggs.test.ts index 10ed22c861188..abb95ed05b12e 100644 --- a/src/plugins/data/public/search/expressions/esaggs.test.ts +++ b/src/plugins/data/public/search/expressions/esaggs.test.ts @@ -72,7 +72,6 @@ describe('esaggs expression function - public', () => { types: {}, }; startDependencies = { - addFilters: jest.fn(), aggs: ({ createAggConfigs: jest.fn().mockReturnValue({ foo: 'bar' }), } as unknown) as jest.Mocked, @@ -113,7 +112,6 @@ describe('esaggs expression function - public', () => { expect(handleEsaggsRequest).toHaveBeenCalledWith(null, args, { abortSignal: mockHandlers.abortSignal, - addFilters: startDependencies.addFilters, aggs: { foo: 'bar' }, deserializeFieldFormat: startDependencies.deserializeFieldFormat, filters: undefined, diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index 4a078bf9b2e55..d8d90ea464a73 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -49,7 +49,6 @@ export function getFunctionDefinition({ ...getEsaggsMeta(), async fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId }) { const { - addFilters, aggs, deserializeFieldFormat, indexPatterns, @@ -64,7 +63,6 @@ export function getFunctionDefinition({ return await handleEsaggsRequest(input, args, { abortSignal: (abortSignal as unknown) as AbortSignal, - addFilters, aggs: aggConfigs, deserializeFieldFormat, filters: get(input, 'filters', undefined), @@ -104,9 +102,8 @@ export function getEsaggs({ return getFunctionDefinition({ getStartDependencies: async () => { const [, , self] = await getStartServices(); - const { fieldFormats, indexPatterns, query, search } = self; + const { fieldFormats, indexPatterns, search } = self; return { - addFilters: query.filterManager.addFilters.bind(query.filterManager), aggs: search.aggs, deserializeFieldFormat: fieldFormats.deserialize.bind(fieldFormats), indexPatterns, diff --git a/src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts b/src/plugins/data/public/triggers/apply_filter_trigger.ts similarity index 81% rename from src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts rename to src/plugins/data/public/triggers/apply_filter_trigger.ts index aa54706476a8f..07422eb313ae3 100644 --- a/src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts +++ b/src/plugins/data/public/triggers/apply_filter_trigger.ts @@ -18,15 +18,15 @@ */ import { i18n } from '@kbn/i18n'; -import { Trigger } from '.'; +import { Trigger } from '../../../ui_actions/public'; export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; -export const applyFilterTrigger: Trigger<'FILTER_TRIGGER'> = { +export const applyFilterTrigger: Trigger = { id: APPLY_FILTER_TRIGGER, - title: i18n.translate('uiActions.triggers.applyFilterTitle', { + title: i18n.translate('data.triggers.applyFilterTitle', { defaultMessage: 'Apply filter', }), - description: i18n.translate('uiActions.triggers.applyFilterDescription', { + description: i18n.translate('data.triggers.applyFilterDescription', { defaultMessage: 'When kibana filter is applied. Could be a single value or a range filter.', }), }; diff --git a/src/plugins/inspector/common/adapters/data/index.ts b/src/plugins/data/public/triggers/index.ts similarity index 89% rename from src/plugins/inspector/common/adapters/data/index.ts rename to src/plugins/data/public/triggers/index.ts index a8b1abcd8cd7e..36a38ae76bc0e 100644 --- a/src/plugins/inspector/common/adapters/data/index.ts +++ b/src/plugins/data/public/triggers/index.ts @@ -17,6 +17,4 @@ * under the License. */ -export * from './data_adapter'; -export * from './formatted_data'; -export * from './types'; +export * from './apply_filter_trigger'; diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 4082fbe55094c..c7b66acfc6c7a 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -31,6 +31,7 @@ import { QuerySetup, QueryStart } from './query'; import { IndexPatternsContract } from './index_patterns'; import { IndexPatternSelectProps, StatefulSearchBarProps } from './ui'; import { UsageCollectionSetup } from '../../usage_collection/public'; +import { Setup as InspectorSetup } from '../../inspector/public'; export interface DataPublicPluginEnhancements { search: SearchEnhancements; @@ -40,6 +41,7 @@ export interface DataSetupDependencies { bfetch: BfetchPublicSetup; expressions: ExpressionsSetup; uiActions: UiActionsSetup; + inspector: InspectorSetup; usageCollection?: UsageCollectionSetup; } diff --git a/src/plugins/data/public/ui/filter_bar/filter_item.tsx b/src/plugins/data/public/ui/filter_bar/filter_item.tsx index 5e6fd5323c0b7..7b65805a482dd 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_item.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_item.tsx @@ -71,19 +71,27 @@ export function FilterItem(props: Props) { useEffect(() => { const index = props.filter.meta.index; + let isSubscribed = true; if (index) { getIndexPatterns() .get(index) .then((indexPattern) => { - setIndexPatternExists(!!indexPattern); + if (isSubscribed) { + setIndexPatternExists(!!indexPattern); + } }) .catch(() => { - setIndexPatternExists(false); + if (isSubscribed) { + setIndexPatternExists(false); + } }); - } else { + } else if (isSubscribed) { // Allow filters without an index pattern and don't validate them. setIndexPatternExists(true); } + return () => { + isSubscribed = false; + }; }, [props.filter.meta.index]); function handleBadgeClick(e: MouseEvent) { diff --git a/src/plugins/inspector/public/views/data/_data_table.scss b/src/plugins/data/public/utils/table_inspector_view/_data_table.scss similarity index 100% rename from src/plugins/inspector/public/views/data/_data_table.scss rename to src/plugins/data/public/utils/table_inspector_view/_data_table.scss diff --git a/src/plugins/inspector/public/views/data/_index.scss b/src/plugins/data/public/utils/table_inspector_view/_index.scss similarity index 100% rename from src/plugins/inspector/public/views/data/_index.scss rename to src/plugins/data/public/utils/table_inspector_view/_index.scss diff --git a/src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap similarity index 68% rename from src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap rename to src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap index ec68b307734e3..4320fc186783b 100644 --- a/src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap +++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap @@ -1,17 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Inspector Data View component should render empty state 1`] = ` -

@@ -272,7 +159,7 @@ exports[`Inspector Data View component should render empty state 1`] = `

@@ -295,7 +182,7 @@ exports[`Inspector Data View component should render empty state 1`] = ` > No data available @@ -316,7 +203,7 @@ exports[`Inspector Data View component should render empty state 1`] = `

The element did not provide any data. @@ -329,7 +216,7 @@ exports[`Inspector Data View component should render empty state 1`] = `

- + `; exports[`Inspector Data View component should render loading state 1`] = ` @@ -442,6 +329,20 @@ exports[`Inspector Data View component should render loading state 1`] = ` } } > +
loading
diff --git a/src/plugins/inspector/public/views/data/components/data_table.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx similarity index 57% rename from src/plugins/inspector/public/views/data/components/data_table.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx index 69be069272f79..f4d1a8988da78 100644 --- a/src/plugins/inspector/public/views/data/components/data_table.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx @@ -35,8 +35,10 @@ import { i18n } from '@kbn/i18n'; import { DataDownloadOptions } from './download_options'; import { DataViewRow, DataViewColumn } from '../types'; -import { TabularData } from '../../../../common/adapters/data/types'; import { IUiSettingsClient } from '../../../../../../core/public'; +import { Datatable, DatatableColumn } from '../../../../../expressions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { UiActionsStart } from '../../../../../ui_actions/public'; interface DataTableFormatState { columns: DataViewColumn[]; @@ -44,10 +46,21 @@ interface DataTableFormatState { } interface DataTableFormatProps { - data: TabularData; + data: Datatable; exportTitle: string; uiSettings: IUiSettingsClient; - isFormatted?: boolean; + fieldFormats: FieldFormatsStart; + uiActions: UiActionsStart; + isFilterable: (column: DatatableColumn) => boolean; +} + +interface RenderCellArguments { + table: Datatable; + columnIndex: number; + rowIndex: number; + formattedValue: string; + uiActions: UiActionsStart; + isFilterable: boolean; } export class DataTableFormat extends Component { @@ -55,25 +68,35 @@ export class DataTableFormat extends Component - {isFormatted ? value.formatted : value} + {formattedValue} - {dataColumn.filter && ( + {isFilterable && ( } @@ -81,23 +104,29 @@ export class DataTableFormat extends Component dataColumn.filter(value)} + onClick={() => { + const value = table.rows[rowIndex][column.id]; + const eventData = { table, column: columnIndex, row: rowIndex, value }; + uiActions.executeTriggerActions('VALUE_CLICK_TRIGGER', { + data: { data: [eventData] }, + }); + }} /> )} - {dataColumn.filterOut && ( + {isFilterable && ( } @@ -105,12 +134,21 @@ export class DataTableFormat extends Component dataColumn.filterOut(value)} + onClick={() => { + const value = table.rows[rowIndex][column.id]; + const eventData = { table, column: columnIndex, row: rowIndex, value }; + uiActions.executeTriggerActions('VALUE_CLICK_TRIGGER', { + data: { data: [eventData], negate: true }, + }); + }} /> @@ -121,7 +159,12 @@ export class DataTableFormat extends Component ({ - name: dataColumn.name, - field: dataColumn.field, - sortable: isFormatted ? (row: DataViewRow) => row[dataColumn.field].raw : true, - render: (value: any) => DataTableFormat.renderCell(dataColumn, value, isFormatted), - })); + const columns = data.columns.map((dataColumn: any, index: number) => { + const formatParams = { id: 'string', ...dataColumn.meta.params }; + const fieldFormatter = fieldFormats.deserialize(formatParams); + const filterable = isFilterable(dataColumn); + return { + originalColumn: () => dataColumn, + name: dataColumn.name, + field: dataColumn.id, + sortable: true, + render: (value: any) => { + const formattedValue = fieldFormatter.convert(value); + const rowIndex = data.rows.findIndex((row) => row[dataColumn.id] === value) || 0; + + return DataTableFormat.renderCell({ + table: data, + columnIndex: index, + rowIndex, + formattedValue, + uiActions, + isFilterable: filterable, + }); + }, + }; + }); return { columns, rows: data.rows }; } @@ -152,12 +213,12 @@ export class DataTableFormat extends Component diff --git a/src/plugins/inspector/public/views/data/components/data_view.test.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx similarity index 77% rename from src/plugins/inspector/public/views/data/components/data_view.test.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx index 82bec5ee3fe8c..975a91548d799 100644 --- a/src/plugins/inspector/public/views/data/components/data_view.test.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx @@ -18,11 +18,11 @@ */ import React, { Suspense } from 'react'; -import { getDataViewDescription } from '../index'; -import { DataAdapter } from '../../../../common/adapters/data'; +import { getTableViewDescription } from '../index'; import { mountWithIntl } from '@kbn/test/jest'; +import { TablesAdapter } from '../../../../../expressions/common'; -jest.mock('../lib/export_csv', () => ({ +jest.mock('./export_csv', () => ({ exportAsCsv: jest.fn(), })); @@ -30,13 +30,18 @@ describe('Inspector Data View', () => { let DataView: any; beforeEach(() => { - DataView = getDataViewDescription(); + DataView = getTableViewDescription(() => ({ + uiActions: {} as any, + uiSettings: {} as any, + fieldFormats: {} as any, + isFilterable: jest.fn(), + })); }); it('should only show if data adapter is present', () => { - const adapter = new DataAdapter(); + const adapter = new TablesAdapter(); - expect(DataView.shouldShow({ data: adapter })).toBe(true); + expect(DataView.shouldShow({ tables: adapter })).toBe(true); expect(DataView.shouldShow({})).toBe(false); }); @@ -44,7 +49,7 @@ describe('Inspector Data View', () => { let adapters: any; beforeEach(() => { - adapters = { data: new DataAdapter() }; + adapters = { tables: new TablesAdapter() }; }); it('should render loading state', () => { @@ -60,9 +65,7 @@ describe('Inspector Data View', () => { it('should render empty state', async () => { const component = mountWithIntl(); // eslint-disable-line react/jsx-pascal-case - const tabularLoader = Promise.resolve(null); - adapters.data.setTabularLoader(() => tabularLoader); - await tabularLoader; + adapters.tables.logDatatable({ columns: [{ id: '1' }], rows: [{ '1': 123 }] }); // After the loader has resolved we'll still need one update, to "flush" the state changes component.update(); expect(component).toMatchSnapshot(); diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx new file mode 100644 index 0000000000000..97dca45d742c9 --- /dev/null +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx @@ -0,0 +1,137 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { DataTableFormat } from './data_table'; +import { IUiSettingsClient } from '../../../../../../core/public'; +import { InspectorViewProps, Adapters } from '../../../../../inspector/public'; +import { UiActionsStart } from '../../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { TablesAdapter, Datatable, DatatableColumn } from '../../../../../expressions/public'; + +interface DataViewComponentState { + datatable: Datatable; + adapters: Adapters; +} + +interface DataViewComponentProps extends InspectorViewProps { + uiSettings: IUiSettingsClient; + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + isFilterable: (column: DatatableColumn) => boolean; +} + +class DataViewComponent extends Component { + static propTypes = { + adapters: PropTypes.object.isRequired, + title: PropTypes.string.isRequired, + uiSettings: PropTypes.object, + uiActions: PropTypes.object.isRequired, + fieldFormats: PropTypes.object.isRequired, + isFilterable: PropTypes.func.isRequired, + }; + + state = {} as DataViewComponentState; + + static getDerivedStateFromProps( + nextProps: Readonly, + state: DataViewComponentState + ) { + if (state && nextProps.adapters === state.adapters) { + return null; + } + + const { tables } = nextProps.adapters.tables; + const keys = Object.keys(tables); + const datatable = keys.length ? tables[keys[0]] : undefined; + + return { + adapters: nextProps.adapters, + datatable, + }; + } + + onUpdateData = (tables: TablesAdapter['tables']) => { + const keys = Object.keys(tables); + const datatable = keys.length ? tables[keys[0]] : undefined; + + if (datatable) { + this.setState({ + datatable, + }); + } + }; + + componentDidMount() { + this.props.adapters.tables!.on('change', this.onUpdateData); + } + + componentWillUnmount() { + this.props.adapters.tables!.removeListener('change', this.onUpdateData); + } + + static renderNoData() { + return ( + + + + } + body={ + +

+ +

+
+ } + /> + ); + } + + render() { + if (!this.state.datatable) { + return DataViewComponent.renderNoData(); + } + + return ( + + ); + } +} + +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export default DataViewComponent; diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx new file mode 100644 index 0000000000000..d8b96da36628c --- /dev/null +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { lazy } from 'react'; +import { IUiSettingsClient } from 'kibana/public'; +import { UiActionsStart } from '../../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { DatatableColumn } from '../../../../../expressions/common/expression_types/specs'; + +const DataViewComponent = lazy(() => import('./data_view')); + +export const getDataViewComponentWrapper = ( + getStartServices: () => { + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + uiSettings: IUiSettingsClient; + isFilterable: (column: DatatableColumn) => boolean; + } +) => { + return (props: any) => { + return ( + + ); + }; +}; diff --git a/src/plugins/inspector/public/views/data/components/download_options.tsx b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx similarity index 77% rename from src/plugins/inspector/public/views/data/components/download_options.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx index cedb723091638..f849f598e9c69 100644 --- a/src/plugins/inspector/public/views/data/components/download_options.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx @@ -24,8 +24,8 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { DataViewColumn, DataViewRow } from '../types'; - -import { exportAsCsv } from '../lib/export_csv'; +import { exportAsCsv } from './export_csv'; +import { FieldFormatsStart } from '../../../field_formats'; interface DataDownloadOptionsState { isPopoverOpen: boolean; @@ -38,6 +38,7 @@ interface DataDownloadOptionsProps { csvSeparator: string; quoteValues: boolean; isFormatted?: boolean; + fieldFormats: FieldFormatsStart; } class DataDownloadOptions extends Component { @@ -45,9 +46,9 @@ class DataDownloadOptions extends Component { + exportCsv = (isFormatted: boolean = true) => { let filename = this.props.title; if (!filename || filename.length === 0) { - filename = i18n.translate('inspector.data.downloadOptionsUnsavedFilename', { + filename = i18n.translate('data.inspector.table.downloadOptionsUnsavedFilename', { defaultMessage: 'unsaved', }); } @@ -79,38 +80,24 @@ class DataDownloadOptions extends Component { - this.exportCsv({ - valueFormatter: (item: any) => item.formatted, - }); + this.exportCsv(true); }; exportFormattedAsRawCsv = () => { - this.exportCsv({ - valueFormatter: (item: any) => item.raw, - }); + this.exportCsv(false); }; - renderUnformattedDownload() { - return ( - - - - ); - } - renderFormattedDownloads() { const button = ( @@ -121,14 +108,14 @@ class DataDownloadOptions extends Component } toolTipPosition="left" > , @@ -137,13 +124,13 @@ class DataDownloadOptions extends Component } toolTipPosition="left" > - + , ]; @@ -162,9 +149,7 @@ class DataDownloadOptions extends Component escape(col.name, quoteValues)); + const formatters = columns.map((column) => { + return fieldFormats.deserialize(column.originalColumn().meta.params); + }); + // Convert the array of row objects to an array of row arrays - const orderedFieldNames = columns.map((col) => col.field); const csvRows = rows.map((row) => { - return orderedFieldNames.map((field) => - escape(valueFormatter ? valueFormatter(row[field]) : row[field], quoteValues) - ); + return columns.map((column, i) => { + return escape( + isFormatted ? formatters[i].convert(row[column.field]) : row[column.field], + quoteValues + ); + }); }); return ( @@ -69,14 +77,18 @@ export function exportAsCsv({ filename, columns, rows, - valueFormatter, + isFormatted, csvSeparator, quoteValues, + fieldFormats, }: any) { const type = 'text/plain;charset=utf-8'; - const csv = new Blob([buildCsv(columns, rows, csvSeparator, quoteValues, valueFormatter)], { - type, - }); + const csv = new Blob( + [buildCsv(columns, rows, csvSeparator, quoteValues, isFormatted, fieldFormats)], + { + type, + } + ); saveAs(csv, filename); } diff --git a/src/plugins/data/public/utils/table_inspector_view/index.ts b/src/plugins/data/public/utils/table_inspector_view/index.ts new file mode 100644 index 0000000000000..3769298af05f3 --- /dev/null +++ b/src/plugins/data/public/utils/table_inspector_view/index.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { IUiSettingsClient } from 'kibana/public'; +import { Adapters, InspectorViewDescription } from '../../../../inspector/public'; +import { getDataViewComponentWrapper } from './components/data_view_wrapper'; +import { UiActionsStart } from '../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../field_formats'; +import { DatatableColumn } from '../../../../expressions/common/expression_types/specs'; + +export const getTableViewDescription = ( + getStartServices: () => { + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + isFilterable: (column: DatatableColumn) => boolean; + uiSettings: IUiSettingsClient; + } +): InspectorViewDescription => ({ + title: i18n.translate('data.inspector.table.dataTitle', { + defaultMessage: 'Data', + }), + order: 10, + help: i18n.translate('data.inspector.table..dataDescriptionTooltip', { + defaultMessage: 'View the data behind the visualization', + }), + shouldShow(adapters: Adapters) { + return Boolean(adapters.tables); + }, + component: getDataViewComponentWrapper(getStartServices), +}); diff --git a/src/plugins/inspector/public/views/data/types.ts b/src/plugins/data/public/utils/table_inspector_view/types.ts similarity index 70% rename from src/plugins/inspector/public/views/data/types.ts rename to src/plugins/data/public/utils/table_inspector_view/types.ts index 31de9eb3a152e..dc85c3c2e3135 100644 --- a/src/plugins/inspector/public/views/data/types.ts +++ b/src/plugins/data/public/utils/table_inspector_view/types.ts @@ -17,15 +17,20 @@ * under the License. */ -import { TabularDataRow } from '../../../common/adapters'; +import { Datatable, DatatableColumn, DatatableRow } from '../../../../expressions/common'; -type DataViewColumnRender = (value: string, _item: TabularDataRow) => string; +type DataViewColumnRender = (value: string, _item: DatatableRow) => string; export interface DataViewColumn { + originalColumn: () => DatatableColumn; name: string; field: string; - sortable: (item: TabularDataRow) => string | number; + sortable: (item: DatatableRow) => string | number; render: DataViewColumnRender; } -export type DataViewRow = TabularDataRow; +export type DataViewRow = DatatableRow; + +export interface TableInspectorAdapter { + [key: string]: Datatable; +} diff --git a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts index 21a3bf6e73e61..9023044184df3 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts @@ -30,8 +30,14 @@ export class IndexPatternsApiServer implements IIndexPatternsApiClient { constructor(elasticsearchClient: ElasticsearchClient) { this.esClient = elasticsearchClient; } - async getFieldsForWildcard({ pattern, metaFields, type, rollupIndex }: GetFieldsOptions) { - const indexPatterns = new IndexPatternsFetcher(this.esClient); + async getFieldsForWildcard({ + pattern, + metaFields, + type, + rollupIndex, + allowNoIndex, + }: GetFieldsOptions) { + const indexPatterns = new IndexPatternsFetcher(this.esClient, allowNoIndex); return await indexPatterns.getFieldsForWildcard({ pattern, metaFields, diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index e9dbc2e972c68..f0b51e456337f 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -75,13 +75,20 @@ export function registerRoutes( }), type: schema.maybe(schema.string()), rollup_index: schema.maybe(schema.string()), + allow_no_index: schema.maybe(schema.boolean()), }), }, }, async (context, request, response) => { const { asCurrentUser } = context.core.elasticsearch.client; const indexPatterns = new IndexPatternsFetcher(asCurrentUser); - const { pattern, meta_fields: metaFields, type, rollup_index: rollupIndex } = request.query; + const { + pattern, + meta_fields: metaFields, + type, + rollup_index: rollupIndex, + allow_no_index: allowNoIndex, + } = request.query; let parsedFields: string[] = []; try { @@ -96,6 +103,9 @@ export function registerRoutes( metaFields: parsedFields, type, rollupIndex, + fieldCapsOptions: { + allow_no_indices: allowNoIndex || false, + }, }); return response.ok({ diff --git a/src/plugins/data/server/index_patterns/routes/create_index_pattern.ts b/src/plugins/data/server/index_patterns/routes/create_index_pattern.ts index 57a745b19748d..1163fd2dc9953 100644 --- a/src/plugins/data/server/index_patterns/routes/create_index_pattern.ts +++ b/src/plugins/data/server/index_patterns/routes/create_index_pattern.ts @@ -50,6 +50,7 @@ const indexPatternSpecSchema = schema.object({ }) ) ), + allowNoIndex: schema.maybe(schema.boolean()), }); export const registerCreateIndexPatternRoute = ( diff --git a/src/plugins/data/server/index_patterns/routes/update_index_pattern.ts b/src/plugins/data/server/index_patterns/routes/update_index_pattern.ts index 10567544af6ea..8bd59e47730fd 100644 --- a/src/plugins/data/server/index_patterns/routes/update_index_pattern.ts +++ b/src/plugins/data/server/index_patterns/routes/update_index_pattern.ts @@ -38,6 +38,7 @@ const indexPatternUpdateSchema = schema.object({ ), fieldFormats: schema.maybe(schema.recordOf(schema.string(), serializedFieldFormatSchema)), fields: schema.maybe(schema.recordOf(schema.string(), fieldSpecSchema)), + allowNoIndex: schema.maybe(schema.boolean()), }); export const registerUpdateIndexPatternRoute = ( diff --git a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts index 1794df7391cb0..038f340babb1f 100644 --- a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts +++ b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.test.ts @@ -18,7 +18,7 @@ */ import { fetchProvider } from './fetch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { CollectorFetchContext } from 'src/plugins/usage_collection/server'; import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks'; @@ -30,7 +30,7 @@ jest.mock('../../../common', () => ({ })); let fetch: ReturnType; -let callCluster: LegacyAPICaller; +let esClient: ElasticsearchClient; let collectorFetchContext: CollectorFetchContext; const collectorFetchContextMock = createCollectorFetchContextMock(); @@ -38,34 +38,33 @@ function setupMockCallCluster( optCount: { optInCount?: number; optOutCount?: number } | null, language: string | undefined | null ) { - callCluster = (jest.fn((method, params) => { - if (params && 'id' in params && params.id === 'kql-telemetry:kql-telemetry') { - if (optCount === null) { - return Promise.resolve({ + function mockedEsGetMethod() { + if (optCount === null) { + return Promise.resolve({ + body: { _index: '.kibana_1', _id: 'kql-telemetry:kql-telemetry', found: false, - }); - } else { - return Promise.resolve({ + }, + }); + } else { + return Promise.resolve({ + body: { _source: { - 'kql-telemetry': { - ...optCount, - }, + 'kql-telemetry': { ...optCount }, type: 'kql-telemetry', updated_at: '2018-10-05T20:20:56.258Z', }, - }); - } - } else if (params && 'body' in params && params.body.query.term.type === 'config') { - if (language === 'missingConfigDoc') { - return Promise.resolve({ - hits: { - hits: [], - }, - }); - } else { - return Promise.resolve({ + }, + }); + } + } + function mockedEsSearchMethod() { + if (language === 'missingConfigDoc') { + return Promise.resolve({ body: { hits: { hits: [] } } }); + } else { + return Promise.resolve({ + body: { hits: { hits: [ { @@ -77,12 +76,15 @@ function setupMockCallCluster( }, ], }, - }); - } + }, + }); } - - throw new Error('invalid call'); - }) as unknown) as LegacyAPICaller; + } + const esClientMock = ({ + get: jest.fn().mockImplementation(mockedEsGetMethod), + search: jest.fn().mockImplementation(mockedEsSearchMethod), + } as unknown) as ElasticsearchClient; + esClient = esClientMock; } describe('makeKQLUsageCollector', () => { @@ -95,7 +97,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster({ optInCount: 1 }, 'kuery'); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.optInCount).toBe(1); @@ -106,7 +108,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster({ optInCount: 1 }, 'kuery'); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.defaultQueryLanguage).toBe('kuery'); @@ -117,7 +119,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster({ optInCount: 1 }, null); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.defaultQueryLanguage).toBe('lucene'); @@ -127,7 +129,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster({ optInCount: 1 }, undefined); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.defaultQueryLanguage).toBe('default-lucene'); @@ -137,7 +139,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster(null, 'kuery'); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.optInCount).toBe(0); @@ -148,7 +150,7 @@ describe('makeKQLUsageCollector', () => { setupMockCallCluster(null, 'missingConfigDoc'); collectorFetchContext = { ...collectorFetchContextMock, - callCluster, + esClient, }; const fetchResponse = await fetch(collectorFetchContext); expect(fetchResponse.defaultQueryLanguage).toBe('default-lucene'); diff --git a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts index 21a1843d1ec81..5178aa65705d8 100644 --- a/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts +++ b/src/plugins/data/server/kql_telemetry/usage_collector/fetch.ts @@ -30,18 +30,22 @@ export interface Usage { } export function fetchProvider(index: string) { - return async ({ callCluster }: CollectorFetchContext): Promise => { - const [response, config] = await Promise.all([ - callCluster('get', { - index, - id: 'kql-telemetry:kql-telemetry', - ignore: [404], - }), - callCluster('search', { - index, - body: { query: { term: { type: 'config' } } }, - ignore: [404], - }), + return async ({ esClient }: CollectorFetchContext): Promise => { + const [{ body: response }, { body: config }] = await Promise.all([ + esClient.get( + { + index, + id: 'kql-telemetry:kql-telemetry', + }, + { ignore: [404] } + ), + esClient.search( + { + index, + body: { query: { term: { type: 'config' } } }, + }, + { ignore: [404] } + ), ]); const queryLanguageConfigValue: string | null | undefined = get( diff --git a/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts b/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts index b1410e2498667..3b223e6fdb9b2 100644 --- a/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts +++ b/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts @@ -94,4 +94,55 @@ Object { expect(migrationFn(input, savedObjectMigrationContext)).toEqual(expected); }); }); + + describe('7.11.0', () => { + const migrationFn = indexPatternSavedObjectTypeMigrations['7.11.0']; + + test('should set allowNoIndex', () => { + const input = { + type: 'index-pattern', + id: 'logs-*', + attributes: {}, + }; + const expected = { + type: 'index-pattern', + id: 'logs-*', + attributes: { + allowNoIndex: true, + }, + }; + + expect(migrationFn(input, savedObjectMigrationContext)).toEqual(expected); + + const input2 = { + type: 'index-pattern', + id: 'metrics-*', + attributes: {}, + }; + const expected2 = { + type: 'index-pattern', + id: 'metrics-*', + attributes: { + allowNoIndex: true, + }, + }; + + expect(migrationFn(input2, savedObjectMigrationContext)).toEqual(expected2); + + const input3 = { + type: 'index-pattern', + id: 'xxx', + attributes: {}, + }; + const expected3 = { + type: 'index-pattern', + id: 'xxx', + attributes: { + allowNoIndex: undefined, + }, + }; + + expect(migrationFn(input3, savedObjectMigrationContext)).toEqual(expected3); + }); + }); }); diff --git a/src/plugins/data/server/saved_objects/index_pattern_migrations.ts b/src/plugins/data/server/saved_objects/index_pattern_migrations.ts index 768041a376ad1..4650aeefba056 100644 --- a/src/plugins/data/server/saved_objects/index_pattern_migrations.ts +++ b/src/plugins/data/server/saved_objects/index_pattern_migrations.ts @@ -54,7 +54,16 @@ const migrateSubTypeAndParentFieldProperties: SavedObjectMigrationFn = }; }; +const addAllowNoIndex: SavedObjectMigrationFn = (doc) => ({ + ...doc, + attributes: { + ...doc.attributes, + allowNoIndex: doc.id === 'logs-*' || doc.id === 'metrics-*' || undefined, + }, +}); + export const indexPatternSavedObjectTypeMigrations = { '6.5.0': flow(migrateAttributeTypeAndAttributeTypeMeta), '7.6.0': flow(migrateSubTypeAndParentFieldProperties), + '7.11.0': flow(addAllowNoIndex), }; diff --git a/src/plugins/data/server/search/aggs/aggs_service.ts b/src/plugins/data/server/search/aggs/aggs_service.ts index c23f748b1eeb5..ae1cf3054ec3f 100644 --- a/src/plugins/data/server/search/aggs/aggs_service.ts +++ b/src/plugins/data/server/search/aggs/aggs_service.ts @@ -86,6 +86,7 @@ export class AggsService { const { calculateAutoTimeExpression, getDateMetaByDatatableColumn, + datatableUtilities, types, } = this.aggsCommonService.start({ getConfig, @@ -130,7 +131,8 @@ export class AggsService { return { calculateAutoTimeExpression, getDateMetaByDatatableColumn, - createAggConfigs: (indexPattern, configStates = [], schemas) => { + datatableUtilities, + createAggConfigs: (indexPattern, configStates = []) => { return new AggConfigs(indexPattern, configStates, { typesRegistry }); }, types: typesRegistry, diff --git a/src/plugins/data/server/search/aggs/mocks.ts b/src/plugins/data/server/search/aggs/mocks.ts index 7b7f3d3c40652..66a6aa2c7d803 100644 --- a/src/plugins/data/server/search/aggs/mocks.ts +++ b/src/plugins/data/server/search/aggs/mocks.ts @@ -70,6 +70,11 @@ export const searchAggsSetupMock = (): AggsSetup => ({ const commonStartMock = (): AggsCommonStart => ({ calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), getDateMetaByDatatableColumn: jest.fn(), + datatableUtilities: { + getIndexPattern: jest.fn(), + getAggConfig: jest.fn(), + isFilterable: jest.fn(), + }, createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), diff --git a/src/plugins/data/server/search/collectors/fetch.ts b/src/plugins/data/server/search/collectors/fetch.ts index 344bc18c7b4b6..9d0d431cf4eaf 100644 --- a/src/plugins/data/server/search/collectors/fetch.ts +++ b/src/plugins/data/server/search/collectors/fetch.ts @@ -20,31 +20,34 @@ import { Observable } from 'rxjs'; import { first } from 'rxjs/operators'; import { SharedGlobalConfig } from 'kibana/server'; +import { SearchResponse } from 'elasticsearch'; import { CollectorFetchContext } from 'src/plugins/usage_collection/server'; import { Usage } from './register'; - -interface SearchTelemetrySavedObject { +interface SearchTelemetry { 'search-telemetry': Usage; } +type ESResponse = SearchResponse; export function fetchProvider(config$: Observable) { - return async ({ callCluster }: CollectorFetchContext): Promise => { + return async ({ esClient }: CollectorFetchContext): Promise => { const config = await config$.pipe(first()).toPromise(); - - const response = await callCluster('search', { - index: config.kibana.index, - body: { - query: { term: { type: { value: 'search-telemetry' } } }, + const { body: esResponse } = await esClient.search( + { + index: config.kibana.index, + body: { + query: { term: { type: { value: 'search-telemetry' } } }, + }, }, - ignore: [404], - }); - - return response.hits.hits.length - ? response.hits.hits[0]._source['search-telemetry'] - : { - successCount: 0, - errorCount: 0, - averageDuration: null, - }; + { ignore: [404] } + ); + const size = esResponse?.hits?.hits?.length ?? 0; + if (!size) { + return { + successCount: 0, + errorCount: 0, + averageDuration: null, + }; + } + return esResponse.hits.hits[0]._source['search-telemetry']; }; } diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index 620df9c8edcb0..983e4a44370d9 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -25,6 +25,7 @@ import type { SearchUsage } from '../collectors'; import { getDefaultSearchParams, getShardTimeout, shimAbortSignal } from './request_utils'; import { toKibanaSearchResponse } from './response_utils'; import { searchUsageObserver } from '../collectors/usage'; +import { KbnServerError } from '../../../../kibana_utils/server'; export const esSearchStrategyProvider = ( config$: Observable, @@ -35,7 +36,7 @@ export const esSearchStrategyProvider = ( // Only default index pattern type is supported here. // See data_enhanced for other type support. if (request.indexType) { - throw new Error(`Unsupported index pattern type ${request.indexType}`); + throw new KbnServerError(`Unsupported index pattern type ${request.indexType}`, 400); } const search = async () => { diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts index 7b44aa18bf8fc..ae6362fac1b21 100644 --- a/src/plugins/data/server/search/routes/msearch.ts +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -23,6 +23,7 @@ import { IRouter } from 'src/core/server'; import { SearchRouteDependencies } from '../search_service'; import { getCallMsearch } from './call_msearch'; +import { reportServerError } from '../../../../kibana_utils/server'; /** * The msearch route takes in an array of searches, each consisting of header @@ -69,15 +70,7 @@ export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependenc const response = await callMsearch({ body: request.body }); return res.ok(response); } catch (err) { - return res.customError({ - statusCode: err.statusCode || 500, - body: { - message: err.message, - attributes: { - error: err.body?.error || err.message, - }, - }, - }); + return reportServerError(res, err); } } ); diff --git a/src/plugins/data/server/search/routes/search.ts b/src/plugins/data/server/search/routes/search.ts index ed519164c8e43..6c27b7e2c43d3 100644 --- a/src/plugins/data/server/search/routes/search.ts +++ b/src/plugins/data/server/search/routes/search.ts @@ -22,6 +22,7 @@ import { schema } from '@kbn/config-schema'; import type { IRouter } from 'src/core/server'; import { getRequestAbortedSignal } from '../../lib'; import { shimHitsTotal } from './shim_hits_total'; +import { reportServerError } from '../../../../kibana_utils/server'; export function registerSearchRoute(router: IRouter): void { router.post( @@ -74,15 +75,7 @@ export function registerSearchRoute(router: IRouter): void { }, }); } catch (err) { - return res.customError({ - statusCode: err.statusCode || 500, - body: { - message: err.message, - attributes: { - error: err.body?.error || err.message, - }, - }, - }); + return reportServerError(res, err); } } ); @@ -106,15 +99,7 @@ export function registerSearchRoute(router: IRouter): void { await context.search!.cancel(id, { strategy }); return res.ok(); } catch (err) { - return res.customError({ - statusCode: err.statusCode, - body: { - message: err.message, - attributes: { - error: err.body.error, - }, - }, - }); + return reportServerError(res, err); } } ); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 5c352b999c369..d34ebdbd80611 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -72,7 +72,8 @@ import { } from '../../common/search/aggs/buckets/shard_delay'; import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; import { ConfigSchema } from '../../config'; -import { SessionService, ISessionService } from './session'; +import { SessionService, IScopedSessionService, ISessionService } from './session'; +import { KbnServerError } from '../../../kibana_utils/server'; declare module 'src/core/server' { interface RequestHandlerContext { @@ -306,7 +307,26 @@ export class SearchService implements Plugin { private cancel = (id: string, options: ISearchOptions, deps: SearchStrategyDependencies) => { const strategy = this.getSearchStrategy(options.strategy); - return strategy.cancel ? strategy.cancel(id, options, deps) : Promise.resolve(); + if (!strategy.cancel) { + throw new KbnServerError( + `Search strategy ${options.strategy} doesn't support cancellations`, + 400 + ); + } + return strategy.cancel(id, options, deps); + }; + + private extend = ( + id: string, + keepAlive: string, + options: ISearchOptions, + deps: SearchStrategyDependencies + ) => { + const strategy = this.getSearchStrategy(options.strategy); + if (!strategy.extend) { + throw new KbnServerError(`Search strategy ${options.strategy} does not support extend`, 400); + } + return strategy.extend(id, keepAlive, options, deps); }; private getSearchStrategy = < @@ -318,7 +338,7 @@ export class SearchService implements Plugin { this.logger.debug(`Get strategy ${name}`); const strategy = this.searchStrategies[name]; if (!strategy) { - throw new Error(`Search strategy ${name} not found`); + throw new KbnServerError(`Search strategy ${name} not found`, 404); } return strategy; }; @@ -344,6 +364,7 @@ export class SearchService implements Plugin { ? getSessionAsScoped(request).cancel(id, options) : this.cancel(id, options, deps); }, + extend: (id, keepAlive, options = {}) => this.extend(id, keepAlive, options, deps), }; }; }; diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index db8b8ac72d0e5..fb00f86464e4e 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -86,6 +86,12 @@ export interface ISearchStrategy< deps: SearchStrategyDependencies ) => Observable; cancel?: (id: string, options: ISearchOptions, deps: SearchStrategyDependencies) => Promise; + extend?: ( + id: string, + keepAlive: string, + options: ISearchOptions, + deps: SearchStrategyDependencies + ) => Promise; } export interface ISearchStart< diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 4d24e6d1afd49..bb8ed92e9bfce 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -689,6 +689,7 @@ export class IndexPattern implements IIndexPattern { // Warning: (ae-forgotten-export) The symbol "IndexPatternDeps" needs to be exported by the entry point index.d.ts constructor({ spec, fieldFormats, shortDotsEnable, metaFields, }: IndexPatternDeps); addScriptedField(name: string, script: string, fieldType?: string): Promise; + readonly allowNoIndex: boolean; // (undocumented) readonly deleteFieldFormat: (fieldName: string) => void; // Warning: (ae-forgotten-export) The symbol "FieldAttrs" needs to be exported by the entry point index.d.ts @@ -731,6 +732,7 @@ export class IndexPattern implements IIndexPattern { fieldFormatMap: string | undefined; type: string | undefined; typeMeta: string | undefined; + allowNoIndex: true | undefined; }; // (undocumented) getComputedFields(): { @@ -819,6 +821,7 @@ export class IndexPattern implements IIndexPattern { // // @public (undocumented) export interface IndexPatternAttributes { + allowNoIndex?: boolean; // (undocumented) fieldAttrs?: string; // (undocumented) @@ -949,6 +952,8 @@ export interface ISearchStrategy Promise; // (undocumented) + extend?: (id: string, keepAlive: string, options: ISearchOptions, deps: SearchStrategyDependencies) => Promise; + // (undocumented) search: (request: SearchStrategyRequest, options: ISearchOptions, deps: SearchStrategyDependencies) => Observable; } @@ -1115,7 +1120,7 @@ export class Plugin implements Plugin_2 void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }; // (undocumented) @@ -1124,7 +1129,7 @@ export class Plugin implements Plugin_2 Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -1388,7 +1393,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/common/es_query/filters/meta_filter.ts:54:3 - (ae-forgotten-export) The symbol "FilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:58:45 - (ae-forgotten-export) The symbol "IndexPatternFieldMap" needs to be exported by the entry point index.d.ts // src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:64:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts -// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:128:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts +// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:133:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:40:23 - (ae-forgotten-export) The symbol "buildCustomFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:40:23 - (ae-forgotten-export) The symbol "buildFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:57:23 - (ae-forgotten-export) The symbol "datatableToCSV" needs to be exported by the entry point index.d.ts @@ -1427,7 +1432,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:279:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index_patterns/index_patterns_service.ts:70:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:90:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/search/types.ts:106:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/search/types.ts:112:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/discover/common/index.ts b/src/plugins/discover/common/index.ts index 4334af63539e3..321a102e8d782 100644 --- a/src/plugins/discover/common/index.ts +++ b/src/plugins/discover/common/index.ts @@ -27,4 +27,5 @@ export const FIELDS_LIMIT_SETTING = 'fields:popularLimit'; export const CONTEXT_DEFAULT_SIZE_SETTING = 'context:defaultSize'; export const CONTEXT_STEP_SETTING = 'context:step'; export const CONTEXT_TIE_BREAKER_FIELDS_SETTING = 'context:tieBreakerFields'; +export const DOC_TABLE_LEGACY = 'doc_table:legacy'; export const MODIFY_COLUMNS_ON_SWITCH = 'discover:modifyColumnsOnSwitch'; diff --git a/src/plugins/discover/public/__mocks__/index_pattern.ts b/src/plugins/discover/public/__mocks__/index_pattern.ts index 706118cb71350..f2c12315d4b90 100644 --- a/src/plugins/discover/public/__mocks__/index_pattern.ts +++ b/src/plugins/discover/public/__mocks__/index_pattern.ts @@ -22,29 +22,40 @@ import { IndexPattern } from '../../../data/common'; import { indexPatterns } from '../../../data/public'; const fields = [ + { + name: '_source', + type: '_source', + scripted: false, + filterable: false, + aggregatable: false, + }, { name: '_index', type: 'string', scripted: false, filterable: true, + aggregatable: false, }, { name: 'message', type: 'string', scripted: false, filterable: false, + aggregatable: false, }, { name: 'extension', type: 'string', scripted: false, filterable: true, + aggregatable: true, }, { name: 'bytes', type: 'number', scripted: false, filterable: true, + aggregatable: true, }, { name: 'scripted', @@ -62,16 +73,21 @@ const indexPattern = ({ id: 'the-index-pattern-id', title: 'the-index-pattern-title', metaFields: ['_index', '_score'], + formatField: jest.fn(), flattenHit: undefined, formatHit: jest.fn((hit) => hit._source), fields, - getComputedFields: () => ({}), + getComputedFields: () => ({ docvalueFields: [], scriptFields: {}, storedFields: ['*'] }), getSourceFiltering: () => ({}), getFieldByName: () => ({}), timeFieldName: '', + docvalueFields: [], } as unknown) as IndexPattern; indexPattern.flattenHit = indexPatterns.flattenHitWrapper(indexPattern, indexPattern.metaFields); indexPattern.isTimeBased = () => !!indexPattern.timeFieldName; +indexPattern.formatField = (hit: Record, fieldName: string) => { + return fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; +}; export const indexPatternMock = indexPattern; diff --git a/src/plugins/discover/public/application/angular/context_app.html b/src/plugins/discover/public/application/angular/context_app.html index d20b1ca999af9..8dc3e5c87e504 100644 --- a/src/plugins/discover/public/application/angular/context_app.html +++ b/src/plugins/discover/public/application/angular/context_app.html @@ -1,15 +1,3 @@ - - - diff --git a/src/plugins/discover/public/application/angular/context_app.js b/src/plugins/discover/public/application/angular/context_app.js index 145d3afe23224..d9e2452eb8bd6 100644 --- a/src/plugins/discover/public/application/angular/context_app.js +++ b/src/plugins/discover/public/application/angular/context_app.js @@ -56,13 +56,14 @@ getAngularModule().directive('contextApp', function ContextApp() { }); function ContextAppController($scope, Private) { - const { filterManager, indexPatterns, uiSettings } = getServices(); + const { filterManager, indexPatterns, uiSettings, navigation } = getServices(); const queryParameterActions = getQueryParameterActions(filterManager, indexPatterns); const queryActions = Private(QueryActionsProvider); this.state = createInitialState( parseInt(uiSettings.get(CONTEXT_STEP_SETTING), 10), getFirstSortableField(this.indexPattern, uiSettings.get(CONTEXT_TIE_BREAKER_FIELDS_SETTING)) ); + this.topNavMenu = navigation.ui.TopNavMenu; this.actions = _.mapValues( { diff --git a/src/plugins/discover/public/application/angular/directives/histogram.tsx b/src/plugins/discover/public/application/angular/directives/histogram.tsx index 4c39c8bb25542..5a0bd5cca6109 100644 --- a/src/plugins/discover/public/application/angular/directives/histogram.tsx +++ b/src/plugins/discover/public/application/angular/directives/histogram.tsx @@ -17,25 +17,17 @@ * under the License. */ -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; -import moment from 'moment-timezone'; -import { unitOfTime } from 'moment'; +import moment, { unitOfTime } from 'moment-timezone'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; -import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; import { - AnnotationDomainTypes, Axis, Chart, HistogramBarSeries, - LineAnnotation, Position, ScaleType, Settings, - RectAnnotation, - TooltipValue, TooltipType, ElementClickListener, XYChartElementEvent, @@ -43,12 +35,17 @@ import { Theme, } from '@elastic/charts'; -import { i18n } from '@kbn/i18n'; import { IUiSettingsClient } from 'kibana/public'; import { EuiChartThemeType } from '@elastic/eui/dist/eui_charts_theme'; import { Subscription, combineLatest } from 'rxjs'; import { getServices } from '../../../kibana_services'; import { Chart as IChart } from '../helpers/point_series'; +import { + CurrentTime, + Endzones, + getAdjustedInterval, + renderEndzoneTooltip, +} from '../../../../../charts/public'; export interface DiscoverHistogramProps { chartData: IChart; @@ -60,34 +57,6 @@ interface DiscoverHistogramState { chartsBaseTheme: Theme; } -function findIntervalFromDuration( - dateValue: number, - esValue: number, - esUnit: unitOfTime.Base, - timeZone: string -) { - const date = moment.tz(dateValue, timeZone); - const startOfDate = moment.tz(date, timeZone).startOf(esUnit); - const endOfDate = moment.tz(date, timeZone).startOf(esUnit).add(esValue, esUnit); - return endOfDate.valueOf() - startOfDate.valueOf(); -} - -function getIntervalInMs( - value: number, - esValue: number, - esUnit: unitOfTime.Base, - timeZone: string -): number { - switch (esUnit) { - case 's': - return 1000 * esValue; - case 'ms': - return 1 * esValue; - default: - return findIntervalFromDuration(value, esValue, esUnit, timeZone); - } -} - function getTimezone(uiSettings: IUiSettingsClient) { if (uiSettings.isDefault('dateFormat:tz')) { const detectedTimezone = moment.tz.guess(); @@ -98,27 +67,6 @@ function getTimezone(uiSettings: IUiSettingsClient) { } } -export function findMinInterval( - xValues: number[], - esValue: number, - esUnit: string, - timeZone: string -): number { - return xValues.reduce((minInterval, currentXvalue, index) => { - let currentDiff = minInterval; - if (index > 0) { - currentDiff = Math.abs(xValues[index - 1] - currentXvalue); - } - const singleUnitInterval = getIntervalInMs( - currentXvalue, - esValue, - esUnit as unitOfTime.Base, - timeZone - ); - return Math.min(minInterval, singleUnitInterval, currentDiff); - }, Number.MAX_SAFE_INTEGER); -} - export class DiscoverHistogram extends Component { public static propTypes = { chartData: PropTypes.object, @@ -132,10 +80,10 @@ export class DiscoverHistogram extends Component + getServices().theme.chartsBaseTheme$, + ]).subscribe(([chartsTheme, chartsBaseTheme]) => this.setState({ chartsTheme, chartsBaseTheme }) ); } @@ -171,40 +119,6 @@ export class DiscoverHistogram extends Component ( - headerData: TooltipValue - ): JSX.Element | string => { - const headerDataValue = headerData.value; - const formattedValue = this.formatXValue(headerDataValue); - - const partialDataText = i18n.translate('discover.histogram.partialData.bucketTooltipText', { - defaultMessage: - 'The selected time range does not include this entire bucket, it may contain partial data.', - }); - - if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) { - return ( - - - - - - {partialDataText} - - -

{formattedValue}

-
- ); - } - - return formattedValue; - }; - public render() { const uiSettings = getServices().uiSettings; const timeZone = getTimezone(uiSettings); @@ -216,8 +130,9 @@ export class DiscoverHistogram extends Component domainStart ? domainStart : data[0]?.x; - const domainMax = domainEnd - xInterval > lastXValue ? domainEnd - xInterval : lastXValue; + const domainMin = Math.min(data[0]?.x, domainStart); + const domainMax = Math.max(domainEnd - xInterval, lastXValue); const xDomain = { min: domainMin, max: domainMax, - minInterval: findMinInterval(xValues, intervalESValue, intervalESUnit, timeZone), - }; - - // Domain end of 'now' will be milliseconds behind current time, so we extend time by 1 minute and check if - // the annotation is within this range; if so, the line annotation uses the domainEnd as its value - const now = moment(); - const isAnnotationAtEdge = moment(domainEnd).add(60000).isAfter(now) && now.isAfter(domainEnd); - const lineAnnotationValue = isAnnotationAtEdge ? domainEnd : now; - - const lineAnnotationData = [ - { - dataValue: lineAnnotationValue, - }, - ]; - const isDarkMode = uiSettings.get('theme:darkMode'); - - const lineAnnotationStyle = { - line: { - strokeWidth: 2, - stroke: isDarkMode ? darkEuiTheme.euiColorDanger : lightEuiTheme.euiColorDanger, - opacity: 0.7, - }, + minInterval: getAdjustedInterval( + xValues, + intervalESValue, + intervalESUnit as unitOfTime.Base, + timeZone + ), }; - - const rectAnnotations = []; - if (domainStart !== domainMin) { - rectAnnotations.push({ - coordinates: { - x1: domainStart, - }, - }); - } - if (domainEnd !== domainMax) { - rectAnnotations.push({ - coordinates: { - x0: domainEnd, - }, - }); - } - - const rectAnnotationStyle = { - stroke: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, - strokeWidth: 0, - opacity: isDarkMode ? 0.6 : 0.2, - fill: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, - }; - const tooltipProps = { - headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd), + headerFormatter: renderEndzoneTooltip(xInterval, domainStart, domainEnd, this.formatXValue), type: TooltipType.VerticalCursor, }; @@ -313,19 +188,14 @@ export class DiscoverHistogram extends Component - - + { }; const discoverRoute = { ...defaults, - template: indexTemplateLegacy, + template: getServices().uiSettings.get('doc_table:legacy', true) + ? indexTemplateLegacy + : indexTemplateGrid, reloadOnSearch: false, resolve: { savedObjects: function ($route, Promise) { @@ -338,6 +342,8 @@ function discoverController($element, $route, $scope, $timeout, Promise, uiCapab $scope.minimumVisibleRows = 50; $scope.fetchStatus = fetchStatuses.UNINITIALIZED; $scope.showSaveQuery = uiCapabilities.discover.saveQuery; + $scope.showTimeCol = + !config.get('doc_table:hideTimeColumn', false) && $scope.indexPattern.timeFieldName; let abortController; $scope.$on('$destroy', () => { @@ -410,9 +416,13 @@ function discoverController($element, $route, $scope, $timeout, Promise, uiCapab function getStateDefaults() { const query = $scope.searchSource.getField('query') || data.query.queryString.getDefaultQuery(); - return { + const sort = getSortArray(savedSearch.sort, $scope.indexPattern); + + const defaultState = { query, - sort: getSortArray(savedSearch.sort, $scope.indexPattern), + sort: !sort.length + ? getDefaultSort($scope.indexPattern, config.get(SORT_DEFAULT_ORDER_SETTING, 'desc')) + : sort, columns: savedSearch.columns.length > 0 ? savedSearch.columns @@ -421,6 +431,11 @@ function discoverController($element, $route, $scope, $timeout, Promise, uiCapab interval: 'auto', filters: _.cloneDeep($scope.searchSource.getOwnField('filter')), }; + if (savedSearch.grid) { + defaultState.grid = savedSearch.grid; + } + + return defaultState; } $scope.state.index = $scope.indexPattern.id; @@ -434,6 +449,8 @@ function discoverController($element, $route, $scope, $timeout, Promise, uiCapab indexPatternList: $route.current.locals.savedObjects.ip.list, config: config, setHeaderActionMenu: getHeaderActionMenuMounter(), + filterManager, + setAppState, data, }; @@ -777,6 +794,17 @@ function discoverController($element, $route, $scope, $timeout, Promise, uiCapab const columns = columnActions.moveColumn($scope.state.columns, columnName, newIndex); setAppState({ columns }); }; + + $scope.setColumns = function setColumns(columns) { + // remove first element of columns if it's the configured timeFieldName, which is prepended automatically + const actualColumns = + $scope.indexPattern.timeFieldName && $scope.indexPattern.timeFieldName === columns[0] + ? columns.slice(1) + : columns; + $scope.state = { ...$scope.state, columns: actualColumns }; + setAppState({ columns: actualColumns }); + }; + async function setupVisualization() { // If no timefield has been specified we don't create a histogram of messages if (!getTimeField()) return; diff --git a/src/plugins/discover/public/application/angular/discover_datagrid.html b/src/plugins/discover/public/application/angular/discover_datagrid.html new file mode 100644 index 0000000000000..e59ebbb0fafd0 --- /dev/null +++ b/src/plugins/discover/public/application/angular/discover_datagrid.html @@ -0,0 +1,31 @@ + + + + diff --git a/src/plugins/discover/public/application/angular/discover_legacy.html b/src/plugins/discover/public/application/angular/discover_legacy.html index 7cdcd6cbbca3a..3596c0a2519ed 100644 --- a/src/plugins/discover/public/application/angular/discover_legacy.html +++ b/src/plugins/discover/public/application/angular/discover_legacy.html @@ -1,6 +1,5 @@ { + indexPattern = FixturesStubbedLogstashIndexPatternProvider() as IndexPattern; + }); + test('should be a function', function () { + expect(typeof getDefaultSort === 'function').toBeTruthy(); + }); + + test('should return default sort for an index pattern with timeFieldName', function () { + expect(getDefaultSort(indexPattern, 'desc')).toEqual([['time', 'desc']]); + expect(getDefaultSort(indexPattern, 'asc')).toEqual([['time', 'asc']]); + }); + + test('should return default sort for an index pattern without timeFieldName', function () { + delete indexPattern.timeFieldName; + expect(getDefaultSort(indexPattern, 'desc')).toEqual([]); + expect(getDefaultSort(indexPattern, 'asc')).toEqual([]); + }); +}); diff --git a/src/plugins/discover/public/application/angular/doc_table/lib/get_default_sort.ts b/src/plugins/discover/public/application/angular/doc_table/lib/get_default_sort.ts index 634e3cfec3a0b..c1e4da0bab54d 100644 --- a/src/plugins/discover/public/application/angular/doc_table/lib/get_default_sort.ts +++ b/src/plugins/discover/public/application/angular/doc_table/lib/get_default_sort.ts @@ -17,7 +17,6 @@ * under the License. */ import { IndexPattern } from '../../../../kibana_services'; -// @ts-ignore import { isSortable } from './get_sort'; import { SortOrder } from '../components/table_header/helpers'; @@ -26,12 +25,12 @@ import { SortOrder } from '../components/table_header/helpers'; * the default sort is returned depending of the index pattern */ export function getDefaultSort( - indexPattern: IndexPattern, + indexPattern: IndexPattern | undefined, defaultSortOrder: string = 'desc' ): SortOrder[] { - if (indexPattern.timeFieldName && isSortable(indexPattern.timeFieldName, indexPattern)) { + if (indexPattern?.timeFieldName && isSortable(indexPattern.timeFieldName, indexPattern)) { return [[indexPattern.timeFieldName, defaultSortOrder]]; } else { - return [['_score', defaultSortOrder]]; + return []; } } diff --git a/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.test.ts b/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.test.ts new file mode 100644 index 0000000000000..1dbd31897d307 --- /dev/null +++ b/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.test.ts @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { getSortForSearchSource } from './get_sort_for_search_source'; +// @ts-ignore +import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; +import { IndexPattern } from '../../../../kibana_services'; +import { SortOrder } from '../components/table_header/helpers'; + +describe('getSortForSearchSource function', function () { + let indexPattern: IndexPattern; + beforeEach(() => { + indexPattern = FixturesStubbedLogstashIndexPatternProvider() as IndexPattern; + }); + test('should be a function', function () { + expect(typeof getSortForSearchSource === 'function').toBeTruthy(); + }); + + test('should return an object to use for searchSource when columns are given', function () { + const cols = [['bytes', 'desc']] as SortOrder[]; + expect(getSortForSearchSource(cols, indexPattern)).toEqual([{ bytes: 'desc' }]); + expect(getSortForSearchSource(cols, indexPattern, 'asc')).toEqual([{ bytes: 'desc' }]); + delete indexPattern.timeFieldName; + expect(getSortForSearchSource(cols, indexPattern)).toEqual([{ bytes: 'desc' }]); + expect(getSortForSearchSource(cols, indexPattern, 'asc')).toEqual([{ bytes: 'desc' }]); + }); + + test('should return an object to use for searchSource when no columns are given', function () { + const cols = [] as SortOrder[]; + expect(getSortForSearchSource(cols, indexPattern)).toEqual([{ _doc: 'desc' }]); + expect(getSortForSearchSource(cols, indexPattern, 'asc')).toEqual([{ _doc: 'asc' }]); + delete indexPattern.timeFieldName; + expect(getSortForSearchSource(cols, indexPattern)).toEqual([{ _score: 'desc' }]); + expect(getSortForSearchSource(cols, indexPattern, 'asc')).toEqual([{ _score: 'asc' }]); + }); +}); diff --git a/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.ts b/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.ts index 6721f7a03584c..1244a0e229cdb 100644 --- a/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.ts +++ b/src/plugins/discover/public/application/angular/doc_table/lib/get_sort_for_search_source.ts @@ -19,7 +19,6 @@ import { EsQuerySortValue, IndexPattern } from '../../../../kibana_services'; import { SortOrder } from '../components/table_header/helpers'; import { getSort } from './get_sort'; -import { getDefaultSort } from './get_default_sort'; /** * Prepares sort for search source, that's sending the request to ES @@ -33,10 +32,13 @@ export function getSortForSearchSource( indexPattern?: IndexPattern, defaultDirection: string = 'desc' ): EsQuerySortValue[] { - if (!sort || !indexPattern) { - return []; - } else if (Array.isArray(sort) && sort.length === 0) { - sort = getDefaultSort(indexPattern, defaultDirection); + if (!sort || !indexPattern || (Array.isArray(sort) && sort.length === 0)) { + if (indexPattern?.timeFieldName) { + // sorting by index order + return [{ _doc: defaultDirection } as EsQuerySortValue]; + } else { + return [{ _score: defaultDirection } as EsQuerySortValue]; + } } const { timeFieldName } = indexPattern; return getSort(sort, indexPattern).map((sortPair: Record) => { diff --git a/src/plugins/discover/public/application/components/context_app/__mocks__/top_nav_menu.tsx b/src/plugins/discover/public/application/components/context_app/__mocks__/top_nav_menu.tsx new file mode 100644 index 0000000000000..be02fd7bc46d2 --- /dev/null +++ b/src/plugins/discover/public/application/components/context_app/__mocks__/top_nav_menu.tsx @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; + +export const TopNavMenuMock = () =>
Hello World
; diff --git a/src/plugins/discover/public/application/components/context_app/context_app_legacy.test.tsx b/src/plugins/discover/public/application/components/context_app/context_app_legacy.test.tsx index f76e0178e98b0..cf6dc70e92d03 100644 --- a/src/plugins/discover/public/application/components/context_app/context_app_legacy.test.tsx +++ b/src/plugins/discover/public/application/components/context_app/context_app_legacy.test.tsx @@ -25,6 +25,7 @@ import { DocTableLegacy } from '../../angular/doc_table/create_doc_table_react'; import { findTestSubject } from '@elastic/eui/lib/test'; import { ActionBar } from '../../angular/context/components/action_bar/action_bar'; import { ContextErrorMessage } from '../context_error_message'; +import { TopNavMenuMock } from './__mocks__/top_nav_menu'; describe('ContextAppLegacy test', () => { const hit = { @@ -64,6 +65,17 @@ describe('ContextAppLegacy test', () => { onChangeSuccessorCount: jest.fn(), predecessorStatus: 'loaded', successorStatus: 'loaded', + topNavMenu: TopNavMenuMock, + }; + const topNavProps = { + appName: 'context', + showSearchBar: true, + showQueryBar: false, + showFilterBar: true, + showSaveQuery: false, + showDatePicker: false, + indexPatterns: [indexPattern], + useDefaultBehaviors: true, }; it('renders correctly', () => { @@ -72,6 +84,9 @@ describe('ContextAppLegacy test', () => { const loadingIndicator = findTestSubject(component, 'contextApp_loadingIndicator'); expect(loadingIndicator.length).toBe(0); expect(component.find(ActionBar).length).toBe(2); + const topNavMenu = component.find(TopNavMenuMock); + expect(topNavMenu.length).toBe(1); + expect(topNavMenu.props()).toStrictEqual(topNavProps); }); it('renders loading indicator', () => { @@ -82,6 +97,7 @@ describe('ContextAppLegacy test', () => { const loadingIndicator = findTestSubject(component, 'contextApp_loadingIndicator'); expect(loadingIndicator.length).toBe(1); expect(component.find(ActionBar).length).toBe(2); + expect(component.find(TopNavMenuMock).length).toBe(1); }); it('renders error message', () => { @@ -90,6 +106,7 @@ describe('ContextAppLegacy test', () => { props.reason = 'something went wrong'; const component = mountWithIntl(); expect(component.find(DocTableLegacy).length).toBe(0); + expect(component.find(TopNavMenuMock).length).toBe(0); const errorMessage = component.find(ContextErrorMessage); expect(errorMessage.length).toBe(1); }); diff --git a/src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx b/src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx index af99c995c60eb..f519df8a0b80d 100644 --- a/src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx +++ b/src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx @@ -27,8 +27,10 @@ import { import { IIndexPattern, IndexPatternField } from '../../../../../data/common/index_patterns'; import { LOADING_STATUS } from './constants'; import { ActionBar, ActionBarProps } from '../../angular/context/components/action_bar/action_bar'; +import { TopNavMenuProps } from '../../../../../navigation/public'; export interface ContextAppProps { + topNavMenu: React.ComponentType; columns: string[]; hits: Array>; indexPattern: IIndexPattern; @@ -96,6 +98,20 @@ export function ContextAppLegacy(renderProps: ContextAppProps) { } as DocTableLegacyProps; }; + const TopNavMenu = renderProps.topNavMenu; + const getNavBarProps = () => { + return { + appName: 'context', + showSearchBar: true, + showQueryBar: false, + showFilterBar: true, + showSaveQuery: false, + showDatePicker: false, + indexPatterns: [renderProps.indexPattern], + useDefaultBehaviors: true, + }; + }; + const loadingFeedback = () => { if (status === LOADING_STATUS.UNINITIALIZED || status === LOADING_STATUS.LOADING) { return ( @@ -112,20 +128,23 @@ export function ContextAppLegacy(renderProps: ContextAppProps) { {isFailed ? ( ) : ( - - - - {loadingFeedback()} - - {isLoaded ? ( -
- -
- ) : null} - - -
-
+
+ + + + + {loadingFeedback()} + + {isLoaded ? ( +
+ +
+ ) : null} + + +
+
+
)} ); diff --git a/src/plugins/discover/public/application/components/context_app/context_app_legacy_directive.ts b/src/plugins/discover/public/application/components/context_app/context_app_legacy_directive.ts index bc4b7c4babd21..dfb5d90c2befe 100644 --- a/src/plugins/discover/public/application/components/context_app/context_app_legacy_directive.ts +++ b/src/plugins/discover/public/application/components/context_app/context_app_legacy_directive.ts @@ -37,5 +37,6 @@ export function createContextAppLegacy(reactDirective: any) { ['successorAvailable', { watchDepth: 'reference' }], ['successorStatus', { watchDepth: 'reference' }], ['onChangeSuccessorCount', { watchDepth: 'reference' }], + ['topNavMenu', { watchDepth: 'reference' }], ]); } diff --git a/src/plugins/discover/public/application/components/create_discover_directive.ts b/src/plugins/discover/public/application/components/create_discover_directive.ts new file mode 100644 index 0000000000000..a146f60652d8a --- /dev/null +++ b/src/plugins/discover/public/application/components/create_discover_directive.ts @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Discover } from './discover'; + +export function createDiscoverDirective(reactDirective: any) { + return reactDirective(Discover, [ + ['fetch', { watchDepth: 'reference' }], + ['fetchCounter', { watchDepth: 'reference' }], + ['fetchError', { watchDepth: 'reference' }], + ['fieldCounts', { watchDepth: 'reference' }], + ['histogramData', { watchDepth: 'reference' }], + ['hits', { watchDepth: 'reference' }], + ['indexPattern', { watchDepth: 'reference' }], + ['onAddColumn', { watchDepth: 'reference' }], + ['onAddFilter', { watchDepth: 'reference' }], + ['onChangeInterval', { watchDepth: 'reference' }], + ['onRemoveColumn', { watchDepth: 'reference' }], + ['onSetColumns', { watchDepth: 'reference' }], + ['onSort', { watchDepth: 'reference' }], + ['opts', { watchDepth: 'reference' }], + ['resetQuery', { watchDepth: 'reference' }], + ['resultState', { watchDepth: 'reference' }], + ['rows', { watchDepth: 'reference' }], + ['searchSource', { watchDepth: 'reference' }], + ['setColumns', { watchDepth: 'reference' }], + ['setIndexPattern', { watchDepth: 'reference' }], + ['showSaveQuery', { watchDepth: 'reference' }], + ['state', { watchDepth: 'reference' }], + ['timefilterUpdateHandler', { watchDepth: 'reference' }], + ['timeRange', { watchDepth: 'reference' }], + ['topNavMenu', { watchDepth: 'reference' }], + ['updateQuery', { watchDepth: 'reference' }], + ['updateSavedQueryId', { watchDepth: 'reference' }], + ]); +} diff --git a/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx b/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx new file mode 100644 index 0000000000000..4e2a2506e282d --- /dev/null +++ b/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import * as React from 'react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { DiscoverGrid, DiscoverGridProps } from './discover_grid/discover_grid'; +import { getServices } from '../../kibana_services'; + +export const DataGridMemoized = React.memo((props: DiscoverGridProps) => ( + +)); + +export function DiscoverGridEmbeddable(props: DiscoverGridProps) { + return ( + + + + ); +} + +/** + * this is just needed for the embeddable + */ +export function createDiscoverGridDirective(reactDirective: any) { + return reactDirective(DiscoverGridEmbeddable, [ + ['columns', { watchDepth: 'collection' }], + ['indexPattern', { watchDepth: 'reference' }], + ['onAddColumn', { watchDepth: 'reference', wrapApply: false }], + ['onFilter', { watchDepth: 'reference', wrapApply: false }], + ['onRemoveColumn', { watchDepth: 'reference', wrapApply: false }], + ['onSetColumns', { watchDepth: 'reference', wrapApply: false }], + ['onSort', { watchDepth: 'reference', wrapApply: false }], + ['rows', { watchDepth: 'collection' }], + ['sampleSize', { watchDepth: 'reference' }], + ['searchDescription', { watchDepth: 'reference' }], + ['searchTitle', { watchDepth: 'reference' }], + ['settings', { watchDepth: 'reference' }], + ['showTimeCol', { watchDepth: 'value' }], + ['sort', { watchDepth: 'value' }], + ]); +} diff --git a/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts index cb3cb06aa90a3..6e5d47be987d8 100644 --- a/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts +++ b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts @@ -21,7 +21,6 @@ import { DiscoverLegacy } from './discover_legacy'; export function createDiscoverLegacyDirective(reactDirective: any) { return reactDirective(DiscoverLegacy, [ - ['addColumn', { watchDepth: 'reference' }], ['fetch', { watchDepth: 'reference' }], ['fetchCounter', { watchDepth: 'reference' }], ['fetchError', { watchDepth: 'reference' }], @@ -30,6 +29,7 @@ export function createDiscoverLegacyDirective(reactDirective: any) { ['hits', { watchDepth: 'reference' }], ['indexPattern', { watchDepth: 'reference' }], ['minimumVisibleRows', { watchDepth: 'reference' }], + ['onAddColumn', { watchDepth: 'reference' }], ['onAddFilter', { watchDepth: 'reference' }], ['onChangeInterval', { watchDepth: 'reference' }], ['onMoveColumn', { watchDepth: 'reference' }], diff --git a/src/plugins/discover/public/application/components/discover.scss b/src/plugins/discover/public/application/components/discover.scss index b17da97a45930..665bd98c232a5 100644 --- a/src/plugins/discover/public/application/components/discover.scss +++ b/src/plugins/discover/public/application/components/discover.scss @@ -35,6 +35,10 @@ discover-app { } } +.dscPageContent { + border: $euiBorderThin; +} + .dscPageContent, .dscPageContent__inner { height: 100%; @@ -46,6 +50,7 @@ discover-app { .dscResultCount { padding: $euiSizeS; + min-height: $euiSize * 3; @include euiBreakpoint('xs', 's') { .dscResultCount__toggle { @@ -76,6 +81,13 @@ discover-app { padding: $euiSizeS; } +// new slimmer layout for data grid +.dscHistogramGrid { + display: flex; + height: $euiSize * 8; + padding: $euiSizeS $euiSizeS 0 $euiSizeS; +} + .dscTable { // SASSTODO: add a monospace modifier to the doc-table component .kbnDocTable__row { diff --git a/src/plugins/discover/public/application/components/discover.tsx b/src/plugins/discover/public/application/components/discover.tsx new file mode 100644 index 0000000000000..aa756d960e435 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover.tsx @@ -0,0 +1,321 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import './discover.scss'; +import React, { useState, useRef } from 'react'; +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiHideFor, + EuiHorizontalRule, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import classNames from 'classnames'; +import { HitsCounter } from './hits_counter'; +import { TimechartHeader } from './timechart_header'; +import { getServices } from '../../kibana_services'; +import { DiscoverUninitialized, DiscoverHistogram } from '../angular/directives'; +import { DiscoverNoResults } from './no_results'; +import { LoadingSpinner } from './loading_spinner/loading_spinner'; +import { search } from '../../../../data/public'; +import { + DiscoverSidebarResponsive, + DiscoverSidebarResponsiveProps, +} from './sidebar/discover_sidebar_responsive'; +import { DiscoverProps } from './discover_legacy'; +import { SortPairArr } from '../angular/doc_table/lib/get_sort'; +import { DiscoverGrid, DiscoverGridProps } from './discover_grid/discover_grid'; + +export const SidebarMemoized = React.memo((props: DiscoverSidebarResponsiveProps) => ( + +)); + +export const DataGridMemoized = React.memo((props: DiscoverGridProps) => ( + +)); + +export function Discover({ + fetch, + fetchCounter, + fetchError, + fieldCounts, + histogramData, + hits, + indexPattern, + onAddColumn, + onAddFilter, + onChangeInterval, + onRemoveColumn, + onSetColumns, + onSort, + opts, + resetQuery, + resultState, + rows, + searchSource, + setIndexPattern, + showSaveQuery, + state, + timefilterUpdateHandler, + timeRange, + topNavMenu, + updateQuery, + updateSavedQueryId, +}: DiscoverProps) { + const scrollableDesktop = useRef(null); + const collapseIcon = useRef(null); + const [toggleOn, toggleChart] = useState(true); + const [isSidebarClosed, setIsSidebarClosed] = useState(false); + const services = getServices(); + const { TopNavMenu } = services.navigation.ui; + const { trackUiMetric } = services; + const { savedSearch, indexPatternList, config } = opts; + const bucketAggConfig = opts.chartAggConfigs?.aggs[1]; + const bucketInterval = + bucketAggConfig && search.aggs.isDateHistogramBucketAggConfig(bucketAggConfig) + ? bucketAggConfig.buckets?.getInterval() + : undefined; + const contentCentered = resultState === 'uninitialized'; + const showTimeCol = !config.get('doc_table:hideTimeColumn', false) && indexPattern.timeFieldName; + const columns = + state.columns && + state.columns.length > 0 && + // check if all columns where removed except the configured timeField (this can't be removed) + !(state.columns.length === 1 && state.columns[0] === indexPattern.timeFieldName) + ? state.columns + : ['_source']; + // if columns include _source this is considered as default view, so you can't remove columns + // until you add a column using Discover's sidebar + const defaultColumns = columns.includes('_source'); + + return ( + + + + +

+ {savedSearch.title} +

+ + + + + + + setIsSidebarClosed(!isSidebarClosed)} + data-test-subj="collapseSideBarButton" + aria-controls="discover-sidebar" + aria-expanded={isSidebarClosed ? 'false' : 'true'} + aria-label={i18n.translate('discover.toggleSidebarAriaLabel', { + defaultMessage: 'Toggle sidebar', + })} + buttonRef={collapseIcon} + /> + + + + + {resultState === 'none' && ( + + )} + {resultState === 'uninitialized' && } + {resultState === 'loading' && } + {resultState === 'ready' && ( + + + + + 0 ? hits : 0} + showResetButton={!!(savedSearch && savedSearch.id)} + onResetQuery={resetQuery} + /> + + {toggleOn && ( + + + + )} + + { + toggleChart(!toggleOn); + }} + > + {toggleOn + ? i18n.translate('discover.hideChart', { + defaultMessage: 'Hide chart', + }) + : i18n.translate('discover.showChart', { + defaultMessage: 'Show chart', + })} + + + + + {toggleOn && opts.timefield && ( + +
+ {opts.chartAggConfigs && histogramData && rows.length !== 0 && ( +
+ +
+ )} +
+ +
+ )} + + + + +
+

+ +

+ {rows && rows.length && ( +
+ { + const grid = { ...state.grid } || {}; + const newColumns = { ...grid.columns } || {}; + newColumns[colSettings.columnId] = { + width: colSettings.width, + }; + const newGrid = { ...grid, columns: newColumns }; + opts.setAppState({ grid: newGrid }); + }} + /> +
+ )} +
+
+
+ )} +
+
+
+
+
+
+ ); +} diff --git a/src/plugins/discover/public/application/components/discover_grid/constants.ts b/src/plugins/discover/public/application/components/discover_grid/constants.ts new file mode 100644 index 0000000000000..dec483da8f8a1 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/constants.ts @@ -0,0 +1,38 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +// data types +export const kibanaJSON = 'kibana-json'; +export const geoPoint = 'geo-point'; +export const unknownType = 'unknown'; +export const gridStyle = { + border: 'all', + fontSize: 's', + cellPadding: 's', + rowHover: 'none', +}; + +export const pageSizeArr = [25, 50, 100]; +export const defaultPageSize = 25; +export const toolbarVisibility = { + showColumnSelector: { + allowHide: false, + allowReorder: true, + }, + showStyleSelector: false, +}; diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid.scss b/src/plugins/discover/public/application/components/discover_grid/discover_grid.scss new file mode 100644 index 0000000000000..64a7eda963349 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid.scss @@ -0,0 +1,68 @@ +.dscDiscoverGrid { + width: 100%; + max-width: 100%; + height: 100%; + overflow: hidden; + + .euiDataGrid__controls { + border: none; + border-bottom: $euiBorderThin; + } + + .euiDataGridRowCell:first-of-type, + .euiDataGrid--headerShade.euiDataGrid--bordersAll .euiDataGridHeaderCell:first-of-type { + border-left: none; + border-right: none; + } + + .euiDataGridRowCell:last-of-type, + .euiDataGridHeaderCell:last-of-type { + border-right: none; + } +} + +.dscDiscoverGrid__footer { + background-color: $euiColorLightShade; + padding: $euiSize / 2 $euiSize; + margin-top: $euiSize / 4; + text-align: center; +} + +.dscTable__flyoutHeader { + white-space: nowrap; +} + +// We only truncate if the cell is not a control column. +.euiDataGridHeader { + .euiDataGridHeaderCell__content { + @include euiTextTruncate; + overflow: hidden; + white-space: nowrap; + flex-grow: 1; + } + + .euiDataGridHeaderCell__popover { + flex-grow: 0; + flex-basis: auto; + width: auto; + padding-left: $euiSizeXS; + } +} + +.euiDataGridRowCell--numeric { + text-align: right; +} + +.euiDataGrid__noResults { + display: flex; + flex-direction: column; + justify-content: center; + flex: 1 0 100%; + text-align: center; + height: 100%; + width: 100%; +} + +.dscFormatSource { + @include euiTextTruncate; +} diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid.tsx new file mode 100644 index 0000000000000..9588f74ed2bc2 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid.tsx @@ -0,0 +1,336 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback, useMemo, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import './discover_grid.scss'; +import { + EuiDataGridSorting, + EuiDataGridStyle, + EuiDataGridProps, + EuiDataGrid, + EuiIcon, + EuiScreenReaderOnly, + EuiSpacer, + EuiText, + htmlIdGenerator, +} from '@elastic/eui'; +import { IndexPattern } from '../../../kibana_services'; +import { DocViewFilterFn, ElasticSearchHit } from '../../doc_views/doc_views_types'; +import { getPopoverContents, getSchemaDetectors } from './discover_grid_schema'; +import { DiscoverGridFlyout } from './discover_grid_flyout'; +import { DiscoverGridContext } from './discover_grid_context'; +import { getRenderCellValueFn } from './get_render_cell_value'; +import { DiscoverGridSettings } from './types'; +import { SortPairArr } from '../../angular/doc_table/lib/get_sort'; +import { + getEuiGridColumns, + getLeadControlColumns, + getVisibleColumns, +} from './discover_grid_columns'; +import { defaultPageSize, gridStyle, pageSizeArr, toolbarVisibility } from './constants'; +import { DiscoverServices } from '../../../build_services'; + +interface SortObj { + id: string; + direction: string; +} + +export interface DiscoverGridProps { + /** + * Determines which element labels the grid for ARIA + */ + ariaLabelledBy: string; + /** + * Determines which columns are displayed + */ + columns: string[]; + /** + * Determines whether the given columns are the default ones, so parts of the document + * are displayed (_source) with limited actions (cannor move, remove columns) + * Implemented for matching with legacy behavior + */ + defaultColumns: boolean; + /** + * The used index pattern + */ + indexPattern: IndexPattern; + /** + * Function used to add a column in the document flyout + */ + onAddColumn: (column: string) => void; + /** + * Function to add a filter in the grid cell or document flyout + */ + onFilter: DocViewFilterFn; + /** + * Function used in the grid header and flyout to remove a column + * @param column + */ + onRemoveColumn: (column: string) => void; + /** + * Function triggered when a column is resized by the user + */ + onResize?: (colSettings: { columnId: string; width: number }) => void; + /** + * Function to set all columns + */ + onSetColumns: (columns: string[]) => void; + /** + * function to change sorting of the documents + */ + onSort: (sort: string[][]) => void; + /** + * Array of documents provided by Elasticsearch + */ + rows?: ElasticSearchHit[]; + /** + * The max size of the documents returned by Elasticsearch + */ + sampleSize: number; + /** + * Grid display settings persisted in Elasticsearch (e.g. column width) + */ + settings?: DiscoverGridSettings; + /** + * Saved search description + */ + searchDescription?: string; + /** + * Saved search title + */ + searchTitle?: string; + /** + * Discover plugin services + */ + services: DiscoverServices; + /** + * Determines whether the time columns should be displayed (legacy settings) + */ + showTimeCol: boolean; + /** + * Current sort setting + */ + sort: SortPairArr[]; +} + +export const EuiDataGridMemoized = React.memo((props: EuiDataGridProps) => { + return ; +}); + +export const DiscoverGrid = ({ + ariaLabelledBy, + columns, + defaultColumns, + indexPattern, + onAddColumn, + onFilter, + onRemoveColumn, + onResize, + onSetColumns, + onSort, + rows, + sampleSize, + searchDescription, + searchTitle, + services, + settings, + showTimeCol, + sort, +}: DiscoverGridProps) => { + const [expanded, setExpanded] = useState(undefined); + + /** + * Pagination + */ + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: defaultPageSize }); + const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]); + const pageCount = useMemo(() => Math.ceil(rowCount / pagination.pageSize), [ + rowCount, + pagination, + ]); + const isOnLastPage = pagination.pageIndex === pageCount - 1; + + const paginationObj = useMemo(() => { + const onChangeItemsPerPage = (pageSize: number) => + setPagination((paginationData) => ({ ...paginationData, pageSize })); + + const onChangePage = (pageIndex: number) => + setPagination((paginationData) => ({ ...paginationData, pageIndex })); + + return { + onChangeItemsPerPage, + onChangePage, + pageIndex: pagination.pageIndex > pageCount - 1 ? 0 : pagination.pageIndex, + pageSize: pagination.pageSize, + pageSizeOptions: pageSizeArr, + }; + }, [pagination, pageCount]); + + /** + * Sorting + */ + const sortingColumns = useMemo(() => sort.map(([id, direction]) => ({ id, direction })), [sort]); + + const onTableSort = useCallback( + (sortingColumnsData) => { + onSort(sortingColumnsData.map(({ id, direction }: SortObj) => [id, direction])); + }, + [onSort] + ); + + /** + * Cell rendering + */ + const renderCellValue = useMemo( + () => + getRenderCellValueFn( + indexPattern, + rows, + rows ? rows.map((hit) => indexPattern.flattenHit(hit)) : [] + ), + [rows, indexPattern] + ); + + /** + * Render variables + */ + const showDisclaimer = rowCount === sampleSize && isOnLastPage; + const randomId = useMemo(() => htmlIdGenerator()(), []); + + const euiGridColumns = useMemo( + () => getEuiGridColumns(columns, settings, indexPattern, showTimeCol, defaultColumns), + [columns, indexPattern, showTimeCol, settings, defaultColumns] + ); + const schemaDetectors = useMemo(() => getSchemaDetectors(), []); + const popoverContents = useMemo(() => getPopoverContents(), []); + const columnsVisibility = useMemo( + () => ({ + visibleColumns: getVisibleColumns(columns, indexPattern, showTimeCol) as string[], + setVisibleColumns: (newColumns: string[]) => { + onSetColumns(newColumns); + }, + }), + [columns, indexPattern, showTimeCol, onSetColumns] + ); + const sorting = useMemo(() => ({ columns: sortingColumns, onSort: onTableSort }), [ + sortingColumns, + onTableSort, + ]); + const lead = useMemo(() => getLeadControlColumns(), []); + + if (!rowCount) { + return ( +
+ + + + + +
+ ); + } + + return ( + + <> + { + if (onResize) { + onResize(col); + } + }} + pagination={paginationObj} + popoverContents={popoverContents} + renderCellValue={renderCellValue} + rowCount={rowCount} + schemaDetectors={schemaDetectors} + sorting={sorting as EuiDataGridSorting} + toolbarVisibility={ + defaultColumns + ? { + ...toolbarVisibility, + showColumnSelector: false, + } + : toolbarVisibility + } + /> + + {showDisclaimer && ( +

+ + + + +

+ )} + {searchTitle && ( + +

+ {searchDescription ? ( + + ) : ( + + )} +

+
+ )} + {expanded && ( + setExpanded(undefined)} + services={services} + /> + )} + + + ); +}; diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.test.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.test.tsx new file mode 100644 index 0000000000000..a85583f66c6fa --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.test.tsx @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { mountWithIntl } from '@kbn/test/jest'; +import { findTestSubject } from '@elastic/eui/lib/test'; +import { FilterInBtn, FilterOutBtn } from './discover_grid_cell_actions'; +import { DiscoverGridContext } from './discover_grid_context'; + +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { esHits } from '../../../__mocks__/es_hits'; +import { EuiButton } from '@elastic/eui'; + +describe('Discover cell actions ', function () { + it('triggers filter function when FilterInBtn is clicked', async () => { + const contextMock = { + expanded: undefined, + setExpanded: jest.fn(), + rows: esHits, + onFilter: jest.fn(), + indexPattern: indexPatternMock, + isDarkMode: false, + }; + + const component = mountWithIntl( + + } + rowIndex={1} + columnId={'extension'} + isExpanded={false} + closePopover={jest.fn()} + /> + + ); + const button = findTestSubject(component, 'filterForButton'); + await button.simulate('click'); + expect(contextMock.onFilter).toHaveBeenCalledWith('extension', 'jpg', '+'); + }); + it('triggers filter function when FilterOutBtn is clicked', async () => { + const contextMock = { + expanded: undefined, + setExpanded: jest.fn(), + rows: esHits, + onFilter: jest.fn(), + indexPattern: indexPatternMock, + isDarkMode: false, + }; + + const component = mountWithIntl( + + } + rowIndex={1} + columnId={'extension'} + isExpanded={false} + closePopover={jest.fn()} + /> + + ); + const button = findTestSubject(component, 'filterOutButton'); + await button.simulate('click'); + expect(contextMock.onFilter).toHaveBeenCalledWith('extension', 'jpg', '-'); + }); +}); diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx new file mode 100644 index 0000000000000..ef56166258c9b --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_cell_actions.tsx @@ -0,0 +1,97 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useContext } from 'react'; +import { EuiDataGridColumnCellActionProps } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { IndexPatternField } from '../../../../../data/common/index_patterns/fields'; +import { DiscoverGridContext } from './discover_grid_context'; + +export const FilterInBtn = ({ + Component, + rowIndex, + columnId, +}: EuiDataGridColumnCellActionProps) => { + const context = useContext(DiscoverGridContext); + const buttonTitle = i18n.translate('discover.grid.filterForAria', { + defaultMessage: 'Filter for this {value}', + values: { value: columnId }, + }); + + return ( + { + const row = context.rows[rowIndex]; + const flattened = context.indexPattern.flattenHit(row); + + if (flattened) { + context.onFilter(columnId, flattened[columnId], '+'); + } + }} + iconType="plusInCircle" + aria-label={buttonTitle} + title={buttonTitle} + data-test-subj="filterForButton" + > + {i18n.translate('discover.grid.filterFor', { + defaultMessage: 'Filter for', + })} + + ); +}; + +export const FilterOutBtn = ({ + Component, + rowIndex, + columnId, +}: EuiDataGridColumnCellActionProps) => { + const context = useContext(DiscoverGridContext); + const buttonTitle = i18n.translate('discover.grid.filterOutAria', { + defaultMessage: 'Filter out this {value}', + values: { value: columnId }, + }); + + return ( + { + const row = context.rows[rowIndex]; + const flattened = context.indexPattern.flattenHit(row); + + if (flattened) { + context.onFilter(columnId, flattened[columnId], '-'); + } + }} + iconType="minusInCircle" + aria-label={buttonTitle} + title={buttonTitle} + data-test-subj="filterOutButton" + > + {i18n.translate('discover.grid.filterOut', { + defaultMessage: 'Filter out', + })} + + ); +}; + +export function buildCellActions(field: IndexPatternField) { + if (!field.aggregatable && !field.searchable) { + return undefined; + } + + return [FilterInBtn, FilterOutBtn]; +} 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 new file mode 100644 index 0000000000000..dad7e1363fdd9 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.test.tsx @@ -0,0 +1,154 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { getEuiGridColumns } from './discover_grid_columns'; +import { indexPatternWithTimefieldMock } from '../../../__mocks__/index_pattern_with_timefield'; + +describe('Discover grid columns ', function () { + it('returns eui grid columns without time column', async () => { + const actual = getEuiGridColumns(['extension', 'message'], {}, indexPatternMock, false, false); + expect(actual).toMatchInlineSnapshot(` + Array [ + Object { + "actions": Object { + "showHide": Object { + "iconType": "cross", + "label": "Remove column", + }, + "showMoveLeft": true, + "showMoveRight": true, + }, + "cellActions": undefined, + "display": undefined, + "id": "extension", + "isSortable": undefined, + "schema": "unknown", + }, + Object { + "actions": Object { + "showHide": Object { + "iconType": "cross", + "label": "Remove column", + }, + "showMoveLeft": true, + "showMoveRight": true, + }, + "cellActions": undefined, + "display": undefined, + "id": "message", + "isSortable": undefined, + "schema": "unknown", + }, + ] + `); + }); + it('returns eui grid columns without time column showing default columns', async () => { + const actual = getEuiGridColumns( + ['extension', 'message'], + {}, + indexPatternWithTimefieldMock, + false, + true + ); + expect(actual).toMatchInlineSnapshot(` + Array [ + Object { + "actions": Object { + "showHide": false, + "showMoveLeft": false, + "showMoveRight": false, + }, + "cellActions": undefined, + "display": undefined, + "id": "extension", + "isSortable": undefined, + "schema": "unknown", + }, + Object { + "actions": Object { + "showHide": false, + "showMoveLeft": false, + "showMoveRight": false, + }, + "cellActions": undefined, + "display": undefined, + "id": "message", + "isSortable": undefined, + "schema": "unknown", + }, + ] + `); + }); + it('returns eui grid columns with time column', async () => { + const actual = getEuiGridColumns( + ['extension', 'message'], + {}, + indexPatternWithTimefieldMock, + true, + false + ); + expect(actual).toMatchInlineSnapshot(` + Array [ + Object { + "actions": Object { + "showHide": false, + "showMoveLeft": true, + "showMoveRight": true, + }, + "cellActions": undefined, + "display": "Time (timestamp)", + "id": "timestamp", + "initialWidth": 180, + "isSortable": undefined, + "schema": "unknown", + }, + Object { + "actions": Object { + "showHide": Object { + "iconType": "cross", + "label": "Remove column", + }, + "showMoveLeft": true, + "showMoveRight": true, + }, + "cellActions": undefined, + "display": undefined, + "id": "extension", + "isSortable": undefined, + "schema": "unknown", + }, + Object { + "actions": Object { + "showHide": Object { + "iconType": "cross", + "label": "Remove column", + }, + "showMoveLeft": true, + "showMoveRight": true, + }, + "cellActions": undefined, + "display": undefined, + "id": "message", + "isSortable": undefined, + "schema": "unknown", + }, + ] + `); + }); +}); 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 new file mode 100644 index 0000000000000..1cf9c84405a61 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_columns.tsx @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiDataGridColumn, EuiScreenReaderOnly } from '@elastic/eui'; +import { ExpandButton } from './discover_grid_expand_button'; +import { DiscoverGridSettings } from './types'; +import { IndexPattern } from '../../../../../data/common/index_patterns/index_patterns'; +import { buildCellActions } from './discover_grid_cell_actions'; +import { getSchemaByKbnType } from './discover_grid_schema'; + +export function getLeadControlColumns() { + return [ + { + id: 'openDetails', + width: 32, + headerCellRender: () => ( + + + {i18n.translate('discover.controlColumnHeader', { + defaultMessage: 'Control column', + })} + + + ), + rowCellRender: ExpandButton, + }, + ]; +} + +export function buildEuiGridColumn( + columnName: string, + columnWidth: number | undefined = 0, + indexPattern: IndexPattern, + defaultColumns: boolean +) { + const timeString = i18n.translate('discover.timeLabel', { + defaultMessage: 'Time', + }); + const indexPatternField = indexPattern.getFieldByName(columnName); + const column: EuiDataGridColumn = { + id: columnName, + schema: getSchemaByKbnType(indexPatternField?.type), + isSortable: indexPatternField?.sortable, + display: indexPatternField?.displayName, + actions: { + showHide: + defaultColumns || columnName === indexPattern.timeFieldName + ? false + : { + label: i18n.translate('discover.removeColumnLabel', { + defaultMessage: 'Remove column', + }), + iconType: 'cross', + }, + showMoveLeft: !defaultColumns, + showMoveRight: !defaultColumns, + }, + cellActions: indexPatternField ? buildCellActions(indexPatternField) : [], + }; + + if (column.id === indexPattern.timeFieldName) { + column.display = `${timeString} (${indexPattern.timeFieldName})`; + column.initialWidth = 180; + } + if (columnWidth > 0) { + column.initialWidth = Number(columnWidth); + } + return column; +} + +export function getEuiGridColumns( + columns: string[], + settings: DiscoverGridSettings | undefined, + indexPattern: IndexPattern, + showTimeCol: boolean, + defaultColumns: boolean +) { + const timeFieldName = indexPattern.timeFieldName; + const getColWidth = (column: string) => settings?.columns?.[column]?.width ?? 0; + + if (showTimeCol && indexPattern.timeFieldName && !columns.find((col) => col === timeFieldName)) { + const usedColumns = [indexPattern.timeFieldName, ...columns]; + return usedColumns.map((column) => + buildEuiGridColumn(column, getColWidth(column), indexPattern, defaultColumns) + ); + } + + return columns.map((column) => + buildEuiGridColumn(column, getColWidth(column), indexPattern, defaultColumns) + ); +} + +export function getVisibleColumns( + columns: string[], + indexPattern: IndexPattern, + showTimeCol: boolean +) { + const timeFieldName = indexPattern.timeFieldName; + + if (showTimeCol && !columns.find((col) => col === timeFieldName)) { + return [timeFieldName, ...columns]; + } + + return columns; +} diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx new file mode 100644 index 0000000000000..dcc404a0e48df --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_context.tsx @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { DocViewFilterFn, ElasticSearchHit } from '../../doc_views/doc_views_types'; +import { IndexPattern } from '../../../kibana_services'; + +export interface GridContext { + expanded: ElasticSearchHit | undefined; + setExpanded: (hit: ElasticSearchHit | undefined) => void; + rows: ElasticSearchHit[]; + onFilter: DocViewFilterFn; + indexPattern: IndexPattern; + isDarkMode: boolean; +} + +const defaultContext = ({} as unknown) as GridContext; + +export const DiscoverGridContext = React.createContext(defaultContext); diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.test.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.test.tsx new file mode 100644 index 0000000000000..82fcad8c2cd6f --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.test.tsx @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { mountWithIntl } from '@kbn/test/jest'; +import { findTestSubject } from '@elastic/eui/lib/test'; +import { ExpandButton } from './discover_grid_expand_button'; +import { DiscoverGridContext } from './discover_grid_context'; +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { esHits } from '../../../__mocks__/es_hits'; + +describe('Discover grid view button ', function () { + it('when no document is expanded, setExpanded is called with current document', async () => { + const contextMock = { + expanded: undefined, + setExpanded: jest.fn(), + rows: esHits, + onFilter: jest.fn(), + indexPattern: indexPatternMock, + isDarkMode: false, + }; + + const component = mountWithIntl( + + + + ); + const button = findTestSubject(component, 'docTableExpandToggleColumn'); + await button.simulate('click'); + expect(contextMock.setExpanded).toHaveBeenCalledWith(esHits[0]); + }); + it('when the current document is expanded, setExpanded is called with undefined', async () => { + const contextMock = { + expanded: esHits[0], + setExpanded: jest.fn(), + rows: esHits, + onFilter: jest.fn(), + indexPattern: indexPatternMock, + isDarkMode: false, + }; + + const component = mountWithIntl( + + + + ); + const button = findTestSubject(component, 'docTableExpandToggleColumn'); + await button.simulate('click'); + expect(contextMock.setExpanded).toHaveBeenCalledWith(undefined); + }); + it('when another document is expanded, setExpanded is called with the current document', async () => { + const contextMock = { + expanded: esHits[0], + setExpanded: jest.fn(), + rows: esHits, + onFilter: jest.fn(), + indexPattern: indexPatternMock, + isDarkMode: false, + }; + + const component = mountWithIntl( + + + + ); + const button = findTestSubject(component, 'docTableExpandToggleColumn'); + await button.simulate('click'); + expect(contextMock.setExpanded).toHaveBeenCalledWith(esHits[1]); + }); +}); diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.tsx new file mode 100644 index 0000000000000..d4a3fe85e34ef --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_expand_button.tsx @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useContext, useEffect } from 'react'; +import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiToolTip } from '@elastic/eui'; +import themeDark from '@elastic/eui/dist/eui_theme_dark.json'; +import themeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { i18n } from '@kbn/i18n'; +import { DiscoverGridContext } from './discover_grid_context'; +/** + * Button to expand a given row + */ +export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueElementProps) => { + const { expanded, setExpanded, rows, isDarkMode } = useContext(DiscoverGridContext); + const current = rows[rowIndex]; + useEffect(() => { + if (expanded && current && expanded._id === current._id) { + setCellProps({ + style: { + backgroundColor: isDarkMode ? themeDark.euiColorHighlight : themeLight.euiColorHighlight, + }, + }); + } else { + setCellProps({ style: undefined }); + } + }, [expanded, current, setCellProps, isDarkMode]); + + const isCurrentRowExpanded = current === expanded; + const buttonLabel = i18n.translate('discover.grid.viewDoc', { + defaultMessage: 'Toggle dialog with details', + }); + + return ( + + setExpanded(isCurrentRowExpanded ? undefined : current)} + color={isCurrentRowExpanded ? 'primary' : 'subdued'} + iconType={isCurrentRowExpanded ? 'minimize' : 'expand'} + isSelected={isCurrentRowExpanded} + /> + + ); +}; diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx new file mode 100644 index 0000000000000..79ad98ae2babe --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_flyout.tsx @@ -0,0 +1,143 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiButtonEmpty, + EuiText, + EuiSpacer, + EuiPortal, +} from '@elastic/eui'; +import { DocViewer } from '../doc_viewer/doc_viewer'; +import { IndexPattern } from '../../../kibana_services'; +import { DocViewFilterFn, ElasticSearchHit } from '../../doc_views/doc_views_types'; +import { DiscoverServices } from '../../../build_services'; +import { getContextUrl } from '../../helpers/get_context_url'; + +interface Props { + columns: string[]; + hit: ElasticSearchHit; + indexPattern: IndexPattern; + onAddColumn: (column: string) => void; + onClose: () => void; + onFilter: DocViewFilterFn; + onRemoveColumn: (column: string) => void; + services: DiscoverServices; +} + +/** + * Flyout displaying an expanded Elasticsearch document + */ +export function DiscoverGridFlyout({ + hit, + indexPattern, + columns, + onFilter, + onClose, + onRemoveColumn, + onAddColumn, + services, +}: Props) { + return ( + + + + +

+ {i18n.translate('discover.grid.tableRow.detailHeading', { + defaultMessage: 'Expanded document', + })} +

+
+ + + + + + + {i18n.translate('discover.grid.tableRow.viewText', { + defaultMessage: 'View:', + })} + + + + + + {i18n.translate('discover.grid.tableRow.viewSingleDocumentLinkTextSimple', { + defaultMessage: 'Single document', + })} + + + {indexPattern.isTimeBased() && indexPattern.id && ( + + + {i18n.translate('discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple', { + defaultMessage: 'Surrounding documents', + })} + + + )} + +
+ + { + onFilter(mapping, value, mode); + onClose(); + }} + onRemoveColumn={(columnName: string) => { + onRemoveColumn(columnName); + onClose(); + }} + onAddColumn={(columnName: string) => { + onAddColumn(columnName); + onClose(); + }} + /> + +
+
+ ); +} diff --git a/src/plugins/discover/public/application/components/discover_grid/discover_grid_schema.tsx b/src/plugins/discover/public/application/components/discover_grid/discover_grid_schema.tsx new file mode 100644 index 0000000000000..aa87d3982fa06 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/discover_grid_schema.tsx @@ -0,0 +1,103 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { ReactNode } from 'react'; +import { EuiCodeBlock } from '@elastic/eui'; +import { geoPoint, kibanaJSON, unknownType } from './constants'; +import { KBN_FIELD_TYPES } from '../../../../../data/common'; + +export function getSchemaByKbnType(kbnType: string | undefined) { + // Default DataGrid schemas: boolean, numeric, datetime, json, currency, string + switch (kbnType) { + case KBN_FIELD_TYPES.IP: + case KBN_FIELD_TYPES.GEO_SHAPE: + case KBN_FIELD_TYPES.NUMBER: + return 'numeric'; + case KBN_FIELD_TYPES.BOOLEAN: + return 'boolean'; + case KBN_FIELD_TYPES.STRING: + return 'string'; + case KBN_FIELD_TYPES.DATE: + return 'datetime'; + case KBN_FIELD_TYPES._SOURCE: + return kibanaJSON; + case KBN_FIELD_TYPES.GEO_POINT: + return geoPoint; + default: + return unknownType; + } +} + +export function getSchemaDetectors() { + return [ + { + type: kibanaJSON, + detector() { + return 0; // this schema is always explicitly defined + }, + sortTextAsc: '', + sortTextDesc: '', + icon: '', + color: '', + }, + { + type: unknownType, + detector() { + return 0; // this schema is always explicitly defined + }, + sortTextAsc: '', + sortTextDesc: '', + icon: '', + color: '', + }, + { + type: geoPoint, + detector() { + return 0; // this schema is always explicitly defined + }, + sortTextAsc: '', + sortTextDesc: '', + icon: 'tokenGeo', + }, + ]; +} + +/** + * Returns custom popover content for certain schemas + */ +export function getPopoverContents() { + return { + [geoPoint]: ({ children }: { children: ReactNode }) => { + return {children}; + }, + [unknownType]: ({ children }: { children: ReactNode }) => { + return ( + + {children} + + ); + }, + [kibanaJSON]: ({ children }: { children: ReactNode }) => { + return ( + + {children} + + ); + }, + }; +} diff --git a/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.test.tsx b/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.test.tsx new file mode 100644 index 0000000000000..d9896f4c53907 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.test.tsx @@ -0,0 +1,132 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { shallow } from 'enzyme'; +import { getRenderCellValueFn } from './get_render_cell_value'; +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +const rows = [ + { + _id: '1', + _index: 'test', + _type: 'test', + _score: 1, + _source: { bytes: 100 }, + }, +]; + +describe('Discover grid cell rendering', function () { + it('renders bytes column correctly', () => { + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rows, + rows.map((row) => indexPatternMock.flattenHit(row)) + ); + const component = shallow( + + ); + expect(component.html()).toMatchInlineSnapshot(`"100"`); + }); + it('renders _source column correctly', () => { + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rows, + rows.map((row) => indexPatternMock.flattenHit(row)) + ); + const component = shallow( + + ); + expect(component.html()).toMatchInlineSnapshot( + `"
bytes
100
"` + ); + }); + + it('renders _source column correctly when isDetails is set to true', () => { + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rows, + rows.map((row) => indexPatternMock.flattenHit(row)) + ); + const component = shallow( + + ); + expect(component.html()).toMatchInlineSnapshot(` + "{ + "bytes": 100 + }" + `); + }); + + it('renders correctly when invalid row is given', () => { + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rows, + rows.map((row) => indexPatternMock.flattenHit(row)) + ); + const component = shallow( + + ); + expect(component.html()).toMatchInlineSnapshot(`"-"`); + }); + it('renders correctly when invalid column is given', () => { + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rows, + rows.map((row) => indexPatternMock.flattenHit(row)) + ); + const component = shallow( + + ); + expect(component.html()).toMatchInlineSnapshot(`"-"`); + }); +}); diff --git a/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx new file mode 100644 index 0000000000000..2157e778f84db --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/get_render_cell_value.tsx @@ -0,0 +1,116 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { Fragment, useContext, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import themeLight from '@elastic/eui/dist/eui_theme_light.json'; +import themeDark from '@elastic/eui/dist/eui_theme_dark.json'; + +import { + EuiDataGridCellValueElementProps, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, +} from '@elastic/eui'; +import { IndexPattern } from '../../../kibana_services'; +import { ElasticSearchHit } from '../../doc_views/doc_views_types'; +import { DiscoverGridContext } from './discover_grid_context'; + +export const getRenderCellValueFn = ( + indexPattern: IndexPattern, + rows: ElasticSearchHit[] | undefined, + rowsFlattened: Array> +) => ({ rowIndex, columnId, isDetails, setCellProps }: EuiDataGridCellValueElementProps) => { + const row = rows ? (rows[rowIndex] as Record) : undefined; + const rowFlattened = rowsFlattened + ? (rowsFlattened[rowIndex] as Record) + : undefined; + + const field = indexPattern.fields.getByName(columnId); + const ctx = useContext(DiscoverGridContext); + + useEffect(() => { + if (ctx.expanded && row && ctx.expanded._id === row._id) { + setCellProps({ + style: { + backgroundColor: ctx.isDarkMode + ? themeDark.euiColorHighlight + : themeLight.euiColorHighlight, + }, + }); + } else { + setCellProps({ style: undefined }); + } + }, [ctx, row, setCellProps]); + + if (typeof row === 'undefined' || typeof rowFlattened === 'undefined') { + return -; + } + + if (field && field.type === '_source') { + if (isDetails) { + // nicely formatted JSON for the expanded view + return {JSON.stringify(row[columnId], null, 2)}; + } + const formatted = indexPattern.formatHit(row); + + return ( + + {Object.keys(formatted).map((key) => ( + + {key} + + + ))} + + ); + } + + if (!field?.type && rowFlattened && typeof rowFlattened[columnId] === 'object') { + if (isDetails) { + // nicely formatted JSON for the expanded view + return {JSON.stringify(rowFlattened[columnId], null, 2)}; + } + + return {JSON.stringify(rowFlattened[columnId])}; + } + + if (field?.type === 'geo_point' && rowFlattened && rowFlattened[columnId]) { + const valueFormatted = rowFlattened[columnId] as { lat: number; lon: number }; + return ( +
+ {i18n.translate('discover.latitudeAndLongitude', { + defaultMessage: 'Lat: {lat} Lon: {lon}', + values: { + lat: valueFormatted?.lat, + lon: valueFormatted?.lon, + }, + })} +
+ ); + } + + const valueFormatted = indexPattern.formatField(row, columnId); + if (typeof valueFormatted === 'undefined') { + return -; + } + return ( + // eslint-disable-next-line react/no-danger + + ); +}; diff --git a/src/plugins/discover/public/application/components/discover_grid/types.ts b/src/plugins/discover/public/application/components/discover_grid/types.ts new file mode 100644 index 0000000000000..3d57dbffe924e --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_grid/types.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * User configurable state of data grid, persisted in saved search + */ +export interface DiscoverGridSettings { + columns?: Record; +} + +export interface DiscoverGridSettingsColumn { + width?: number; +} diff --git a/src/plugins/discover/public/application/components/discover_legacy.test.tsx b/src/plugins/discover/public/application/components/discover_legacy.test.tsx index e2f4ba7ab6e2e..bad5c1d2e532d 100644 --- a/src/plugins/discover/public/application/components/discover_legacy.test.tsx +++ b/src/plugins/discover/public/application/components/discover_legacy.test.tsx @@ -67,7 +67,6 @@ function getProps(indexPattern: IndexPattern) { } as unknown) as DiscoverServices; return { - addColumn: jest.fn(), fetch: jest.fn(), fetchCounter: 0, fetchError: undefined, @@ -75,6 +74,7 @@ function getProps(indexPattern: IndexPattern) { hits: esHits.length, indexPattern, minimumVisibleRows: 10, + onAddColumn: jest.fn(), onAddFilter: jest.fn(), onChangeInterval: jest.fn(), onMoveColumn: jest.fn(), diff --git a/src/plugins/discover/public/application/components/discover_legacy.tsx b/src/plugins/discover/public/application/components/discover_legacy.tsx index d228be66990bd..436a145024437 100644 --- a/src/plugins/discover/public/application/components/discover_legacy.tsx +++ b/src/plugins/discover/public/application/components/discover_legacy.tsx @@ -63,46 +63,161 @@ import { import { DocViewFilterFn, ElasticSearchHit } from '../doc_views/doc_views_types'; export interface DiscoverProps { - addColumn: (column: string) => void; + /** + * Function to fetch documents from Elasticsearch + */ fetch: () => void; + /** + * Counter how often data was fetched (used for testing) + */ fetchCounter: number; + /** + * Error in case of a failing document fetch + */ fetchError?: Error; + /** + * Statistics by fields calculated using the fetched documents + */ fieldCounts: Record; + /** + * Histogram aggregation data + */ histogramData?: Chart; + /** + * Number of documents found by recent fetch + */ hits: number; + /** + * Current IndexPattern + */ indexPattern: IndexPattern; + /** + * Value needed for legacy "infinite" loading functionality + * Determins how much records are rendered using the legacy table + * Increased when scrolling down + */ minimumVisibleRows: number; + /** + * Function to add a column to state + */ + onAddColumn: (column: string) => void; + /** + * Function to add a filter to state + */ onAddFilter: DocViewFilterFn; + /** + * Function to change the used time interval of the date histogram + */ onChangeInterval: (interval: string) => void; + /** + * Function to move a given column to a given index, used in legacy table + */ onMoveColumn: (columns: string, newIdx: number) => void; + /** + * Function to remove a given column from state + */ onRemoveColumn: (column: string) => void; + /** + * Function to replace columns in state + */ onSetColumns: (columns: string[]) => void; + /** + * Function to scroll down the legacy table to the bottom + */ onSkipBottomButtonClick: () => void; + /** + * Function to change sorting of the table, triggers a fetch + */ onSort: (sort: string[][]) => void; opts: { + /** + * Date histogram aggregation config + */ chartAggConfigs?: AggConfigs; + /** + * Client of uiSettings + */ config: IUiSettingsClient; + /** + * Data plugin + */ data: DataPublicPluginStart; - fixedScroll: (el: HTMLElement) => void; + /** + * Data plugin filter manager + */ filterManager: FilterManager; + /** + * List of available index patterns + */ indexPatternList: Array>; + /** + * The number of documents that can be displayed in the table/grid + */ sampleSize: number; + /** + * Current instance of SavedSearch + */ savedSearch: SavedSearch; + /** + * Function to set the header menu + */ setHeaderActionMenu: (menuMount: MountPoint | undefined) => void; + /** + * Timefield of the currently used index pattern + */ timefield: string; + /** + * Function to set the current state + */ setAppState: (state: Partial) => void; }; + /** + * Function to reset the current query + */ resetQuery: () => void; + /** + * Current state of the actual query, one of 'uninitialized', 'loading' ,'ready', 'none' + */ resultState: string; + /** + * Array of document of the recent successful search request + */ rows: ElasticSearchHit[]; + /** + * Instance of SearchSource, the high level search API + */ searchSource: ISearchSource; + /** + * Function to change the current index pattern + */ setIndexPattern: (id: string) => void; + /** + * Determines whether the user should be able to use the save query feature + */ showSaveQuery: boolean; + /** + * Current app state of URL + */ state: AppState; + /** + * Function to update the time filter + */ timefilterUpdateHandler: (ranges: { from: number; to: number }) => void; + /** + * Currently selected time range + */ timeRange?: { from: string; to: string }; + /** + * Menu data of top navigation (New, save ...) + */ topNavMenu: TopNavMenuData[]; + /** + * Function to update the actual query + */ updateQuery: (payload: { dateRange: TimeRange; query?: Query }, isUpdate?: boolean) => void; + /** + * Function to update the actual savedQuery id + */ updateSavedQueryId: (savedQueryId?: string) => void; } @@ -114,7 +229,6 @@ export const SidebarMemoized = React.memo((props: DiscoverSidebarResponsiveProps )); export function DiscoverLegacy({ - addColumn, fetch, fetchCounter, fieldCounts, @@ -123,6 +237,7 @@ export function DiscoverLegacy({ hits, indexPattern, minimumVisibleRows, + onAddColumn, onAddFilter, onChangeInterval, onMoveColumn, @@ -192,7 +307,7 @@ export function DiscoverLegacy({ fieldCounts={fieldCounts} hits={rows} indexPatternList={indexPatternList} - onAddField={addColumn} + onAddField={onAddColumn} onAddFilter={onAddFilter} onRemoveField={onRemoveColumn} selectedIndexPattern={searchSource && searchSource.getField('index')} @@ -206,6 +321,8 @@ export function DiscoverLegacy({ setIsSidebarClosed(!isSidebarClosed)} data-test-subj="collapseSideBarButton" aria-controls="discover-sidebar" @@ -335,7 +452,7 @@ export function DiscoverLegacy({ sort={state.sort || []} searchDescription={opts.savedSearch.description} searchTitle={opts.savedSearch.lastSavedTitle} - onAddColumn={addColumn} + onAddColumn={onAddColumn} onFilter={onAddFilter} onMoveColumn={onMoveColumn} onRemoveColumn={onRemoveColumn} diff --git a/src/plugins/discover/public/application/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap b/src/plugins/discover/public/application/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap index b5bd961037e21..d02b484a06a49 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap +++ b/src/plugins/discover/public/application/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap @@ -6,6 +6,7 @@ exports[`Render with 3 different tabs 1`] = ` > - +
); } diff --git a/src/plugins/discover/public/application/components/field_name/__snapshots__/field_name.test.tsx.snap b/src/plugins/discover/public/application/components/field_name/__snapshots__/field_name.test.tsx.snap index 2fa96f9372380..6b5e45f8a0448 100644 --- a/src/plugins/discover/public/application/components/field_name/__snapshots__/field_name.test.tsx.snap +++ b/src/plugins/discover/public/application/components/field_name/__snapshots__/field_name.test.tsx.snap @@ -31,7 +31,7 @@ exports[`FieldName renders a geo field 1`] = `
`; -exports[`FieldName renders a number field by providing a field record, useShortDots is set to false 1`] = ` +exports[`FieldName renders a number field by providing a field record 1`] = `
diff --git a/src/plugins/discover/public/application/components/field_name/field_name.test.tsx b/src/plugins/discover/public/application/components/field_name/field_name.test.tsx index 0deddce1c40a8..248191acf9ab9 100644 --- a/src/plugins/discover/public/application/components/field_name/field_name.test.tsx +++ b/src/plugins/discover/public/application/components/field_name/field_name.test.tsx @@ -27,7 +27,7 @@ test('FieldName renders a string field by providing fieldType and fieldName', () expect(component).toMatchSnapshot(); }); -test('FieldName renders a number field by providing a field record, useShortDots is set to false', () => { +test('FieldName renders a number field by providing a field record', () => { const component = render(); expect(component).toMatchSnapshot(); }); diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx index 391e15485f074..0957ee101bd27 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx @@ -56,7 +56,6 @@ function getComponent({ }: { selected?: boolean; showDetails?: boolean; - useShortDots?: boolean; field?: IndexPatternField; }) { const indexPattern = getStubIndexPattern( diff --git a/src/plugins/discover/public/application/components/sidebar/lib/group_fields.test.ts b/src/plugins/discover/public/application/components/sidebar/lib/group_fields.test.ts index d4670a1e76011..22cacae4c3b45 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/group_fields.test.ts +++ b/src/plugins/discover/public/application/components/sidebar/lib/group_fields.test.ts @@ -19,51 +19,58 @@ import { groupFields } from './group_fields'; import { getDefaultFieldFilter } from './field_filter'; +import { IndexPatternField } from '../../../../../../data/common/index_patterns/fields'; -describe('group_fields', function () { - it('should group fields in selected, popular, unpopular group', function () { - const fields = [ - { - name: 'category', - type: 'string', - esTypes: ['text'], - count: 1, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'currency', - type: 'string', - esTypes: ['keyword'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'customer_birth_date', - type: 'date', - esTypes: ['date'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - ]; +const fields = [ + { + name: 'category', + type: 'string', + esTypes: ['text'], + count: 1, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'currency', + type: 'string', + esTypes: ['keyword'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'customer_birth_date', + type: 'date', + esTypes: ['date'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, +]; - const fieldCounts = { - category: 1, - currency: 1, - customer_birth_date: 1, - }; +const fieldCounts = { + category: 1, + currency: 1, + customer_birth_date: 1, +}; +describe('group_fields', function () { + it('should group fields in selected, popular, unpopular group', function () { const fieldFilterState = getDefaultFieldFilter(); - const actual = groupFields(fields as any, ['currency'], 5, fieldCounts, fieldFilterState); + const actual = groupFields( + fields as IndexPatternField[], + ['currency'], + 5, + fieldCounts, + fieldFilterState + ); expect(actual).toMatchInlineSnapshot(` Object { "popular": Array [ @@ -111,4 +118,34 @@ describe('group_fields', function () { } `); }); + + it('should sort selected fields by columns order ', function () { + const fieldFilterState = getDefaultFieldFilter(); + + const actual1 = groupFields( + fields as IndexPatternField[], + ['customer_birth_date', 'currency', 'unknown'], + 5, + fieldCounts, + fieldFilterState + ); + expect(actual1.selected.map((field) => field.name)).toEqual([ + 'customer_birth_date', + 'currency', + 'unknown', + ]); + + const actual2 = groupFields( + fields as IndexPatternField[], + ['currency', 'customer_birth_date', 'unknown'], + 5, + fieldCounts, + fieldFilterState + ); + expect(actual2.selected.map((field) => field.name)).toEqual([ + 'currency', + 'customer_birth_date', + 'unknown', + ]); + }); }); diff --git a/src/plugins/discover/public/application/components/sidebar/lib/group_fields.tsx b/src/plugins/discover/public/application/components/sidebar/lib/group_fields.tsx index c6a06618900fd..c34becc97cb93 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/group_fields.tsx +++ b/src/plugins/discover/public/application/components/sidebar/lib/group_fields.tsx @@ -70,6 +70,15 @@ export function groupFields( result.unpopular.push(field); } } + // add columns, that are not part of the index pattern, to be removeable + for (const column of columns) { + if (!result.selected.find((field) => field.name === column)) { + result.selected.push({ name: column, displayName: column } as IndexPatternField); + } + } + result.selected.sort((a, b) => { + return columns.indexOf(a.name) - columns.indexOf(b.name); + }); return result; } diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable.ts b/src/plugins/discover/public/application/embeddable/search_embeddable.ts index b143afd1988e6..e4a8ab7bc67ff 100644 --- a/src/plugins/discover/public/application/embeddable/search_embeddable.ts +++ b/src/plugins/discover/public/application/embeddable/search_embeddable.ts @@ -21,9 +21,10 @@ import angular from 'angular'; import _ from 'lodash'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; -import { UiActionsStart, APPLY_FILTER_TRIGGER } from '../../../../ui_actions/public'; +import { UiActionsStart } from '../../../../ui_actions/public'; import { RequestAdapter, Adapters } from '../../../../inspector/public'; import { + APPLY_FILTER_TRIGGER, esFilters, Filter, TimeRange, @@ -35,6 +36,7 @@ import { import { Container, Embeddable } from '../../../../embeddable/public'; import * as columnActions from '../angular/doc_table/actions/columns'; import searchTemplate from './search_template.html'; +import searchTemplateGrid from './search_template_datagrid.html'; import { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; import { SortOrder } from '../angular/doc_table/components/table_header/helpers'; import { getSortForSearchSource } from '../angular/doc_table'; @@ -48,22 +50,29 @@ import { import { SEARCH_EMBEDDABLE_TYPE } from './constants'; import { SavedSearch } from '../..'; import { SAMPLE_SIZE_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../common'; +import { DiscoverGridSettings } from '../components/discover_grid/types'; +import { DiscoverServices } from '../../build_services'; +import { ElasticSearchHit } from '../doc_views/doc_views_types'; +import { getDefaultSort } from '../angular/doc_table/lib/get_default_sort'; interface SearchScope extends ng.IScope { columns?: string[]; + settings?: DiscoverGridSettings; description?: string; sort?: SortOrder[]; sharedItemTitle?: string; inspectorAdapters?: Adapters; setSortOrder?: (sortPair: SortOrder[]) => void; + setColumns?: (columns: string[]) => void; removeColumn?: (column: string) => void; addColumn?: (column: string) => void; moveColumn?: (column: string, index: number) => void; filter?: (field: IFieldType, value: string[], operator: string) => void; - hits?: any[]; + hits?: ElasticSearchHit[]; indexPattern?: IndexPattern; totalHitCount?: number; isLoading?: boolean; + showTimeCol?: boolean; } interface SearchEmbeddableConfig { @@ -75,6 +84,7 @@ interface SearchEmbeddableConfig { indexPatterns?: IndexPattern[]; editable: boolean; filterManager: FilterManager; + services: DiscoverServices; } export class SearchEmbeddable @@ -93,6 +103,7 @@ export class SearchEmbeddable public readonly type = SEARCH_EMBEDDABLE_TYPE; private filterManager: FilterManager; private abortController?: AbortController; + private services: DiscoverServices; private prevTimeRange?: TimeRange; private prevFilters?: Filter[]; @@ -109,6 +120,7 @@ export class SearchEmbeddable indexPatterns, editable, filterManager, + services, }: SearchEmbeddableConfig, initialInput: SearchInput, private readonly executeTriggerActions: UiActionsStart['executeTriggerActions'], @@ -126,7 +138,7 @@ export class SearchEmbeddable }, parent ); - + this.services = services; this.filterManager = filterManager; this.savedSearch = savedSearch; this.$rootScope = $rootScope; @@ -136,8 +148,8 @@ export class SearchEmbeddable }; this.initializeSearchScope(); - this.autoRefreshFetchSubscription = getServices() - .timefilter.getAutoRefreshFetch$() + this.autoRefreshFetchSubscription = this.services.timefilter + .getAutoRefreshFetch$() .subscribe(this.fetch); this.subscription = this.getUpdated$().subscribe(() => { @@ -165,7 +177,9 @@ export class SearchEmbeddable if (!this.searchScope) { throw new Error('Search scope not defined'); } - this.searchInstance = this.$compile(searchTemplate)(this.searchScope); + this.searchInstance = this.$compile( + this.services.uiSettings.get('doc_table:legacy', true) ? searchTemplate : searchTemplateGrid + )(this.searchScope); const rootNode = angular.element(domNode); rootNode.append(this.searchInstance); @@ -200,6 +214,13 @@ export class SearchEmbeddable const { searchSource } = this.savedSearch; const indexPattern = (searchScope.indexPattern = searchSource.getField('index'))!; + if (!this.savedSearch.sort || !this.savedSearch.sort.length) { + this.savedSearch.sort = getDefaultSort( + indexPattern, + getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') + ); + } + const timeRangeSearchSource = searchSource.create(); timeRangeSearchSource.setField('filter', () => { if (!this.searchScope || !this.input.timeRange) return; @@ -241,6 +262,15 @@ export class SearchEmbeddable this.updateInput({ columns }); }; + searchScope.setColumns = (columns: string[]) => { + this.updateInput({ columns }); + }; + + if (this.savedSearch.grid) { + searchScope.settings = this.savedSearch.grid; + } + searchScope.showTimeCol = !this.services.uiSettings.get('doc_table:hideTimeColumn', false); + searchScope.filter = async (field, value, operator) => { let filters = esFilters.generateFilters( this.filterManager, @@ -277,13 +307,13 @@ export class SearchEmbeddable if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - searchSource.setField('size', getServices().uiSettings.get(SAMPLE_SIZE_SETTING)); + searchSource.setField('size', this.services.uiSettings.get(SAMPLE_SIZE_SETTING)); searchSource.setField( 'sort', getSortForSearchSource( this.searchScope.sort, this.searchScope.indexPattern, - getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING) + this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING) ) ); @@ -341,7 +371,14 @@ export class SearchEmbeddable // If there is column or sort data on the panel, that means the original columns or sort settings have // been overridden in a dashboard. searchScope.columns = this.input.columns || this.savedSearch.columns; - searchScope.sort = this.input.sort || this.savedSearch.sort; + const savedSearchSort = + this.savedSearch.sort && this.savedSearch.sort.length + ? this.savedSearch.sort + : getDefaultSort( + this.searchScope?.indexPattern, + getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') + ); + searchScope.sort = this.input.sort || savedSearchSort; searchScope.sharedItemTitle = this.panelTitle; if (forceFetch || isFetchRequired) { diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts index f61fa361f0c0e..d85476568201f 100644 --- a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts +++ b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts @@ -103,6 +103,7 @@ export class SearchEmbeddableFactory filterManager, editable: getServices().capabilities.discover.save as boolean, indexPatterns: indexPattern ? [indexPattern] : [], + services: getServices(), }, input, executeTriggerActions, diff --git a/src/plugins/discover/public/application/embeddable/search_template.html b/src/plugins/discover/public/application/embeddable/search_template.html index e188d230ea307..be2f5cceac080 100644 --- a/src/plugins/discover/public/application/embeddable/search_template.html +++ b/src/plugins/discover/public/application/embeddable/search_template.html @@ -1,20 +1,20 @@ diff --git a/src/plugins/discover/public/application/embeddable/search_template_datagrid.html b/src/plugins/discover/public/application/embeddable/search_template_datagrid.html new file mode 100644 index 0000000000000..6524783897f8f --- /dev/null +++ b/src/plugins/discover/public/application/embeddable/search_template_datagrid.html @@ -0,0 +1,19 @@ + diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts index b2aa3a05d7eb0..2ab1b93d6c37e 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts @@ -21,6 +21,7 @@ import { getSharingData } from './get_sharing_data'; import { IUiSettingsClient } from 'kibana/public'; import { createSearchSourceMock } from '../../../../data/common/search/search_source/mocks'; import { indexPatternMock } from '../../__mocks__/index_pattern'; +import { SORT_DEFAULT_ORDER_SETTING } from '../../../common'; describe('getSharingData', () => { test('returns valid data for sharing', async () => { @@ -29,7 +30,10 @@ describe('getSharingData', () => { searchSourceMock, { columns: [] }, ({ - get: () => { + get: (key: string) => { + if (key === SORT_DEFAULT_ORDER_SETTING) { + return 'desc'; + } return false; }, } as unknown) as IUiSettingsClient, @@ -47,7 +51,7 @@ describe('getSharingData', () => { "searchRequest": Object { "body": Object { "_source": Object {}, - "fields": undefined, + "fields": Array [], "query": Object { "bool": Object { "filter": Array [], @@ -57,8 +61,16 @@ describe('getSharingData', () => { }, }, "script_fields": Object {}, - "sort": Array [], - "stored_fields": undefined, + "sort": Array [ + Object { + "_score": Object { + "order": "desc", + }, + }, + ], + "stored_fields": Array [ + "*", + ], }, "index": "the-index-pattern-title", }, diff --git a/src/plugins/discover/public/application/helpers/persist_saved_search.ts b/src/plugins/discover/public/application/helpers/persist_saved_search.ts index 8e956eff598f3..8ec2012b5843e 100644 --- a/src/plugins/discover/public/application/helpers/persist_saved_search.ts +++ b/src/plugins/discover/public/application/helpers/persist_saved_search.ts @@ -53,6 +53,9 @@ export async function persistSavedSearch( savedSearch.columns = state.columns || []; savedSearch.sort = (state.sort as SortOrder[]) || []; + if (state.grid) { + savedSearch.grid = state.grid; + } try { const id = await savedSearch.save(saveOptions); diff --git a/src/plugins/discover/public/get_inner_angular.ts b/src/plugins/discover/public/get_inner_angular.ts index 651a26cad755d..c32cf3023a25e 100644 --- a/src/plugins/discover/public/get_inner_angular.ts +++ b/src/plugins/discover/public/get_inner_angular.ts @@ -41,6 +41,7 @@ import { createTableRowDirective } from './application/angular/doc_table/compone import { createPagerFactory } from './application/angular/doc_table/lib/pager/pager_factory'; import { createInfiniteScrollDirective } from './application/angular/doc_table/infinite_scroll'; import { createDocViewerDirective } from './application/angular/doc_viewer'; +import { createDiscoverGridDirective } from './application/components/create_discover_grid_directive'; import { createRenderCompleteDirective } from './application/angular/directives/render_complete'; import { initAngularBootstrap, @@ -49,12 +50,12 @@ import { PromiseServiceCreator, registerListenEventListener, watchMultiDecorator, - createTopNavDirective, - createTopNavHelper, } from '../../kibana_legacy/public'; import { DiscoverStartPlugins } from './plugin'; import { getScopedHistory } from './kibana_services'; import { createDiscoverLegacyDirective } from './application/components/create_discover_legacy_directive'; +import { createDiscoverDirective } from './application/components/create_discover_directive'; + /** * returns the main inner angular module, it contains all the parts of Angular Discover * needs to render, so in the end the current 'kibana' angular module is no longer necessary @@ -95,7 +96,6 @@ export function initializeInnerAngularModule( createLocalI18nModule(); createLocalPrivateModule(); createLocalPromiseModule(); - createLocalTopNavModule(navigation); createLocalStorageModule(); createPagerFactoryModule(); createDocTableModule(); @@ -128,7 +128,6 @@ export function initializeInnerAngularModule( 'discoverI18n', 'discoverPrivate', 'discoverPromise', - 'discoverTopNav', 'discoverLocalStorageProvider', 'discoverDocTable', 'discoverPagerFactory', @@ -136,7 +135,8 @@ export function initializeInnerAngularModule( .config(watchMultiDecorator) .run(registerListenEventListener) .directive('renderComplete', createRenderCompleteDirective) - .directive('discoverLegacy', createDiscoverLegacyDirective); + .directive('discoverLegacy', createDiscoverLegacyDirective) + .directive('discover', createDiscoverDirective); } function createLocalPromiseModule() { @@ -147,13 +147,6 @@ function createLocalPrivateModule() { angular.module('discoverPrivate', []).provider('Private', PrivateProvider); } -function createLocalTopNavModule(navigation: NavigationStart) { - angular - .module('discoverTopNav', ['react']) - .directive('kbnTopNav', createTopNavDirective) - .directive('kbnTopNavHelper', createTopNavHelper(navigation.ui)); -} - function createLocalI18nModule() { angular .module('discoverI18n', []) @@ -188,6 +181,7 @@ function createDocTableModule() { .directive('kbnTableRow', createTableRowDirective) .directive('toolBarPagerButtons', createToolBarPagerButtonsDirective) .directive('kbnInfiniteScroll', createInfiniteScrollDirective) + .directive('discoverGrid', createDiscoverGridDirective) .directive('docViewer', createDocViewerDirective) .directive('contextAppLegacy', createContextAppLegacy); } diff --git a/src/plugins/discover/public/saved_searches/_saved_search.ts b/src/plugins/discover/public/saved_searches/_saved_search.ts index 1ec4549f05d49..8a0ec128b4eb2 100644 --- a/src/plugins/discover/public/saved_searches/_saved_search.ts +++ b/src/plugins/discover/public/saved_searches/_saved_search.ts @@ -26,6 +26,7 @@ export function createSavedSearchClass(savedObjects: SavedObjectsStart) { description: 'text', hits: 'integer', columns: 'keyword', + grid: 'object', sort: 'keyword', version: 'integer', }; @@ -45,6 +46,7 @@ export function createSavedSearchClass(savedObjects: SavedObjectsStart) { description: 'text', hits: 'integer', columns: 'keyword', + grid: 'object', sort: 'keyword', version: 'integer', }, diff --git a/src/plugins/discover/public/saved_searches/types.ts b/src/plugins/discover/public/saved_searches/types.ts index d5e5dd765a364..7f6f1a2553d5e 100644 --- a/src/plugins/discover/public/saved_searches/types.ts +++ b/src/plugins/discover/public/saved_searches/types.ts @@ -19,6 +19,7 @@ import { SearchSource } from '../../../data/public'; import { SavedObjectSaveOpts } from '../../../saved_objects/public'; +import { DiscoverGridSettings } from '../application/components/discover_grid/types'; export type SortOrder = [string, string]; export interface SavedSearch { @@ -28,6 +29,7 @@ export interface SavedSearch { description?: string; columns: string[]; sort: SortOrder[]; + grid: DiscoverGridSettings; destroy: () => void; save: (saveOptions: SavedObjectSaveOpts) => Promise; lastSavedTitle?: string; diff --git a/src/plugins/discover/server/saved_objects/search.ts b/src/plugins/discover/server/saved_objects/search.ts index a6e42f956a025..d124a24b120fd 100644 --- a/src/plugins/discover/server/saved_objects/search.ts +++ b/src/plugins/discover/server/saved_objects/search.ts @@ -53,6 +53,7 @@ export const searchSavedObjectType: SavedObjectsType = { }, sort: { type: 'keyword', index: false, doc_values: false }, title: { type: 'text' }, + grid: { type: 'object', enabled: false }, version: { type: 'integer' }, }, }, diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index f45281ee62202..425928385e64a 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -33,6 +33,7 @@ import { CONTEXT_DEFAULT_SIZE_SETTING, CONTEXT_STEP_SETTING, CONTEXT_TIE_BREAKER_FIELDS_SETTING, + DOC_TABLE_LEGACY, MODIFY_COLUMNS_ON_SWITCH, } from '../common'; @@ -165,6 +166,23 @@ export const uiSettings: Record = { category: ['discover'], schema: schema.arrayOf(schema.string()), }, + [DOC_TABLE_LEGACY]: { + name: i18n.translate('discover.advancedSettings.docTableVersionName', { + defaultMessage: 'Use legacy table', + }), + value: true, + description: i18n.translate('discover.advancedSettings.docTableVersionDescription', { + defaultMessage: + 'Discover uses a new table layout that includes better data sorting, drag-and-drop columns, and a full screen ' + + 'view. Enable this option if you prefer to fall back to the legacy table.', + }), + category: ['discover'], + schema: schema.boolean(), + metric: { + type: METRIC_TYPE.CLICK, + name: 'discover:useLegacyDataGrid', + }, + }, [MODIFY_COLUMNS_ON_SWITCH]: { name: i18n.translate('discover.advancedSettings.discover.modifyColumnsOnSwitchTitle', { defaultMessage: 'Modify columns when changing index patterns', diff --git a/src/plugins/embeddable/common/types.ts b/src/plugins/embeddable/common/types.ts index 8965446cc85fa..8366d81a65754 100644 --- a/src/plugins/embeddable/common/types.ts +++ b/src/plugins/embeddable/common/types.ts @@ -18,8 +18,6 @@ */ import { PersistableStateService, SerializableState } from '../../kibana_utils/common'; -import { Query, TimeRange } from '../../data/common/query'; -import { Filter } from '../../data/common/es_query/filters'; export enum ViewMode { EDIT = 'edit', @@ -54,24 +52,14 @@ export type EmbeddableInput = { disableTriggers?: boolean; /** - * Time range of the chart. - */ - timeRange?: TimeRange; - - /** - * Visualization query string used to narrow down results. - */ - query?: Query; - - /** - * Visualization filters used to narrow down results. + * Search session id to group searches */ - filters?: Filter[]; + searchSessionId?: string; /** - * Search session id to group searches + * Flag whether colors should be synced with other panels */ - searchSessionId?: string; + syncColors?: boolean; }; export interface PanelState { diff --git a/src/plugins/embeddable/public/bootstrap.ts b/src/plugins/embeddable/public/bootstrap.ts index 5c95214ef591b..7898fac16fd9e 100644 --- a/src/plugins/embeddable/public/bootstrap.ts +++ b/src/plugins/embeddable/public/bootstrap.ts @@ -20,34 +20,11 @@ import { UiActionsSetup } from '../../ui_actions/public'; import { contextMenuTrigger, panelBadgeTrigger, - EmbeddableContext, - CONTEXT_MENU_TRIGGER, - PANEL_BADGE_TRIGGER, - ACTION_ADD_PANEL, - ACTION_CUSTOMIZE_PANEL, - ACTION_INSPECT_PANEL, - REMOVE_PANEL_ACTION, - ACTION_EDIT_PANEL, panelNotificationTrigger, - PANEL_NOTIFICATION_TRIGGER, + selectRangeTrigger, + valueClickTrigger, } from './lib'; -declare module '../../ui_actions/public' { - export interface TriggerContextMapping { - [CONTEXT_MENU_TRIGGER]: EmbeddableContext; - [PANEL_BADGE_TRIGGER]: EmbeddableContext; - [PANEL_NOTIFICATION_TRIGGER]: EmbeddableContext; - } - - export interface ActionContextMapping { - [ACTION_CUSTOMIZE_PANEL]: EmbeddableContext; - [ACTION_ADD_PANEL]: EmbeddableContext; - [ACTION_INSPECT_PANEL]: EmbeddableContext; - [REMOVE_PANEL_ACTION]: EmbeddableContext; - [ACTION_EDIT_PANEL]: EmbeddableContext; - } -} - /** * This method initializes Embeddable plugin with initial set of * triggers and actions. @@ -56,4 +33,6 @@ export const bootstrap = (uiActions: UiActionsSetup) => { uiActions.registerTrigger(contextMenuTrigger); uiActions.registerTrigger(panelBadgeTrigger); uiActions.registerTrigger(panelNotificationTrigger); + uiActions.registerTrigger(selectRangeTrigger); + uiActions.registerTrigger(valueClickTrigger); }; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 0fc7c7965010b..d537ef2bd0c5c 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -65,6 +65,8 @@ export { PanelNotFoundError, PanelState, PropertySpec, + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, ViewMode, withEmbeddableSubscription, SavedObjectEmbeddableInput, diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx index c7c71656bceb2..c0e13a84066ca 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx @@ -24,8 +24,10 @@ import { Embeddable } from './embeddable'; import { EmbeddableOutput, EmbeddableInput } from './i_embeddable'; import { ViewMode } from '../types'; import { ContactCardEmbeddable } from '../test_samples/embeddables/contact_card/contact_card_embeddable'; -import { FilterableEmbeddable } from '../test_samples/embeddables/filterable_embeddable'; -import type { Filter } from '../../../../data/public'; +import { + MockFilter, + FilterableEmbeddable, +} from '../test_samples/embeddables/filterable_embeddable'; class TestClass { constructor() {} @@ -83,7 +85,7 @@ test('Embeddable reload is called if lastReloadRequest input time changes', asyn test('Embeddable reload is called if lastReloadRequest input time changed and new input is used', async () => { const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 0 }); - const aFilter = ({} as unknown) as Filter; + const aFilter = ({} as unknown) as MockFilter; hello.reload = jest.fn(() => { // when reload is called embeddable already has new input expect(hello.getInput().filters).toEqual([aFilter]); diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx index 2173082d67d3e..f776e41a20458 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx @@ -25,7 +25,6 @@ import { RenderCompleteDispatcher } from '../../../../kibana_utils/public'; import { Adapters } from '../types'; import { IContainer } from '../containers'; import { EmbeddableOutput, IEmbeddable } from './i_embeddable'; -import { TriggerContextMapping } from '../ui_actions'; import { EmbeddableInput, ViewMode } from '../../../common/types'; function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { @@ -248,7 +247,7 @@ export abstract class Embeddable< this.onResetInput(newInput); } - public supportedTriggers(): Array { + public supportedTriggers(): string[] { return []; } } diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts index a19ec2345db8d..3b0c60f3fb08e 100644 --- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts +++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts @@ -20,7 +20,6 @@ import { Observable } from 'rxjs'; import { Adapters } from '../types'; import { IContainer } from '../containers/i_container'; -import { TriggerContextMapping } from '../../../../ui_actions/public'; import { EmbeddableInput } from '../../../common/types'; export interface EmbeddableError { @@ -173,5 +172,5 @@ export interface IEmbeddable< /** * List of triggers that this embeddable will execute. */ - supportedTriggers(): Array; + supportedTriggers(): string[]; } diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx index 2104d93da9ad8..80238b06ff9fa 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx @@ -24,7 +24,7 @@ import { mountWithIntl, nextTick } from '@kbn/test/jest'; import { findTestSubject } from '@elastic/eui/lib/test'; import { I18nProvider } from '@kbn/i18n/react'; import { CONTEXT_MENU_TRIGGER } from '../triggers'; -import { Action, UiActionsStart, ActionType } from '../../../../ui_actions/public'; +import { Action, UiActionsStart } from '../../../../ui_actions/public'; import { Trigger, ViewMode } from '../types'; import { isErrorEmbeddable } from '../embeddables'; import { EmbeddablePanel } from './embeddable_panel'; @@ -216,7 +216,7 @@ const renderInEditModeAndOpenContextMenu = async ( test('HelloWorldContainer in edit mode hides disabledActions', async () => { const action = { id: 'FOO', - type: 'FOO' as ActionType, + type: 'FOO', getIconType: () => undefined, getDisplayName: () => 'foo', isCompatible: async () => true, @@ -252,7 +252,7 @@ test('HelloWorldContainer in edit mode hides disabledActions', async () => { test('HelloWorldContainer hides disabled badges', async () => { const action = { id: 'BAR', - type: 'BAR' as ActionType, + type: 'BAR', getIconType: () => undefined, getDisplayName: () => 'bar', isCompatible: async () => true, diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx index 0361939fd07e6..cb78fac5471a9 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx @@ -20,6 +20,7 @@ import { ViewMode, EmbeddableOutput, isErrorEmbeddable } from '../../../../'; import { AddPanelAction } from './add_panel_action'; import { + MockFilter, FILTERABLE_EMBEDDABLE, FilterableEmbeddable, FilterableEmbeddableInput, @@ -28,7 +29,6 @@ import { FilterableEmbeddableFactory } from '../../../../test_samples/embeddable import { FilterableContainer } from '../../../../test_samples/embeddables/filterable_container'; import { coreMock } from '../../../../../../../../core/public/mocks'; import { ContactCardEmbeddable } from '../../../../test_samples'; -import { esFilters, Filter } from '../../../../../../../../plugins/data/public'; import { EmbeddableStart } from '../../../../../plugin'; import { embeddablePluginMock } from '../../../../../mocks'; import { defaultTrigger } from '../../../../../../../ui_actions/public/triggers'; @@ -51,8 +51,8 @@ beforeEach(async () => { () => null ); - const derivedFilter: Filter = { - $state: { store: esFilters.FilterStateStore.APP_STATE }, + const derivedFilter: MockFilter = { + $state: { store: 'appState' }, meta: { disabled: false, alias: 'name', negate: false }, query: { match: {} }, }; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx index 867092b78ef7a..3363f556b418e 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx @@ -17,20 +17,20 @@ * under the License. */ import React from 'react'; -import { NotificationsStart, OverlayStart } from 'src/core/public'; +import { NotificationsStart, OverlayRef, OverlayStart } from 'src/core/public'; import { EmbeddableStart } from '../../../../../plugin'; import { toMountPoint } from '../../../../../../../kibana_react/public'; import { IContainer } from '../../../../containers'; import { AddPanelFlyout } from './add_panel_flyout'; -export async function openAddPanelFlyout(options: { +export function openAddPanelFlyout(options: { embeddable: IContainer; getFactory: EmbeddableStart['getEmbeddableFactory']; getAllFactories: EmbeddableStart['getEmbeddableFactories']; overlays: OverlayStart; notifications: NotificationsStart; SavedObjectFinder: React.ComponentType; -}) { +}): OverlayRef { const { embeddable, getFactory, @@ -59,4 +59,5 @@ export async function openAddPanelFlyout(options: { ownFocus: true, } ); + return flyoutSession; } diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx index eb83641448986..b784a46127305 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx @@ -29,7 +29,6 @@ import { import { inspectorPluginMock } from '../../../../../../../plugins/inspector/public/mocks'; import { EmbeddableOutput, isErrorEmbeddable, ErrorEmbeddable } from '../../../embeddables'; import { of } from '../../../../tests/helpers'; -import { esFilters } from '../../../../../../../plugins/data/public'; import { embeddablePluginMock } from '../../../../mocks'; import { EmbeddableStart } from '../../../../plugin'; @@ -43,7 +42,7 @@ const setupTests = async () => { panels: {}, filters: [ { - $state: { store: esFilters.FilterStateStore.APP_STATE }, + $state: { store: 'appState' }, meta: { disabled: false, alias: 'name', negate: false }, query: { match: {} }, }, diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx index dea4a88bda082..ce6a1cc20fc4d 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx @@ -21,6 +21,7 @@ import { EmbeddableOutput, isErrorEmbeddable } from '../../../'; import { RemovePanelAction } from './remove_panel_action'; import { EmbeddableStart } from '../../../../plugin'; import { + MockFilter, FILTERABLE_EMBEDDABLE, FilterableEmbeddable, FilterableEmbeddableInput, @@ -29,7 +30,6 @@ import { FilterableEmbeddableFactory } from '../../../test_samples/embeddables/f import { FilterableContainer } from '../../../test_samples/embeddables/filterable_container'; import { ViewMode } from '../../../types'; import { ContactCardEmbeddable } from '../../../test_samples/embeddables/contact_card/contact_card_embeddable'; -import { esFilters, Filter } from '../../../../../../../plugins/data/public'; import { embeddablePluginMock } from '../../../../mocks'; const { setup, doStart } = embeddablePluginMock.createInstance(); @@ -39,8 +39,8 @@ let container: FilterableContainer; let embeddable: FilterableEmbeddable; beforeEach(async () => { - const derivedFilter: Filter = { - $state: { store: esFilters.FilterStateStore.APP_STATE }, + const derivedFilter: MockFilter = { + $state: { store: 'appState' }, meta: { disabled: false, alias: 'name', negate: false }, query: { match: {} }, }; diff --git a/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.test.ts b/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.test.ts index cbaeddf472d52..be034d125dcee 100644 --- a/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.test.ts +++ b/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.test.ts @@ -23,6 +23,7 @@ import { EmbeddableStateTransfer } from '.'; import { ApplicationStart, PublicAppInfo } from '../../../../../core/public'; import { EMBEDDABLE_EDITOR_STATE_KEY, EMBEDDABLE_PACKAGE_STATE_KEY } from './types'; import { EMBEDDABLE_STATE_TRANSFER_STORAGE_KEY } from './embeddable_state_transfer'; +import { Subject } from 'rxjs'; const createStorage = (): Storage => { const createMockStore = () => { @@ -46,16 +47,24 @@ const createStorage = (): Storage => { describe('embeddable state transfer', () => { let application: jest.Mocked; let stateTransfer: EmbeddableStateTransfer; + let currentAppId$: Subject; let store: Storage; const destinationApp = 'superUltraVisualize'; const originatingApp = 'superUltraTestDashboard'; beforeEach(() => { + currentAppId$ = new Subject(); + currentAppId$.next(originatingApp); const core = coreMock.createStart(); application = core.application; store = createStorage(); - stateTransfer = new EmbeddableStateTransfer(application.navigateToApp, undefined, store); + stateTransfer = new EmbeddableStateTransfer( + application.navigateToApp, + currentAppId$, + undefined, + store + ); }); it('cannot fetch app name when given no app list', async () => { @@ -67,7 +76,7 @@ describe('embeddable state transfer', () => { ['testId', { title: 'State Transfer Test App Hello' } as PublicAppInfo], ['testId2', { title: 'State Transfer Test App Goodbye' } as PublicAppInfo], ]); - stateTransfer = new EmbeddableStateTransfer(application.navigateToApp, appsList); + stateTransfer = new EmbeddableStateTransfer(application.navigateToApp, currentAppId$, appsList); expect(stateTransfer.getAppNameFromId('kibanana')).toBeUndefined(); }); @@ -76,7 +85,7 @@ describe('embeddable state transfer', () => { ['testId', { title: 'State Transfer Test App Hello' } as PublicAppInfo], ['testId2', { title: 'State Transfer Test App Goodbye' } as PublicAppInfo], ]); - stateTransfer = new EmbeddableStateTransfer(application.navigateToApp, appsList); + stateTransfer = new EmbeddableStateTransfer(application.navigateToApp, currentAppId$, appsList); expect(stateTransfer.getAppNameFromId('testId')).toBe('State Transfer Test App Hello'); expect(stateTransfer.getAppNameFromId('testId2')).toBe('State Transfer Test App Goodbye'); }); @@ -107,6 +116,13 @@ describe('embeddable state transfer', () => { }); }); + it('sets isTransferInProgress to true when sending an outgoing editor state', async () => { + await stateTransfer.navigateToEditor(destinationApp, { state: { originatingApp } }); + expect(stateTransfer.isTransferInProgress).toEqual(true); + currentAppId$.next(destinationApp); + expect(stateTransfer.isTransferInProgress).toEqual(false); + }); + it('can send an outgoing embeddable package state', async () => { await stateTransfer.navigateToWithEmbeddablePackage(destinationApp, { state: { type: 'coolestType', input: { savedObjectId: '150' } }, @@ -135,6 +151,15 @@ describe('embeddable state transfer', () => { }); }); + it('sets isTransferInProgress to true when sending an outgoing embeddable package state', async () => { + await stateTransfer.navigateToWithEmbeddablePackage(destinationApp, { + state: { type: 'coolestType', input: { savedObjectId: '150' } }, + }); + expect(stateTransfer.isTransferInProgress).toEqual(true); + currentAppId$.next(destinationApp); + expect(stateTransfer.isTransferInProgress).toEqual(false); + }); + it('can fetch an incoming editor state', async () => { store.set(EMBEDDABLE_STATE_TRANSFER_STORAGE_KEY, { [EMBEDDABLE_EDITOR_STATE_KEY]: { originatingApp: 'superUltraTestDashboard' }, diff --git a/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.ts b/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.ts index 0b34bea810520..92900059668db 100644 --- a/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.ts +++ b/src/plugins/embeddable/public/lib/state_transfer/embeddable_state_transfer.ts @@ -38,14 +38,20 @@ export const EMBEDDABLE_STATE_TRANSFER_STORAGE_KEY = 'EMBEDDABLE_STATE_TRANSFER' * @public */ export class EmbeddableStateTransfer { + public isTransferInProgress: boolean; private storage: Storage; constructor( private navigateToApp: ApplicationStart['navigateToApp'], + currentAppId$: ApplicationStart['currentAppId$'], private appList?: ReadonlyMap | undefined, customStorage?: Storage ) { this.storage = customStorage ? customStorage : new Storage(sessionStorage); + this.isTransferInProgress = false; + currentAppId$.subscribe(() => { + this.isTransferInProgress = false; + }); } /** @@ -105,6 +111,7 @@ export class EmbeddableStateTransfer { state: EmbeddableEditorState; } ): Promise { + this.isTransferInProgress = true; await this.navigateToWithState(appId, EMBEDDABLE_EDITOR_STATE_KEY, { ...options, appendToExistingState: true, @@ -119,6 +126,7 @@ export class EmbeddableStateTransfer { appId: string, options?: { path?: string; state: EmbeddablePackageState } ): Promise { + this.isTransferInProgress = true; await this.navigateToWithState(appId, EMBEDDABLE_PACKAGE_STATE_KEY, { ...options, appendToExistingState: true, diff --git a/src/plugins/embeddable/public/lib/test_samples/actions/edit_mode_action.ts b/src/plugins/embeddable/public/lib/test_samples/actions/edit_mode_action.ts index bb34b474efda0..ce13c40f08d7e 100644 --- a/src/plugins/embeddable/public/lib/test_samples/actions/edit_mode_action.ts +++ b/src/plugins/embeddable/public/lib/test_samples/actions/edit_mode_action.ts @@ -17,16 +17,15 @@ * under the License. */ -import { createAction, ActionType } from '../../ui_actions'; +import { createAction } from '../../ui_actions'; import { ViewMode } from '../../types'; import { IEmbeddable } from '../..'; -// Casting to ActionType is a hack - in a real situation use -// declare module and add this id to ActionContextMapping. -export const EDIT_MODE_ACTION = 'EDIT_MODE_ACTION' as ActionType; +export const EDIT_MODE_ACTION = 'EDIT_MODE_ACTION'; export function createEditModeAction() { - return createAction({ + return createAction({ + id: EDIT_MODE_ACTION, type: EDIT_MODE_ACTION, getDisplayName: () => 'I only show up in edit mode', isCompatible: async (context: { embeddable: IEmbeddable }) => diff --git a/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx b/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx index 968caf67b1826..2aa42cbc24554 100644 --- a/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx @@ -17,12 +17,10 @@ * under the License. */ -import { IncompatibleActionError, ActionType, ActionDefinitionByType } from '../../ui_actions'; +import { IncompatibleActionError, Action } from '../../ui_actions'; import { EmbeddableInput, Embeddable, EmbeddableOutput, IEmbeddable } from '../../embeddables'; -// Casting to ActionType is a hack - in a real situation use -// declare module and add this id to ActionContextMapping. -export const SAY_HELLO_ACTION = 'SAY_HELLO_ACTION' as ActionType; +export const SAY_HELLO_ACTION = 'SAY_HELLO_ACTION'; export interface FullNameEmbeddableOutput extends EmbeddableOutput { fullName: string; @@ -42,7 +40,7 @@ export interface SayHelloActionContext { message?: string; } -export class SayHelloAction implements ActionDefinitionByType { +export class SayHelloAction implements Action { public readonly type = SAY_HELLO_ACTION; public readonly id = SAY_HELLO_ACTION; diff --git a/src/plugins/embeddable/public/lib/test_samples/actions/send_message_action.tsx b/src/plugins/embeddable/public/lib/test_samples/actions/send_message_action.tsx index 04898550532df..1427a8dcb736e 100644 --- a/src/plugins/embeddable/public/lib/test_samples/actions/send_message_action.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/actions/send_message_action.tsx @@ -18,16 +18,14 @@ */ import React from 'react'; import { EuiFlyoutBody } from '@elastic/eui'; -import { createAction, IncompatibleActionError, ActionType } from '../../ui_actions'; +import { createAction, IncompatibleActionError } from '../../ui_actions'; import { CoreStart } from '../../../../../../core/public'; import { toMountPoint } from '../../../../../kibana_react/public'; import { Embeddable, EmbeddableInput } from '../../embeddables'; import { GetMessageModal } from './get_message_modal'; import { FullNameEmbeddableOutput, hasFullNameOutput } from './say_hello_action'; -// Casting to ActionType is a hack - in a real situation use -// declare module and add this id to ActionContextMapping. -export const ACTION_SEND_MESSAGE = 'ACTION_SEND_MESSAGE' as ActionType; +export const ACTION_SEND_MESSAGE = 'ACTION_SEND_MESSAGE'; interface ActionContext { embeddable: Embeddable; @@ -44,7 +42,8 @@ export function createSendMessageAction(overlays: CoreStart['overlays']) { overlays.openFlyout(toMountPoint({content})); }; - return createAction({ + return createAction({ + id: ACTION_SEND_MESSAGE, type: ACTION_SEND_MESSAGE, getDisplayName: () => 'Send message', isCompatible, diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx index 01228c778754b..bacc764469a78 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card.tsx @@ -24,13 +24,6 @@ import { EuiButton } from '@elastic/eui'; import * as Rx from 'rxjs'; import { UiActionsStart } from '../../../../../../ui_actions/public'; import { ContactCardEmbeddable, CONTACT_USER_TRIGGER } from './contact_card_embeddable'; -import { EmbeddableContext } from '../../../triggers'; - -declare module '../../../../../../ui_actions/public' { - export interface TriggerContextMapping { - [CONTACT_USER_TRIGGER]: EmbeddableContext; - } -} interface Props { embeddable: ContactCardEmbeddable; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx index 338eb4877a50a..00429c8df0cb1 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx @@ -23,18 +23,21 @@ export class ContactCardExportableEmbeddable extends ContactCardEmbeddable { public getInspectorAdapters = () => { return { tables: { - layer1: { - type: 'datatable', - columns: [ - { id: 'firstName', name: 'First Name' }, - { id: 'originalLastName', name: 'Last Name' }, - ], - rows: [ - { - firstName: this.getInput().firstName, - orignialLastName: this.getInput().lastName, - }, - ], + allowCsvExport: true, + tables: { + layer1: { + type: 'datatable', + columns: [ + { id: 'firstName', name: 'First Name' }, + { id: 'originalLastName', name: 'Last Name' }, + ], + rows: [ + { + firstName: this.getInput().firstName, + orignialLastName: this.getInput().lastName, + }, + ], + }, }, }, }; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx index db71b94ac855f..23696612fd82a 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_container.tsx @@ -18,13 +18,13 @@ */ import { Container, ContainerInput } from '../../containers'; -import { Filter } from '../../../../../data/public'; import { EmbeddableStart } from '../../../plugin'; +import { MockFilter } from './filterable_embeddable'; export const FILTERABLE_CONTAINER = 'FILTERABLE_CONTAINER'; export interface FilterableContainerInput extends ContainerInput { - filters: Filter[]; + filters: MockFilter[]; } /** @@ -33,7 +33,7 @@ export interface FilterableContainerInput extends ContainerInput { * here instead */ export type InheritedChildrenInput = { - filters: Filter[]; + filters: MockFilter[]; id?: string; }; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx index fd6ea3b9aa2b2..99d21198dd151 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/filterable_embeddable.tsx @@ -19,12 +19,18 @@ import { IContainer } from '../../containers'; import { EmbeddableOutput, EmbeddableInput, Embeddable } from '../../embeddables'; -import { Filter } from '../../../../../data/public'; + +/** @internal */ +export interface MockFilter { + $state?: any; + meta: any; + query?: any; +} export const FILTERABLE_EMBEDDABLE = 'FILTERABLE_EMBEDDABLE'; export interface FilterableEmbeddableInput extends EmbeddableInput { - filters: Filter[]; + filters: MockFilter[]; } export class FilterableEmbeddable extends Embeddable { diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index c3b1496b8eca8..cb315b8804484 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -22,8 +22,8 @@ import { Datatable } from '../../../../expressions'; import { Trigger, RowClickContext } from '../../../../ui_actions/public'; import { IEmbeddable } from '..'; -export interface EmbeddableContext { - embeddable: IEmbeddable; +export interface EmbeddableContext { + embeddable: T; } export interface ValueClickContext { @@ -56,7 +56,7 @@ export type ChartActionContext = | RowClickContext; export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; -export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { +export const contextMenuTrigger: Trigger = { id: CONTEXT_MENU_TRIGGER, title: i18n.translate('embeddableApi.contextMenuTrigger.title', { defaultMessage: 'Context menu', @@ -67,7 +67,7 @@ export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { }; export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; -export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = { +export const panelBadgeTrigger: Trigger = { id: PANEL_BADGE_TRIGGER, title: i18n.translate('embeddableApi.panelBadgeTrigger.title', { defaultMessage: 'Panel badges', @@ -78,7 +78,7 @@ export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = { }; export const PANEL_NOTIFICATION_TRIGGER = 'PANEL_NOTIFICATION_TRIGGER'; -export const panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'> = { +export const panelNotificationTrigger: Trigger = { id: PANEL_NOTIFICATION_TRIGGER, title: i18n.translate('embeddableApi.panelNotificationTrigger.title', { defaultMessage: 'Panel notifications', @@ -88,6 +88,28 @@ export const panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'> = { }), }; +export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; +export const selectRangeTrigger: Trigger = { + id: SELECT_RANGE_TRIGGER, + title: i18n.translate('embeddableApi.selectRangeTrigger.title', { + defaultMessage: 'Range selection', + }), + description: i18n.translate('embeddableApi.selectRangeTrigger.description', { + defaultMessage: 'A range of values on the visualization', + }), +}; + +export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; +export const valueClickTrigger: Trigger = { + id: VALUE_CLICK_TRIGGER, + title: i18n.translate('embeddableApi.valueClickTrigger.title', { + defaultMessage: 'Single click', + }), + description: i18n.translate('embeddableApi.valueClickTrigger.description', { + defaultMessage: 'A data point click on the visualization', + }), +}; + export const isValueClickTriggerContext = ( context: ChartActionContext ): context is ValueClickContext => context.data && 'data' in context.data; diff --git a/src/plugins/embeddable/public/mocks.tsx b/src/plugins/embeddable/public/mocks.tsx index df24d9c0393fe..c41ecaabe8479 100644 --- a/src/plugins/embeddable/public/mocks.tsx +++ b/src/plugins/embeddable/public/mocks.tsx @@ -34,7 +34,6 @@ import { coreMock } from '../../../core/public/mocks'; import { UiActionsService } from './lib/ui_actions'; import { CoreStart } from '../../../core/public'; import { Start as InspectorStart } from '../../inspector/public'; -import { dataPluginMock } from '../../data/public/mocks'; import { inspectorPluginMock } from '../../inspector/public/mocks'; import { uiActionsPluginMock } from '../../ui_actions/public/mocks'; @@ -136,13 +135,11 @@ const createInstance = (setupPlugins: Partial = {}) const plugin = new EmbeddablePublicPlugin({} as any); const setup = plugin.setup(coreMock.createSetup(), { uiActions: setupPlugins.uiActions || uiActionsPluginMock.createSetupContract(), - data: dataPluginMock.createSetupContract(), }); const doStart = (startPlugins: Partial = {}) => plugin.start(coreMock.createStart(), { uiActions: startPlugins.uiActions || uiActionsPluginMock.createStartContract(), inspector: inspectorPluginMock.createStartContract(), - data: dataPluginMock.createStartContract(), }); return { plugin, diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 5118a1a8818c0..a417fb3938b8a 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { Subscription } from 'rxjs'; import { identity } from 'lodash'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '../../data/public'; import { getSavedObjectFinder, showSaveModal } from '../../saved_objects/public'; import { UiActionsSetup, UiActionsStart } from '../../ui_actions/public'; import { Start as InspectorStart } from '../../inspector/public'; @@ -62,12 +61,10 @@ import { } from '../common/lib'; export interface EmbeddableSetupDependencies { - data: DataPublicPluginSetup; uiActions: UiActionsSetup; } export interface EmbeddableStartDependencies { - data: DataPublicPluginStart; uiActions: UiActionsStart; inspector: InspectorStart; } @@ -144,7 +141,7 @@ export class EmbeddablePublicPlugin implements Plugin { this.embeddableFactories.set( @@ -161,6 +158,7 @@ export class EmbeddablePublicPlugin implements Plugin storage - ? new EmbeddableStateTransfer(core.application.navigateToApp, this.appList, storage) + ? new EmbeddableStateTransfer( + core.application.navigateToApp, + core.application.currentAppId$, + this.appList, + storage + ) : this.stateTransferService, EmbeddablePanel: getEmbeddablePanelHoc(), telemetry: getTelemetryFunction(commonContract), diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md index 60b694d628b78..386f1b369bef8 100644 --- a/src/plugins/embeddable/public/public.api.md +++ b/src/plugins/embeddable/public/public.api.md @@ -8,88 +8,54 @@ import { Action } from 'history'; import { Action as Action_3 } from 'src/plugins/ui_actions/public'; import { ActionExecutionContext as ActionExecutionContext_2 } from 'src/plugins/ui_actions/public'; import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; -import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch'; import { ApplicationStart as ApplicationStart_2 } from 'kibana/public'; -import { Assign } from '@kbn/utility-types'; -import { BehaviorSubject } from 'rxjs'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; import Boom from '@hapi/boom'; import { ConfigDeprecationProvider } from '@kbn/config'; -import { CoreSetup as CoreSetup_2 } from 'src/core/public'; -import { CoreSetup as CoreSetup_3 } from 'kibana/public'; -import { CoreStart as CoreStart_2 } from 'kibana/public'; import * as CSS from 'csstype'; -import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions'; import { EmbeddableStart as EmbeddableStart_2 } from 'src/plugins/embeddable/public/plugin'; -import { Ensure } from '@kbn/utility-types'; import { EnvironmentMode } from '@kbn/config'; -import { ErrorToastOptions as ErrorToastOptions_2 } from 'src/core/public/notifications'; import { EuiBreadcrumb } from '@elastic/eui'; import { EuiButtonEmptyProps } from '@elastic/eui'; -import { EuiComboBoxProps } from '@elastic/eui'; import { EuiConfirmModalProps } from '@elastic/eui'; import { EuiContextMenuPanelDescriptor } from '@elastic/eui'; import { EuiFlyoutSize } from '@elastic/eui'; import { EuiGlobalToastListToast } from '@elastic/eui'; import { EventEmitter } from 'events'; -import { ExpressionAstExpression } from 'src/plugins/expressions/common'; import { History } from 'history'; import { Href } from 'history'; -import { HttpSetup as HttpSetup_2 } from 'kibana/public'; import { I18nStart as I18nStart_2 } from 'src/core/public'; import { IconType } from '@elastic/eui'; -import { ISearchOptions } from 'src/plugins/data/public'; -import { ISearchSource } from 'src/plugins/data/public'; -import { IStorageWrapper as IStorageWrapper_2 } from 'src/plugins/kibana_utils/public'; -import { IUiSettingsClient as IUiSettingsClient_2 } from 'src/core/public'; import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; import { Location } from 'history'; import { LocationDescriptorObject } from 'history'; import { Logger } from '@kbn/logging'; import { LogMeta } from '@kbn/logging'; import { MaybePromise } from '@kbn/utility-types'; -import { Moment } from 'moment'; -import { NameList } from 'elasticsearch'; import { NotificationsStart as NotificationsStart_2 } from 'src/core/public'; import { Observable } from 'rxjs'; import { Optional } from '@kbn/utility-types'; +import { OverlayRef as OverlayRef_2 } from 'src/core/public'; import { OverlayStart as OverlayStart_2 } from 'src/core/public'; import { PackageInfo } from '@kbn/config'; import { Path } from 'history'; import { PluginInitializerContext } from 'src/core/public'; -import { PluginInitializerContext as PluginInitializerContext_3 } from 'kibana/public'; import * as PropTypes from 'prop-types'; -import { PublicContract } from '@kbn/utility-types'; import { PublicMethodsOf } from '@kbn/utility-types'; import { PublicUiSettingsParams } from 'src/core/server/types'; import React from 'react'; import { RecursiveReadonly } from '@kbn/utility-types'; -import { RequestAdapter as RequestAdapter_2 } from 'src/plugins/inspector/common'; -import { Required } from '@kbn/utility-types'; import * as Rx from 'rxjs'; -import { SavedObject as SavedObject_2 } from 'kibana/server'; -import { SavedObject as SavedObject_3 } from 'src/core/server'; import { SavedObjectAttributes } from 'kibana/server'; import { SavedObjectAttributes as SavedObjectAttributes_2 } from 'src/core/public'; import { SavedObjectAttributes as SavedObjectAttributes_3 } from 'kibana/public'; -import { SavedObjectsClientContract as SavedObjectsClientContract_3 } from 'src/core/public'; -import { SavedObjectsFindOptions as SavedObjectsFindOptions_3 } from 'kibana/public'; -import { SavedObjectsFindResponse as SavedObjectsFindResponse_2 } from 'kibana/server'; -import { Search } from '@elastic/elasticsearch/api/requestParams'; -import { SearchResponse } from 'elasticsearch'; -import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common'; import { ShallowPromise } from '@kbn/utility-types'; import { SimpleSavedObject as SimpleSavedObject_2 } from 'src/core/public'; import { Start as Start_2 } from 'src/plugins/inspector/public'; -import { StartServicesAccessor as StartServicesAccessor_2 } from 'kibana/public'; -import { ToastInputFields as ToastInputFields_2 } from 'src/core/public/notifications'; -import { ToastsSetup as ToastsSetup_2 } from 'kibana/public'; import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; import { TypeOf } from '@kbn/config-schema'; import { UiComponent } from 'src/plugins/kibana_utils/public'; -import { UiCounterMetricType } from '@kbn/analytics'; import { UnregisterCallback } from 'history'; import { UserProvidedValues } from 'src/core/server/types'; @@ -109,10 +75,6 @@ export const ACTION_EDIT_PANEL = "editPanel"; export interface Adapters { // (undocumented) [key: string]: any; - // Warning: (ae-forgotten-export) The symbol "DataAdapter" needs to be exported by the entry point index.d.ts - // - // (undocumented) - data?: DataAdapter; // Warning: (ae-forgotten-export) The symbol "RequestAdapter" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -253,7 +215,7 @@ export const CONTEXT_MENU_TRIGGER = "CONTEXT_MENU_TRIGGER"; // Warning: (ae-missing-release-tag) "contextMenuTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'>; +export const contextMenuTrigger: Trigger; // Warning: (ae-missing-release-tag) "defaultEmbeddableFactoryProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -336,10 +298,8 @@ export abstract class Embeddable; + supportedTriggers(): string[]; // (undocumented) abstract readonly type: string; // (undocumented) @@ -352,7 +312,7 @@ export abstract class Embeddable { +export class EmbeddableChildPanel extends React.Component { constructor(props: EmbeddableChildPanelProps); // (undocumented) [panel: string]: any; @@ -385,9 +345,9 @@ export interface EmbeddableChildPanelProps { // Warning: (ae-missing-release-tag) "EmbeddableContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface EmbeddableContext { +export interface EmbeddableContext { // (undocumented) - embeddable: IEmbeddable; + embeddable: T; } // @public @@ -448,10 +408,8 @@ export type EmbeddableInput = { enhancements?: SerializableState; disabledActions?: string[]; disableTriggers?: boolean; - timeRange?: TimeRange; - query?: Query; - filters?: Filter[]; searchSessionId?: string; + syncColors?: boolean; }; // Warning: (ae-missing-release-tag) "EmbeddableInstanceConfiguration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -505,7 +463,7 @@ export interface EmbeddablePackageState { // Warning: (ae-missing-release-tag) "EmbeddablePanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class EmbeddablePanel extends React.Component { +export class EmbeddablePanel extends React.Component { constructor(props: Props); // (undocumented) closeMyContextMenuPanel: () => void; @@ -575,10 +533,6 @@ export interface EmbeddableSetup { // // @public (undocumented) export interface EmbeddableSetupDependencies { - // Warning: (ae-forgotten-export) The symbol "DataPublicPluginSetup" needs to be exported by the entry point index.d.ts - // - // (undocumented) - data: DataPublicPluginSetup; // Warning: (ae-forgotten-export) The symbol "UiActionsSetup" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -614,10 +568,6 @@ export interface EmbeddableStart extends PersistableStateService | undefined, customStorage?: Storage); + constructor(navigateToApp: ApplicationStart['navigateToApp'], currentAppId$: ApplicationStart['currentAppId$'], appList?: ReadonlyMap | undefined, customStorage?: Storage); // (undocumented) clearEditorState(): void; getAppNameFromId: (appId: string) => string | undefined; getIncomingEditorState(removeAfterFetch?: boolean): EmbeddableEditorState | undefined; getIncomingEmbeddablePackage(removeAfterFetch?: boolean): EmbeddablePackageState | undefined; + // (undocumented) + isTransferInProgress: boolean; // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ApplicationStart" navigateToEditor(appId: string, options?: { path?: string; @@ -709,7 +661,7 @@ export interface IEmbeddable; + supportedTriggers(): string[]; readonly type: string; updateInput(changes: Partial): void; } @@ -717,7 +669,7 @@ export interface IEmbeddable context is EmbeddableContext; +export const isContextMenuTriggerContext: (context: unknown) => context is EmbeddableContext>; // Warning: (ae-missing-release-tag) "isEmbeddable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -764,7 +716,7 @@ export function openAddPanelFlyout(options: { overlays: OverlayStart_2; notifications: NotificationsStart_2; SavedObjectFinder: React.ComponentType; -}): Promise; +}): OverlayRef_2; // Warning: (ae-missing-release-tag) "OutputSpec" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -787,7 +739,7 @@ export const PANEL_NOTIFICATION_TRIGGER = "PANEL_NOTIFICATION_TRIGGER"; // Warning: (ae-missing-release-tag) "panelBadgeTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'>; +export const panelBadgeTrigger: Trigger; // Warning: (ae-missing-release-tag) "PanelNotFoundError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -801,7 +753,7 @@ export class PanelNotFoundError extends Error { // Warning: (ae-missing-release-tag) "panelNotificationTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'>; +export const panelNotificationTrigger: Trigger; // Warning: (ae-missing-release-tag) "PanelState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -871,6 +823,16 @@ export interface SavedObjectEmbeddableInput extends EmbeddableInput { savedObjectId: string; } +// Warning: (ae-missing-release-tag) "SELECT_RANGE_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const SELECT_RANGE_TRIGGER = "SELECT_RANGE_TRIGGER"; + +// Warning: (ae-missing-release-tag) "VALUE_CLICK_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const VALUE_CLICK_TRIGGER = "VALUE_CLICK_TRIGGER"; + // Warning: (ae-missing-release-tag) "ValueClickContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -914,10 +876,7 @@ export const withEmbeddableSubscription: { test('Explicit embeddable input mapped to undefined will default to inherited', async () => { const { start } = await creatHelloWorldContainerAndEmbeddable(); - const derivedFilter: Filter = { - $state: { store: esFilters.FilterStateStore.APP_STATE }, + const derivedFilter: MockFilter = { + $state: { store: 'appState' }, meta: { disabled: false, alias: 'name', negate: false }, query: { match: {} }, }; diff --git a/src/plugins/embeddable/public/tests/explicit_input.test.ts b/src/plugins/embeddable/public/tests/explicit_input.test.ts index 24785dd50a032..531fbcee94db6 100644 --- a/src/plugins/embeddable/public/tests/explicit_input.test.ts +++ b/src/plugins/embeddable/public/tests/explicit_input.test.ts @@ -20,6 +20,7 @@ import { skip } from 'rxjs/operators'; import { testPlugin } from './test_plugin'; import { + MockFilter, FILTERABLE_EMBEDDABLE, FilterableEmbeddableInput, } from '../lib/test_samples/embeddables/filterable_embeddable'; @@ -34,7 +35,6 @@ import { FilterableContainer } from '../lib/test_samples/embeddables/filterable_ import { isErrorEmbeddable } from '../lib'; import { HelloWorldContainer } from '../lib/test_samples/embeddables/hello_world_container'; import { coreMock } from '../../../../core/public/mocks'; -import { esFilters, Filter } from '../../../../plugins/data/public'; import { createEmbeddablePanelMock } from '../mocks'; const { setup, doStart, coreStart, uiActions } = testPlugin( @@ -56,8 +56,8 @@ setup.registerEmbeddableFactory( const start = doStart(); test('Explicit embeddable input mapped to undefined will default to inherited', async () => { - const derivedFilter: Filter = { - $state: { store: esFilters.FilterStateStore.APP_STATE }, + const derivedFilter: MockFilter = { + $state: { store: 'appState' }, meta: { disabled: false, alias: 'name', negate: false }, query: { match: {} }, }; diff --git a/src/plugins/embeddable/public/tests/test_plugin.ts b/src/plugins/embeddable/public/tests/test_plugin.ts index 2c298b437a118..74bb70e913bcc 100644 --- a/src/plugins/embeddable/public/tests/test_plugin.ts +++ b/src/plugins/embeddable/public/tests/test_plugin.ts @@ -21,7 +21,6 @@ import { CoreSetup, CoreStart } from 'src/core/public'; import { UiActionsStart } from '../../../ui_actions/public'; import { uiActionsPluginMock } from '../../../ui_actions/public/mocks'; import { inspectorPluginMock } from '../../../inspector/public/mocks'; -import { dataPluginMock } from '../../../data/public/mocks'; import { coreMock } from '../../../../core/public/mocks'; import { EmbeddablePublicPlugin, EmbeddableSetup, EmbeddableStart } from '../plugin'; @@ -42,7 +41,6 @@ export const testPlugin = ( const initializerContext = {} as any; const plugin = new EmbeddablePublicPlugin(initializerContext); const setup = plugin.setup(coreSetup, { - data: dataPluginMock.createSetupContract(), uiActions: uiActions.setup, }); @@ -53,7 +51,6 @@ export const testPlugin = ( setup, doStart: (anotherCoreStart: CoreStart = coreStart) => { const start = plugin.start(anotherCoreStart, { - data: dataPluginMock.createStartContract(), inspector: inspectorPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), }); diff --git a/src/plugins/es_ui_shared/public/components/cron_editor/cron_editor.tsx b/src/plugins/es_ui_shared/public/components/cron_editor/cron_editor.tsx index 72e2f51c37e4c..19af93b67aca0 100644 --- a/src/plugins/es_ui_shared/public/components/cron_editor/cron_editor.tsx +++ b/src/plugins/es_ui_shared/public/components/cron_editor/cron_editor.tsx @@ -67,6 +67,7 @@ interface Props { fieldToPreferredValueMap: FieldToValueMap; frequency: Frequency; }) => void; + autoFocus?: boolean; } type State = FieldToValueMap; @@ -234,6 +235,7 @@ export class CronEditor extends Component { fullWidth > ) => diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index 10a18d0cbf435..9819c721d7275 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -220,10 +220,10 @@ describe('Execution', () => { }); describe('inspector adapters', () => { - test('by default, "data" and "requests" inspector adapters are available', async () => { + test('by default, "tables" and "requests" inspector adapters are available', async () => { const { result } = (await run('introspectContext key="inspectorAdapters"')) as any; expect(result).toMatchObject({ - data: expect.any(Object), + tables: expect.any(Object), requests: expect.any(Object), }); }); diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index c5c7d82e223b0..609022f8a55c0 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -23,7 +23,7 @@ import { Executor } from '../executor'; import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; import { abortSignalToPromise, Defer, now } from '../../../kibana_utils/common'; -import { RequestAdapter, DataAdapter, Adapters } from '../../../inspector/common'; +import { RequestAdapter, Adapters } from '../../../inspector/common'; import { isExpressionValueError, ExpressionValueError } from '../expression_types/specs/error'; import { ExpressionAstExpression, @@ -34,11 +34,12 @@ import { ExpressionAstNode, } from '../ast'; import { ExecutionContext, DefaultInspectorAdapters } from './types'; -import { getType, ExpressionValue } from '../expression_types'; +import { getType, ExpressionValue, Datatable } from '../expression_types'; import { ArgumentType, ExpressionFunction } from '../expression_functions'; import { getByAlias } from '../util/get_by_alias'; import { ExecutionContract } from './execution_contract'; import { ExpressionExecutionParams } from '../service'; +import { TablesAdapter } from '../util/tables_adapter'; /** * AbortController is not available in Node until v15, so we @@ -72,7 +73,7 @@ export interface ExecutionParams { const createDefaultInspectorAdapters = (): DefaultInspectorAdapters => ({ requests: new RequestAdapter(), - data: new DataAdapter(), + tables: new TablesAdapter(), }); export class Execution< @@ -166,6 +167,9 @@ export class Execution< ast, }); + const inspectorAdapters = + execution.params.inspectorAdapters || createDefaultInspectorAdapters(); + this.context = { getSearchContext: () => this.execution.params.searchContext || {}, getSearchSessionId: () => execution.params.searchSessionId, @@ -175,7 +179,10 @@ export class Execution< variables: execution.params.variables || {}, types: executor.getTypes(), abortSignal: this.abortController.signal, - inspectorAdapters: execution.params.inspectorAdapters || createDefaultInspectorAdapters(), + inspectorAdapters, + logDatatable: (name: string, datatable: Datatable) => { + inspectorAdapters.tables[name] = datatable; + }, ...(execution.params as any).extraContext, }; } diff --git a/src/plugins/expressions/common/execution/execution_contract.test.ts b/src/plugins/expressions/common/execution/execution_contract.test.ts index eaf7e6ea862eb..0a6704a8cb2f6 100644 --- a/src/plugins/expressions/common/execution/execution_contract.test.ts +++ b/src/plugins/expressions/common/execution/execution_contract.test.ts @@ -71,7 +71,7 @@ describe('ExecutionContract', () => { const execution = createExecution('foo bar=123'); const contract = new ExecutionContract(execution); expect(contract.inspect()).toMatchObject({ - data: expect.any(Object), + tables: expect.any(Object), requests: expect.any(Object), }); }); diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index a41f97118c4b2..a1b25c3802f4b 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -21,8 +21,9 @@ import type { KibanaRequest } from 'src/core/server'; import { ExpressionType, SerializableState } from '../expression_types'; -import { Adapters, DataAdapter, RequestAdapter } from '../../../inspector/common'; +import { Adapters, RequestAdapter } from '../../../inspector/common'; import { SavedObject, SavedObjectAttributes } from '../../../../core/public'; +import { TablesAdapter } from '../util/tables_adapter'; /** * `ExecutionContext` is an object available to all functions during a single execution; @@ -89,5 +90,5 @@ export interface ExecutionContext< */ export interface DefaultInspectorAdapters extends Adapters { requests: RequestAdapter; - data: DataAdapter; + tables: TablesAdapter; } diff --git a/src/plugins/expressions/common/expression_renderers/types.ts b/src/plugins/expressions/common/expression_renderers/types.ts index 88aca4c07ee31..3f3cfb9ed2dd9 100644 --- a/src/plugins/expressions/common/expression_renderers/types.ts +++ b/src/plugins/expressions/common/expression_renderers/types.ts @@ -17,8 +17,6 @@ * under the License. */ -import { PersistedState } from 'src/plugins/visualizations/public'; - export interface ExpressionRenderDefinition { /** * Technical name of the renderer, used as ID to identify renderer in @@ -84,5 +82,11 @@ export interface IInterpreterRenderHandlers { event: (event: any) => void; hasCompatibleActions?: (event: any) => Promise; getRenderMode: () => RenderMode; - uiState?: PersistedState; + isSyncColorsEnabled: () => boolean; + /** + * This uiState interface is actually `PersistedState` from the visualizations plugin, + * but expressions cannot know about vis or it creates a mess of circular dependencies. + * Downstream consumers of the uiState handler will need to cast for now. + */ + uiState?: unknown; } diff --git a/src/plugins/expressions/common/util/index.ts b/src/plugins/expressions/common/util/index.ts index ee677d54ce968..ea900687650f8 100644 --- a/src/plugins/expressions/common/util/index.ts +++ b/src/plugins/expressions/common/util/index.ts @@ -19,3 +19,4 @@ export * from './create_error'; export * from './get_by_alias'; +export * from './tables_adapter'; diff --git a/test/functional/apps/getting_started/index.js b/src/plugins/expressions/common/util/tables_adapter.ts similarity index 66% rename from test/functional/apps/getting_started/index.js rename to src/plugins/expressions/common/util/tables_adapter.ts index 399d3fe87484b..30b869818f999 100644 --- a/test/functional/apps/getting_started/index.js +++ b/src/plugins/expressions/common/util/tables_adapter.ts @@ -17,16 +17,18 @@ * under the License. */ -export default function ({ getService, loadTestFile }) { - const browser = getService('browser'); +import { EventEmitter } from 'events'; +import { Datatable } from '../expression_types/specs'; - describe('Getting Started ', function () { - this.tags(['ciGroup6']); +export class TablesAdapter extends EventEmitter { + private _tables: { [key: string]: Datatable } = {}; - before(async function () { - await browser.setWindowSize(1200, 800); - }); - // https://www.elastic.co/guide/en/kibana/current/tutorial-load-dataset.html - loadTestFile(require.resolve('./_shakespeare')); - }); + public logDatatable(name: string, datatable: Datatable): void { + this._tables[name] = datatable; + this.emit('change', this.tables); + } + + public get tables() { + return this._tables; + } } diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 385055bc2fdc2..cd43c90d5ff45 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -117,4 +117,5 @@ export { ExpressionsService, ExpressionsServiceSetup, ExpressionsServiceStart, + TablesAdapter, } from '../common'; diff --git a/src/plugins/expressions/public/loader.test.ts b/src/plugins/expressions/public/loader.test.ts index 598b614a326a9..0508b36fad385 100644 --- a/src/plugins/expressions/public/loader.test.ts +++ b/src/plugins/expressions/public/loader.test.ts @@ -166,7 +166,7 @@ describe('ExpressionLoader', () => { it('inspect() returns correct inspector adapters', () => { const expressionDataHandler = new ExpressionLoader(element, expressionString, {}); - expect(expressionDataHandler.inspect()).toHaveProperty('data'); + expect(expressionDataHandler.inspect()).toHaveProperty('tables'); expect(expressionDataHandler.inspect()).toHaveProperty('requests'); }); }); diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index e9e0fa18af6c3..1cf499ce2635a 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -64,6 +64,7 @@ export class ExpressionLoader { this.renderHandler = new ExpressionRenderHandler(element, { onRenderError: params && params.onRenderError, renderMode: params?.renderMode, + syncColors: params?.syncColors, hasCompatibleActions: params?.hasCompatibleActions, }); this.render$ = this.renderHandler.render$; diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md index 6eb0e71c58e3f..5c018adc0131b 100644 --- a/src/plugins/expressions/public/public.api.md +++ b/src/plugins/expressions/public/public.api.md @@ -12,7 +12,6 @@ import { EventEmitter } from 'events'; import { KibanaRequest } from 'src/core/server'; import { Observable } from 'rxjs'; import { PackageInfo } from '@kbn/config'; -import { PersistedState } from 'src/plugins/visualizations/public'; import { Plugin as Plugin_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import React from 'react'; @@ -532,7 +531,7 @@ export interface ExpressionRenderError extends Error { // @public (undocumented) export class ExpressionRenderHandler { // Warning: (ae-forgotten-export) The symbol "ExpressionRenderHandlerParams" needs to be exported by the entry point index.d.ts - constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActions, }?: ExpressionRenderHandlerParams); + constructor(element: HTMLElement, { onRenderError, renderMode, syncColors, hasCompatibleActions, }?: ExpressionRenderHandlerParams); // (undocumented) destroy: () => void; // (undocumented) @@ -904,6 +903,8 @@ export interface IExpressionLoaderParams { // (undocumented) searchSessionId?: string; // (undocumented) + syncColors?: boolean; + // (undocumented) uiState?: unknown; // (undocumented) variables?: Record; @@ -921,11 +922,12 @@ export interface IInterpreterRenderHandlers { // (undocumented) hasCompatibleActions?: (event: any) => Promise; // (undocumented) + isSyncColorsEnabled: () => boolean; + // (undocumented) onDestroy: (fn: () => void) => void; // (undocumented) reload: () => void; - // (undocumented) - uiState?: PersistedState; + uiState?: unknown; // (undocumented) update: (params: any) => void; } @@ -1096,6 +1098,18 @@ export interface SerializedFieldFormat> { // @public (undocumented) export type Style = ExpressionTypeStyle; +// Warning: (ae-missing-release-tag) "TablesAdapter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class TablesAdapter extends EventEmitter { + // (undocumented) + logDatatable(name: string, datatable: Datatable): void; + // (undocumented) + get tables(): { + [key: string]: Datatable; + }; + } + // Warning: (ae-missing-release-tag) "TextAlignment" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/src/plugins/expressions/public/react_expression_renderer.test.tsx b/src/plugins/expressions/public/react_expression_renderer.test.tsx index e52d4d153882f..d9a4f095127b8 100644 --- a/src/plugins/expressions/public/react_expression_renderer.test.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.test.tsx @@ -146,6 +146,73 @@ describe('ExpressionRenderer', () => { instance.unmount(); }); + it('should not update twice immediately after rendering', () => { + jest.useFakeTimers(); + + const refreshSubject = new Subject(); + const loaderUpdate = jest.fn(); + + (ExpressionLoader as jest.Mock).mockImplementation(() => { + return { + render$: new Subject(), + data$: new Subject(), + loading$: new Subject(), + update: loaderUpdate, + destroy: jest.fn(), + }; + }); + + const instance = mount( + + ); + + act(() => { + jest.runAllTimers(); + }); + + expect(loaderUpdate).toHaveBeenCalledTimes(1); + + instance.unmount(); + }); + + it('waits for debounce period on other loader option change if specified', () => { + jest.useFakeTimers(); + + const refreshSubject = new Subject(); + const loaderUpdate = jest.fn(); + + (ExpressionLoader as jest.Mock).mockImplementation(() => { + return { + render$: new Subject(), + data$: new Subject(), + loading$: new Subject(), + update: loaderUpdate, + destroy: jest.fn(), + }; + }); + + const instance = mount( + + ); + + instance.setProps({ searchContext: { from: 'now-30m', to: 'now' } }); + + expect(loaderUpdate).toHaveBeenCalledTimes(1); + + act(() => { + jest.runAllTimers(); + }); + + expect(loaderUpdate).toHaveBeenCalledTimes(2); + + instance.unmount(); + }); + it('should display a custom error message if the user provides one and then remove it after successful render', () => { const dataSubject = new Subject(); const data$ = dataSubject.asObservable().pipe(share()); @@ -266,4 +333,22 @@ describe('ExpressionRenderer', () => { expect(onEvent).toHaveBeenCalledTimes(1); expect(onEvent.mock.calls[0][0]).toBe(event); }); + + it('should correctly assign classes to the wrapper node', () => { + (ExpressionLoader as jest.Mock).mockImplementation(() => { + return { + render$: new Subject(), + data$: new Subject(), + loading$: new Subject(), + update: jest.fn(), + destroy: jest.fn(), + }; + }); + + const instance = mount(); + // Counte is 2 because the class is applied to ReactExpressionRenderer + internal component + expect(instance.find('.myClassName').length).toBe(2); + + instance.unmount(); + }); }); diff --git a/src/plugins/expressions/public/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer.tsx index 894325c8b65f7..caa8e209ec170 100644 --- a/src/plugins/expressions/public/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.tsx @@ -90,21 +90,28 @@ export const ReactExpressionRenderer = ({ null ); const [debouncedExpression, setDebouncedExpression] = useState(expression); - useEffect(() => { + const [waitingForDebounceToComplete, setDebouncePending] = useState(false); + const firstRender = useRef(true); + useShallowCompareEffect(() => { + if (firstRender.current) { + firstRender.current = false; + return; + } if (debounce === undefined) { return; } + setDebouncePending(true); const handler = setTimeout(() => { setDebouncedExpression(expression); + setDebouncePending(false); }, debounce); return () => { clearTimeout(handler); }; - }, [expression, debounce]); + }, [expression, expressionLoaderOptions, debounce]); const activeExpression = debounce !== undefined ? debouncedExpression : expression; - const waitingForDebounceToComplete = debounce !== undefined && expression !== debouncedExpression; /* eslint-disable react-hooks/exhaustive-deps */ // OK to ignore react-hooks/exhaustive-deps because options update is handled by calling .update() @@ -168,7 +175,12 @@ export const ReactExpressionRenderer = ({ errorRenderHandlerRef.current = null; }; - }, [hasCustomRenderErrorHandler, onEvent]); + }, [ + hasCustomRenderErrorHandler, + onEvent, + expressionLoaderOptions.renderMode, + expressionLoaderOptions.syncColors, + ]); useEffect(() => { const subscription = reload$?.subscribe(() => { @@ -182,12 +194,16 @@ export const ReactExpressionRenderer = ({ // Re-fetch data automatically when the inputs change useShallowCompareEffect( () => { - if (expressionLoaderRef.current) { + // only update the loader if the debounce period is over + if (expressionLoaderRef.current && !waitingForDebounceToComplete) { expressionLoaderRef.current.update(activeExpression, expressionLoaderOptions); } }, - // when expression is changed by reference and when any other loaderOption is changed by reference - [{ activeExpression, ...expressionLoaderOptions }] + // when debounced, wait for debounce status to change to update loader. + // Otherwise, update when expression is changed by reference and when any other loaderOption is changed by reference + debounce === undefined + ? [{ activeExpression, ...expressionLoaderOptions }] + : [{ waitingForDebounceToComplete }] ); /* eslint-enable react-hooks/exhaustive-deps */ @@ -200,10 +216,9 @@ export const ReactExpressionRenderer = ({ } }, [state.error]); - const classes = classNames('expExpressionRenderer', { + const classes = classNames('expExpressionRenderer', className, { 'expExpressionRenderer-isEmpty': state.isEmpty, 'expExpressionRenderer-hasError': !!state.error, - className, }); const expressionStyles: React.CSSProperties = {}; diff --git a/src/plugins/expressions/public/render.ts b/src/plugins/expressions/public/render.ts index 717776a2861b4..e3091b908deca 100644 --- a/src/plugins/expressions/public/render.ts +++ b/src/plugins/expressions/public/render.ts @@ -31,6 +31,7 @@ export type IExpressionRendererExtraHandlers = Record; export interface ExpressionRenderHandlerParams { onRenderError?: RenderErrorHandlerFnType; renderMode?: RenderMode; + syncColors?: boolean; hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise; } @@ -63,6 +64,7 @@ export class ExpressionRenderHandler { { onRenderError, renderMode, + syncColors, hasCompatibleActions = async () => false, }: ExpressionRenderHandlerParams = {} ) { @@ -101,6 +103,9 @@ export class ExpressionRenderHandler { getRenderMode: () => { return renderMode || 'display'; }, + isSyncColorsEnabled: () => { + return syncColors || false; + }, hasCompatibleActions, }; } diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index f37107abbb716..d709d8ca96bbd 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -57,6 +57,7 @@ export interface IExpressionLoaderParams { onRenderError?: RenderErrorHandlerFnType; searchSessionId?: string; renderMode?: RenderMode; + syncColors?: boolean; hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions']; } diff --git a/src/plugins/expressions/server/server.api.md b/src/plugins/expressions/server/server.api.md index 7c1ab11f75027..71199560ee0c7 100644 --- a/src/plugins/expressions/server/server.api.md +++ b/src/plugins/expressions/server/server.api.md @@ -10,7 +10,6 @@ import { Ensure } from '@kbn/utility-types'; import { EventEmitter } from 'events'; import { KibanaRequest } from 'src/core/server'; import { Observable } from 'rxjs'; -import { PersistedState } from 'src/plugins/visualizations/public'; import { Plugin as Plugin_2 } from 'src/core/server'; import { PluginInitializerContext } from 'src/core/server'; import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; @@ -738,11 +737,12 @@ export interface IInterpreterRenderHandlers { // (undocumented) hasCompatibleActions?: (event: any) => Promise; // (undocumented) + isSyncColorsEnabled: () => boolean; + // (undocumented) onDestroy: (fn: () => void) => void; // (undocumented) reload: () => void; - // (undocumented) - uiState?: PersistedState; + uiState?: unknown; // (undocumented) update: (params: any) => void; } 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 60d05890028d1..5cb837f816ff2 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 @@ -34,7 +34,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[eCommerce] Sales by Category', }), visState: - '{"title":"[eCommerce] Sales by Category","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Sum of total_quantity"}}],"seriesParams":[{"show":"true","type":"area","mode":"stacked","data":{"label":"Sum of total_quantity","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"linear","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":true,"legendPosition":"top","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"sum","schema":"metric","params":{"field":"total_quantity"}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"order_date","interval":"auto","time_zone":"America/New_York","drop_partials":false,"customInterval":"2h","min_doc_count":1,"extended_bounds":{}}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"category.keyword","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}', + '{"title":"[eCommerce] Sales by Category","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Sum of total_quantity"}}],"seriesParams":[{"show":"true","type":"area","mode":"stacked","data":{"label":"Sum of total_quantity","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"linear","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":true,"legendPosition":"top","times":[],"addTimeMarker":false,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"sum","schema":"metric","params":{"field":"total_quantity"}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"order_date","interval":"auto","drop_partials":false,"min_doc_count":1,"extended_bounds":{}}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"category.keyword","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}', uiStateJSON: '{}', description: '', version: 1, diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts index e65b6ad40651b..6b06a526a1239 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts @@ -56,7 +56,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Flights] Flight Count and Average Ticket Price', }), visState: - '{"title":"[Flights] Flight Count and Average Ticket Price","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Average Ticket Price"}},{"id":"ValueAxis-2","name":"RightAxis-1","type":"value","position":"right","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Flight Count"}}],"seriesParams":[{"show":true,"mode":"stacked","type":"area","drawLinesBetweenPoints":true,"showCircles":false,"interpolate":"linear","lineWidth":2,"data":{"id":"5","label":"Flight Count"},"valueAxis":"ValueAxis-2"},{"show":true,"mode":"stacked","type":"line","drawLinesBetweenPoints":false,"showCircles":true,"interpolate":"linear","data":{"id":"4","label":"Average Ticket Price"},"valueAxis":"ValueAxis-1","lineWidth":2}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"radiusRatio":13},"aggs":[{"id":"3","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}},{"id":"5","enabled":true,"type":"count","schema":"metric","params":{"customLabel":"Flight Count"}},{"id":"4","enabled":true,"type":"avg","schema":"metric","params":{"field":"AvgTicketPrice","customLabel":"Average Ticket Price"}},{"id":"2","enabled":true,"type":"avg","schema":"radius","params":{"field":"AvgTicketPrice"}}]}', + '{"title":"[Flights] Flight Count and Average Ticket Price","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Average Ticket Price"}},{"id":"ValueAxis-2","name":"RightAxis-1","type":"value","position":"right","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Flight Count"}}],"seriesParams":[{"show":true,"mode":"stacked","type":"area","drawLinesBetweenPoints":true,"showCircles":false,"interpolate":"linear","lineWidth":2,"data":{"id":"5","label":"Flight Count"},"valueAxis":"ValueAxis-2"},{"show":true,"mode":"stacked","type":"line","drawLinesBetweenPoints":false,"showCircles":true,"interpolate":"linear","data":{"id":"4","label":"Average Ticket Price"},"valueAxis":"ValueAxis-1","lineWidth":2}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"radiusRatio":13,"detailedTooltip":true},"aggs":[{"id":"3","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","min_doc_count":1,"extended_bounds":{}}},{"id":"5","enabled":true,"type":"count","schema":"metric","params":{"customLabel":"Flight Count"}},{"id":"4","enabled":true,"type":"avg","schema":"metric","params":{"field":"AvgTicketPrice","customLabel":"Average Ticket Price"}},{"id":"2","enabled":true,"type":"avg","schema":"radius","params":{"field":"AvgTicketPrice"}}]}', uiStateJSON: '{"vis":{"legendOpen":true,"colors":{"Average Ticket Price":"#629E51","Flight Count":"#AEA2E0"}}}', description: '', @@ -133,7 +133,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Flights] Delay Type', }), visState: - '{"title":"[Flights] Delay Type","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"cardinal","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"FlightDelayType","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}', + '{"title":"[Flights] Delay Type","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"cardinal","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","min_doc_count":1,"extended_bounds":{}}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"FlightDelayType","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}', uiStateJSON: '{}', description: '', version: 1, @@ -176,7 +176,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Flights] Delay Buckets', }), visState: - '{"title":"[Flights] Delay Buckets","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"histogram","schema":"segment","params":{"field":"FlightDelayMin","interval":30,"extended_bounds":{},"customLabel":"Flight Delay Minutes"}}]}', + '{"title":"[Flights] Delay Buckets","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"histogram","schema":"segment","params":{"field":"FlightDelayMin","interval":30,"extended_bounds":{},"customLabel":"Flight Delay Minutes"}}]}', uiStateJSON: '{"vis":{"legendOpen":false}}', description: '', version: 1, @@ -198,7 +198,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Flights] Flight Delays', }), visState: - '{"title":"[Flights] Flight Delays","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"left","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"BottomAxis-1","type":"value","position":"bottom","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{"customLabel":""}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"FlightDelay","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"Flight Delays"}}]}', + '{"title":"[Flights] Flight Delays","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"left","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"BottomAxis-1","type":"value","position":"bottom","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{"customLabel":""}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"FlightDelay","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"Flight Delays"}}]}', uiStateJSON: '{}', description: '', version: 1, @@ -220,7 +220,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Flights] Flight Cancellations', }), visState: - '{"title":"[Flights] Flight Cancellations","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"left","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"BottomAxis-1","type":"value","position":"bottom","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{"customLabel":""}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"Cancelled","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"Flight Cancellations"}}]}', + '{"title":"[Flights] Flight Cancellations","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"left","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"BottomAxis-1","type":"value","position":"bottom","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{"customLabel":""}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"Cancelled","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"Flight Cancellations"}}]}', uiStateJSON: '{}', description: '', version: 1, diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts index 068ba66c4b0de..7b891107cdfb0 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts @@ -33,7 +33,7 @@ export const getSavedObjects = (): SavedObject[] => [ defaultMessage: '[Logs] Unique Visitors vs. Average Bytes', }), visState: - '{"title":"[Logs] Unique Visitors vs. Average Bytes","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Avg. Bytes"}},{"id":"ValueAxis-2","name":"RightAxis-1","type":"value","position":"right","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Unique Visitors"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Avg. Bytes","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"linear","valueAxis":"ValueAxis-1"},{"show":true,"mode":"stacked","type":"line","drawLinesBetweenPoints":false,"showCircles":true,"interpolate":"linear","data":{"id":"2","label":"Unique Visitors"},"valueAxis":"ValueAxis-2"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"radiusRatio":17},"aggs":[{"id":"1","enabled":true,"type":"avg","schema":"metric","params":{"field":"bytes","customLabel":"Avg. Bytes"}},{"id":"2","enabled":true,"type":"cardinality","schema":"metric","params":{"field":"clientip","customLabel":"Unique Visitors"}},{"id":"3","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","time_zone":"America/Los_Angeles","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}},{"id":"4","enabled":true,"type":"count","schema":"radius","params":{}}]}', + '{"title":"[Logs] Unique Visitors vs. Average Bytes","type":"area","params":{"type":"area","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100,"filter":true},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Avg. Bytes"}},{"id":"ValueAxis-2","name":"RightAxis-1","type":"value","position":"right","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Unique Visitors"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Avg. Bytes","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"linear","valueAxis":"ValueAxis-1"},{"show":true,"mode":"stacked","type":"line","drawLinesBetweenPoints":false,"showCircles":true,"interpolate":"linear","data":{"id":"2","label":"Unique Visitors"},"valueAxis":"ValueAxis-2"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false,"radiusRatio":17,"detailedTooltip":true},"aggs":[{"id":"1","enabled":true,"type":"avg","schema":"metric","params":{"field":"bytes","customLabel":"Avg. Bytes"}},{"id":"2","enabled":true,"type":"cardinality","schema":"metric","params":{"field":"clientip","customLabel":"Unique Visitors"}},{"id":"3","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"timestamp","interval":"auto","min_doc_count":1,"extended_bounds":{}}},{"id":"4","enabled":true,"type":"count","schema":"radius","params":{}}]}', uiStateJSON: '{"vis":{"colors":{"Avg. Bytes":"#70DBED","Unique Visitors":"#0A437C"}}}', description: '', version: 1, diff --git a/src/plugins/home/server/services/sample_data/usage/collector_fetch.test.ts b/src/plugins/home/server/services/sample_data/usage/collector_fetch.test.ts index 54fed3db1de4d..58bb037f8d614 100644 --- a/src/plugins/home/server/services/sample_data/usage/collector_fetch.test.ts +++ b/src/plugins/home/server/services/sample_data/usage/collector_fetch.test.ts @@ -23,7 +23,7 @@ import { fetchProvider } from './collector_fetch'; const getMockFetchClients = (hits?: unknown[]) => { const fetchParamsMock = createCollectorFetchContextMock(); - fetchParamsMock.callCluster.mockResolvedValue({ hits: { hits } }); + fetchParamsMock.esClient.search = jest.fn().mockResolvedValue({ body: { hits: { hits } } }); return fetchParamsMock; }; diff --git a/src/plugins/home/server/services/sample_data/usage/collector_fetch.ts b/src/plugins/home/server/services/sample_data/usage/collector_fetch.ts index 7df9b14d2efb1..ef958873d9663 100644 --- a/src/plugins/home/server/services/sample_data/usage/collector_fetch.ts +++ b/src/plugins/home/server/services/sample_data/usage/collector_fetch.ts @@ -19,6 +19,7 @@ import { get } from 'lodash'; import moment from 'moment'; +import { SearchResponse } from 'src/core/server'; import { CollectorFetchContext } from '../../../../../usage_collection/server'; interface SearchHit { @@ -41,17 +42,23 @@ export interface TelemetryResponse { last_uninstall_set: string | null; } +type ESResponse = SearchResponse; + export function fetchProvider(index: string) { - return async ({ callCluster }: CollectorFetchContext) => { - const response = await callCluster('search', { - index, - body: { - query: { term: { type: { value: 'sample-data-telemetry' } } }, - _source: { includes: ['sample-data-telemetry', 'type', 'updated_at'] }, + return async ({ esClient }: CollectorFetchContext) => { + const { body: response } = await esClient.search( + { + index, + body: { + query: { term: { type: { value: 'sample-data-telemetry' } } }, + _source: { includes: ['sample-data-telemetry', 'type', 'updated_at'] }, + }, + filter_path: 'hits.hits._id,hits.hits._source', }, - filter_path: 'hits.hits._id,hits.hits._source', - ignore: [404], - }); + { + ignore: [404], + } + ); const getLast = ( dataSet: string, diff --git a/src/plugins/inspector/common/adapters/data/data_adapters.test.ts b/src/plugins/inspector/common/adapters/data/data_adapters.test.ts deleted file mode 100644 index 7cc52807548f0..0000000000000 --- a/src/plugins/inspector/common/adapters/data/data_adapters.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { DataAdapter } from './data_adapter'; - -describe('DataAdapter', () => { - let adapter: DataAdapter; - - beforeEach(() => { - adapter = new DataAdapter(); - }); - - describe('getTabular()', () => { - it('should return a null promise when called before initialized', () => { - expect(adapter.getTabular()).resolves.toEqual({ - data: null, - options: {}, - }); - }); - - it('should call the provided callback and resolve with its value', async () => { - const data = { columns: [], rows: [] }; - const spy = jest.fn(() => data); - adapter.setTabularLoader(spy); - expect(spy).not.toBeCalled(); - const result = await adapter.getTabular(); - expect(spy).toBeCalled(); - expect(result.data).toBe(data); - }); - - it('should pass through options specified via setTabularLoader', async () => { - const data = { columns: [], rows: [] }; - adapter.setTabularLoader(() => data, { returnsFormattedValues: true }); - const result = await adapter.getTabular(); - expect(result.options).toEqual({ returnsFormattedValues: true }); - }); - - it('should return options set when starting loading data', async () => { - const data = { columns: [], rows: [] }; - adapter.setTabularLoader(() => data, { returnsFormattedValues: true }); - const waitForResult = adapter.getTabular(); - adapter.setTabularLoader(() => data, { returnsFormattedValues: false }); - const result = await waitForResult; - expect(result.options).toEqual({ returnsFormattedValues: true }); - }); - }); - - it('should emit a "tabular" event when a new tabular loader is specified', () => { - const data = { columns: [], rows: [] }; - const spy = jest.fn(); - adapter.once('change', spy); - adapter.setTabularLoader(() => data); - expect(spy).toBeCalled(); - }); -}); diff --git a/src/plugins/inspector/common/adapters/index.ts b/src/plugins/inspector/common/adapters/index.ts index 0c6319a2905a8..152d7c54d7d84 100644 --- a/src/plugins/inspector/common/adapters/index.ts +++ b/src/plugins/inspector/common/adapters/index.ts @@ -17,6 +17,5 @@ * under the License. */ -export * from './data'; export * from './request'; export * from './types'; diff --git a/src/plugins/inspector/common/adapters/types.ts b/src/plugins/inspector/common/adapters/types.ts index b51c3e56c749f..ee56c994be469 100644 --- a/src/plugins/inspector/common/adapters/types.ts +++ b/src/plugins/inspector/common/adapters/types.ts @@ -17,14 +17,12 @@ * under the License. */ -import type { DataAdapter } from './data'; import type { RequestAdapter } from './request'; /** * The interface that the adapters used to open an inspector have to fullfill. */ export interface Adapters { - data?: DataAdapter; requests?: RequestAdapter; [key: string]: any; } diff --git a/src/plugins/inspector/common/index.ts b/src/plugins/inspector/common/index.ts index c5755b22095dc..f9f486521a76b 100644 --- a/src/plugins/inspector/common/index.ts +++ b/src/plugins/inspector/common/index.ts @@ -19,15 +19,9 @@ export { Adapters, - DataAdapter, - FormattedData, RequestAdapter, RequestStatistic, RequestStatistics, RequestStatus, RequestResponder, - TabularData, - TabularDataColumn, - TabularDataRow, - TabularDataValue, } from './adapters'; diff --git a/src/plugins/inspector/public/plugin.tsx b/src/plugins/inspector/public/plugin.tsx index 07ef7c8fbab0d..d3d867344a2a8 100644 --- a/src/plugins/inspector/public/plugin.tsx +++ b/src/plugins/inspector/public/plugin.tsx @@ -26,7 +26,7 @@ import { InspectorOptions, InspectorSession } from './types'; import { InspectorPanel } from './ui/inspector_panel'; import { Adapters } from '../common'; -import { getRequestsViewDescription, getDataViewDescription } from './views'; +import { getRequestsViewDescription } from './views'; export interface Setup { registerView: InspectorViewRegistry['register']; @@ -70,7 +70,6 @@ export class InspectorPublicPlugin implements Plugin { public async setup(core: CoreSetup) { this.views = new InspectorViewRegistry(); - this.views.register(getDataViewDescription()); this.views.register(getRequestsViewDescription()); return { diff --git a/src/plugins/inspector/public/test/is_available.test.ts b/src/plugins/inspector/public/test/is_available.test.ts index c38d9d7a3f825..1f5220fc07a63 100644 --- a/src/plugins/inspector/public/test/is_available.test.ts +++ b/src/plugins/inspector/public/test/is_available.test.ts @@ -18,19 +18,12 @@ */ import { inspectorPluginMock } from '../mocks'; -import { DataAdapter, RequestAdapter } from '../../common/adapters'; +import { RequestAdapter } from '../../common/adapters'; -const adapter1 = new DataAdapter(); const adapter2 = new RequestAdapter(); describe('inspector', () => { describe('isAvailable()', () => { - it('should return false if no view would be available', async () => { - const { doStart } = await inspectorPluginMock.createPlugin(); - const start = await doStart(); - expect(start.isAvailable({ adapter1 })).toBe(false); - }); - it('should return true if views would be available, false otherwise', async () => { const { setup, doStart } = await inspectorPluginMock.createPlugin(); @@ -44,7 +37,6 @@ describe('inspector', () => { const start = await doStart(); - expect(start.isAvailable({ adapter1 })).toBe(true); expect(start.isAvailable({ adapter2 })).toBe(false); }); }); diff --git a/src/plugins/inspector/public/views/_index.scss b/src/plugins/inspector/public/views/_index.scss index 620a33e965840..43fbc09e921cc 100644 --- a/src/plugins/inspector/public/views/_index.scss +++ b/src/plugins/inspector/public/views/_index.scss @@ -1,2 +1 @@ -@import './data/index'; @import './requests/index'; diff --git a/src/plugins/inspector/public/views/data/components/data_view.tsx b/src/plugins/inspector/public/views/data/components/data_view.tsx deleted file mode 100644 index 324094d8f93d0..0000000000000 --- a/src/plugins/inspector/public/views/data/components/data_view.tsx +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingChart, - EuiPanel, - EuiSpacer, - EuiText, -} from '@elastic/eui'; - -import { DataTableFormat } from './data_table'; -import { InspectorViewProps } from '../../../types'; -import { Adapters } from '../../../../common'; -import { - TabularLoaderOptions, - TabularData, - TabularHolder, -} from '../../../../common/adapters/data/types'; -import { IUiSettingsClient } from '../../../../../../core/public'; -import { withKibana, KibanaReactContextValue } from '../../../../../kibana_react/public'; - -interface DataViewComponentState { - tabularData: TabularData | null; - tabularOptions: TabularLoaderOptions; - adapters: Adapters; - tabularPromise: Promise | null; -} - -interface DataViewComponentProps extends InspectorViewProps { - kibana: KibanaReactContextValue<{ uiSettings: IUiSettingsClient }>; -} - -class DataViewComponent extends Component { - static propTypes = { - adapters: PropTypes.object.isRequired, - title: PropTypes.string.isRequired, - kibana: PropTypes.object, - }; - - state = {} as DataViewComponentState; - _isMounted = false; - - static getDerivedStateFromProps( - nextProps: DataViewComponentProps, - state: DataViewComponentState - ) { - if (state && nextProps.adapters === state.adapters) { - return null; - } - - return { - adapters: nextProps.adapters, - tabularData: null, - tabularOptions: {}, - tabularPromise: nextProps.adapters.data!.getTabular(), - }; - } - - onUpdateData = (type: string) => { - if (type === 'tabular') { - this.setState({ - tabularData: null, - tabularOptions: {}, - tabularPromise: this.props.adapters.data!.getTabular(), - }); - } - }; - - async finishLoadingData() { - const { tabularPromise } = this.state; - - if (tabularPromise) { - const tabularData: TabularHolder = await tabularPromise; - - if (this._isMounted) { - this.setState({ - tabularData: tabularData.data, - tabularOptions: tabularData.options, - tabularPromise: null, - }); - } - } - } - - componentDidMount() { - this._isMounted = true; - this.props.adapters.data!.on('change', this.onUpdateData); - this.finishLoadingData(); - } - - componentWillUnmount() { - this._isMounted = false; - this.props.adapters.data!.removeListener('change', this.onUpdateData); - } - - componentDidUpdate() { - this.finishLoadingData(); - } - - static renderNoData() { - return ( - - - - } - body={ - -

- -

-
- } - /> - ); - } - - static renderLoading() { - return ( - - - - - - -

- -

-
-
-
-
- ); - } - - render() { - if (this.state.tabularPromise) { - return DataViewComponent.renderLoading(); - } else if (!this.state.tabularData) { - return DataViewComponent.renderNoData(); - } - - return ( - - ); - } -} - -// default export required for React.Lazy -// eslint-disable-next-line import/no-default-export -export default withKibana(DataViewComponent); diff --git a/src/plugins/inspector/public/views/index.ts b/src/plugins/inspector/public/views/index.ts index c75ecfbd3e998..8aef30a68a327 100644 --- a/src/plugins/inspector/public/views/index.ts +++ b/src/plugins/inspector/public/views/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { getDataViewDescription } from './data'; export { getRequestsViewDescription } from './requests'; diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts index a7681e1766427..64f1088dc3392 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts @@ -16,14 +16,25 @@ * specific language governing permissions and limitations * under the License. */ - +import { elasticsearchServiceMock } from '../../../../../../src/core/server/mocks'; import { getSavedObjectsCounts } from './get_saved_object_counts'; +export function mockGetSavedObjectsCounts(params: any) { + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + esClient.search.mockResolvedValue( + // @ts-ignore we only care about the response body + { + body: { ...params }, + } + ); + return esClient; +} + describe('getSavedObjectsCounts', () => { test('Get all the saved objects equal to 0 because no results were found', async () => { - const callCluster = jest.fn(() => ({})); + const esClient = mockGetSavedObjectsCounts({}); - const results = await getSavedObjectsCounts(callCluster as any, '.kibana'); + const results = await getSavedObjectsCounts(esClient, '.kibana'); expect(results).toStrictEqual({ dashboard: { total: 0 }, visualization: { total: 0 }, @@ -35,7 +46,7 @@ describe('getSavedObjectsCounts', () => { }); test('Merge the zeros with the results', async () => { - const callCluster = jest.fn(() => ({ + const esClient = mockGetSavedObjectsCounts({ aggregations: { types: { buckets: [ @@ -46,9 +57,9 @@ describe('getSavedObjectsCounts', () => { ], }, }, - })); + }); - const results = await getSavedObjectsCounts(callCluster as any, '.kibana'); + const results = await getSavedObjectsCounts(esClient, '.kibana'); expect(results).toStrictEqual({ dashboard: { total: 1 }, visualization: { total: 0 }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts index e88d90fe5b24b..65cc3643a88cb 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.ts @@ -27,7 +27,7 @@ */ import { snakeCase } from 'lodash'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'src/core/server'; const TYPES = [ 'dashboard', @@ -48,7 +48,7 @@ export interface KibanaSavedObjectCounts { } export async function getSavedObjectsCounts( - callCluster: LegacyAPICaller, + esClient: ElasticsearchClient, kibanaIndex: string // Typically '.kibana'. We might need a way to obtain it from the SavedObjects client (or the SavedObjects client to provide a way to run aggregations?) ): Promise { const savedObjectCountSearchParams = { @@ -67,9 +67,9 @@ export async function getSavedObjectsCounts( }, }, }; - const resp = await callCluster('search', savedObjectCountSearchParams); + const { body } = await esClient.search(savedObjectCountSearchParams); const buckets: Array<{ key: string; doc_count: number }> = - resp.aggregations?.types?.buckets || []; + body.aggregations?.types?.buckets || []; // Initialise the object with all zeros for all the types const allZeros: KibanaSavedObjectCounts = TYPES.reduce( diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts index 83cac1d456a3a..dee9ca4d32c5f 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts @@ -20,12 +20,13 @@ import { loggingSystemMock, pluginInitializerContextConfigMock, + elasticsearchServiceMock, } from '../../../../../core/server/mocks'; import { Collector, + createCollectorFetchContextMock, createUsageCollectionSetupMock, } from '../../../../usage_collection/server/usage_collection.mock'; -import { createCollectorFetchContextMock } from '../../../../usage_collection/server/mocks'; import { registerKibanaUsageCollector } from './'; const logger = loggingSystemMock.createLogger(); @@ -43,7 +44,9 @@ describe('telemetry_kibana', () => { const getMockFetchClients = (hits?: unknown[]) => { const fetchParamsMock = createCollectorFetchContextMock(); - fetchParamsMock.callCluster.mockResolvedValue({ hits: { hits } }); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + esClient.search.mockResolvedValue({ body: { hits: { hits } } } as any); + fetchParamsMock.esClient = esClient; return fetchParamsMock; }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts index 6c2e0a2c926ad..5dd39d172e1c2 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts @@ -43,13 +43,13 @@ export function getKibanaUsageCollector( graph_workspace: { total: { type: 'long' } }, timelion_sheet: { total: { type: 'long' } }, }, - async fetch({ callCluster }) { + async fetch({ esClient }) { const { kibana: { index }, } = await legacyConfig$.pipe(take(1)).toPromise(); return { index, - ...(await getSavedObjectsCounts(callCluster, index)), + ...(await getSavedObjectsCounts(esClient, index)), }; }, }); diff --git a/src/plugins/kibana_utils/server/index.ts b/src/plugins/kibana_utils/server/index.ts index d994a4940bdfd..a0e933f997dd5 100644 --- a/src/plugins/kibana_utils/server/index.ts +++ b/src/plugins/kibana_utils/server/index.ts @@ -28,3 +28,5 @@ export { Set, url, } from '../common'; + +export { KbnServerError, reportServerError } from './report_server_error'; diff --git a/src/plugins/kibana_utils/server/report_server_error.ts b/src/plugins/kibana_utils/server/report_server_error.ts new file mode 100644 index 0000000000000..43b4dba3d039b --- /dev/null +++ b/src/plugins/kibana_utils/server/report_server_error.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { KibanaResponseFactory } from 'kibana/server'; +import { KbnError } from '../common'; + +export class KbnServerError extends KbnError { + constructor(message: string, public readonly statusCode: number) { + super(message); + } +} + +export function reportServerError(res: KibanaResponseFactory, err: any) { + return res.customError({ + statusCode: err.statusCode ?? 500, + body: { + message: err.message, + attributes: { + error: err.body?.error || err.message, + }, + }, + }); +} diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index bf03c649fa6b4..81026927380e0 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -58,11 +58,12 @@ export class ManagementPlugin implements Plugin ({ diff --git a/src/plugins/region_map/public/region_map_fn.js b/src/plugins/region_map/public/region_map_fn.js index fdb7c273720fa..cc99a5595d096 100644 --- a/src/plugins/region_map/public/region_map_fn.js +++ b/src/plugins/region_map/public/region_map_fn.js @@ -34,9 +34,12 @@ export const createRegionMapFn = () => ({ default: '"{}"', }, }, - fn(context, args) { + fn(context, args, handlers) { const visConfig = JSON.parse(args.visConfig); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } return { type: 'render', as: 'visualization', diff --git a/src/plugins/region_map/public/region_map_fn.test.js b/src/plugins/region_map/public/region_map_fn.test.js index 32467541dee02..d83d04be6d38c 100644 --- a/src/plugins/region_map/public/region_map_fn.test.js +++ b/src/plugins/region_map/public/region_map_fn.test.js @@ -57,7 +57,11 @@ describe('interpreter/functions#regionmap', () => { }; it('returns an object with the correct structure', () => { - const actual = fn(context, { visConfig: JSON.stringify(visConfig) }); + const actual = fn( + context, + { visConfig: JSON.stringify(visConfig) }, + { logDatatable: jest.fn() } + ); expect(actual).toMatchSnapshot(); }); }); diff --git a/src/plugins/telemetry/common/constants.ts b/src/plugins/telemetry/common/constants.ts index fc77332c18fc9..2fa8b32f68291 100644 --- a/src/plugins/telemetry/common/constants.ts +++ b/src/plugins/telemetry/common/constants.ts @@ -49,7 +49,7 @@ export const LOCALSTORAGE_KEY = 'telemetry.data'; /** * Link to Advanced Settings. */ -export const PATH_TO_ADVANCED_SETTINGS = 'management/kibana/settings'; +export const PATH_TO_ADVANCED_SETTINGS = '/app/management/kibana/settings'; /** * Link to the Elastic Telemetry privacy statement. diff --git a/src/plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap b/src/plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap index 62998da73d6f9..897e3b2761c74 100644 --- a/src/plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap +++ b/src/plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap @@ -10,7 +10,7 @@ exports[`OptInDetailsComponent renders as expected 1`] = ` values={ Object { "disableLink": { it('renders as expected', () => { - expect(shallowWithIntl( {}} />)).toMatchSnapshot(); + expect( + shallowWithIntl( {}} http={mockHttp} />) + ).toMatchSnapshot(); }); it('fires the "onSeenBanner" prop when a link is clicked', () => { const onLinkClick = jest.fn(); - const component = shallowWithIntl(); + const component = shallowWithIntl( + + ); const button = component.findWhere((n) => n.type() === EuiButton); diff --git a/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx b/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx index 090893964c881..46ae17171203c 100644 --- a/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx +++ b/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx @@ -24,14 +24,18 @@ import { EuiButton, EuiLink, EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { PATH_TO_ADVANCED_SETTINGS, PRIVACY_STATEMENT_URL } from '../../common/constants'; +import { HttpSetup } from '../../../../core/public'; interface Props { + http: HttpSetup; onSeenBanner: () => any; } export class OptedInNoticeBanner extends React.PureComponent { render() { - const { onSeenBanner } = this.props; + const { onSeenBanner, http } = this.props; + const basePath = http.basePath.get(); + const bannerTitle = i18n.translate('telemetry.telemetryOptedInNoticeTitle', { defaultMessage: 'Help us improve the Elastic Stack', }); @@ -56,7 +60,7 @@ export class OptedInNoticeBanner extends React.PureComponent { ), disableLink: ( - + { it('adds a banner to banners with priority of 10000', () => { const bannerID = 'brucer-wayne'; const overlays = overlayServiceMock.createStartContract(); + const mockHttp = httpServiceMock.createStartContract(); overlays.banners.add.mockReturnValue(bannerID); const returnedBannerId = renderOptedInNoticeBanner({ + http: mockHttp, onSeen: jest.fn(), overlays, }); diff --git a/src/plugins/telemetry/public/services/telemetry_notifications/render_opted_in_notice_banner.tsx b/src/plugins/telemetry/public/services/telemetry_notifications/render_opted_in_notice_banner.tsx index e63e46af6e8ca..e1feea4b6cbe1 100644 --- a/src/plugins/telemetry/public/services/telemetry_notifications/render_opted_in_notice_banner.tsx +++ b/src/plugins/telemetry/public/services/telemetry_notifications/render_opted_in_notice_banner.tsx @@ -23,11 +23,12 @@ import { OptedInNoticeBanner } from '../../components/opted_in_notice_banner'; import { toMountPoint } from '../../../../kibana_react/public'; interface RenderBannerConfig { + http: CoreStart['http']; overlays: CoreStart['overlays']; onSeen: () => void; } -export function renderOptedInNoticeBanner({ onSeen, overlays }: RenderBannerConfig) { - const mount = toMountPoint(); +export function renderOptedInNoticeBanner({ onSeen, overlays, http }: RenderBannerConfig) { + const mount = toMountPoint(); const bannerId = overlays.banners.add(mount, 10000); return bannerId; diff --git a/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts b/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts index fc44a4db7cf5e..6ebbfcfb91336 100644 --- a/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts +++ b/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts @@ -23,18 +23,21 @@ import { renderOptInBanner } from './render_opt_in_banner'; import { TelemetryService } from '../telemetry_service'; interface TelemetryNotificationsConstructor { + http: CoreStart['http']; overlays: CoreStart['overlays']; telemetryService: TelemetryService; } export class TelemetryNotifications { + private readonly http: CoreStart['http']; private readonly overlays: CoreStart['overlays']; private readonly telemetryService: TelemetryService; private optedInNoticeBannerId?: string; private optInBannerId?: string; - constructor({ overlays, telemetryService }: TelemetryNotificationsConstructor) { + constructor({ http, overlays, telemetryService }: TelemetryNotificationsConstructor) { this.telemetryService = telemetryService; + this.http = http; this.overlays = overlays; } @@ -46,6 +49,7 @@ export class TelemetryNotifications { public renderOptedInNoticeBanner = (): void => { const bannerId = renderOptedInNoticeBanner({ + http: this.http, onSeen: this.setOptedInNoticeSeen, overlays: this.overlays, }); diff --git a/src/plugins/tile_map/public/components/tile_map_options.tsx b/src/plugins/tile_map/public/components/tile_map_options.tsx index 1a7b11ccf6e20..a6c0bb8a50dda 100644 --- a/src/plugins/tile_map/public/components/tile_map_options.tsx +++ b/src/plugins/tile_map/public/components/tile_map_options.tsx @@ -21,8 +21,13 @@ import React, { useEffect } from 'react'; import { EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { BasicOptions, RangeOption, SelectOption, SwitchOption } from '../../../charts/public'; +import { + VisOptionsProps, + BasicOptions, + SelectOption, + SwitchOption, + RangeOption, +} from '../../../vis_default_editor/public'; import { WmsOptions, TileMapVisParams, MapTypes } from '../../../maps_legacy/public'; export type TileMapOptionsProps = VisOptionsProps; diff --git a/src/plugins/tile_map/public/tile_map_fn.js b/src/plugins/tile_map/public/tile_map_fn.js index 3253598d98d94..7a5f36be1eb9d 100644 --- a/src/plugins/tile_map/public/tile_map_fn.js +++ b/src/plugins/tile_map/public/tile_map_fn.js @@ -34,7 +34,7 @@ export const createTileMapFn = () => ({ default: '"{}"', }, }, - fn(context, args) { + fn(context, args, handlers) { const visConfig = JSON.parse(args.visConfig); const { geohash, metric, geocentroid } = visConfig.dimensions; const convertedData = convertToGeoJson(context, { @@ -47,6 +47,9 @@ export const createTileMapFn = () => ({ convertedData.meta.geohash = context.columns[geohash.accessor].meta; } + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } return { type: 'render', as: 'visualization', diff --git a/src/plugins/tile_map/public/tilemap_fn.test.js b/src/plugins/tile_map/public/tilemap_fn.test.js index df9fc10a7303c..895842ea1e8f4 100644 --- a/src/plugins/tile_map/public/tilemap_fn.test.js +++ b/src/plugins/tile_map/public/tilemap_fn.test.js @@ -80,13 +80,17 @@ describe('interpreter/functions#tilemap', () => { }); it('returns an object with the correct structure', () => { - const actual = fn(context, { visConfig: JSON.stringify(visConfig) }); + const actual = fn( + context, + { visConfig: JSON.stringify(visConfig) }, + { logDatatable: jest.fn() } + ); expect(actual).toMatchSnapshot(); }); it('calls response handler with correct values', () => { const { geohash, metric, geocentroid } = visConfig.dimensions; - fn(context, { visConfig: JSON.stringify(visConfig) }); + fn(context, { visConfig: JSON.stringify(visConfig) }, { logDatatable: jest.fn() }); expect(convertToGeoJson).toHaveBeenCalledTimes(1); expect(convertToGeoJson).toHaveBeenCalledWith(context, { geohash, diff --git a/src/plugins/ui_actions/public/actions/action.test.ts b/src/plugins/ui_actions/public/actions/action.test.ts index 1f76223a0d7c4..4a51c0323fa8b 100644 --- a/src/plugins/ui_actions/public/actions/action.test.ts +++ b/src/plugins/ui_actions/public/actions/action.test.ts @@ -18,14 +18,12 @@ */ import { ActionExecutionContext, createAction } from '../../../ui_actions/public'; -import { ActionType } from '../types'; import { defaultTrigger } from '../triggers'; -const sayHelloAction = createAction({ - // Casting to ActionType is a hack - in a real situation use - // declare module and add this id to ActionContextMapping. - type: 'test' as ActionType, - isCompatible: ({ amICompatible }: { amICompatible: boolean }) => Promise.resolve(amICompatible), +const sayHelloAction = createAction<{ amICompatible: boolean }>({ + id: 'test', + type: 'test', + isCompatible: ({ amICompatible }) => Promise.resolve(amICompatible), execute: () => Promise.resolve(), }); @@ -33,7 +31,7 @@ test('action is not compatible based on context', async () => { const isCompatible = await sayHelloAction.isCompatible({ amICompatible: false, trigger: defaultTrigger, - } as ActionExecutionContext); + } as ActionExecutionContext<{ amICompatible: boolean }>); expect(isCompatible).toBe(false); }); @@ -41,6 +39,6 @@ test('action is compatible based on context', async () => { const isCompatible = await sayHelloAction.isCompatible({ amICompatible: true, trigger: defaultTrigger, - } as ActionExecutionContext); + } as ActionExecutionContext<{ amICompatible: boolean }>); expect(isCompatible).toBe(true); }); diff --git a/src/plugins/ui_actions/public/actions/action.ts b/src/plugins/ui_actions/public/actions/action.ts index 8005dadd8f5ef..5d479577d4bc6 100644 --- a/src/plugins/ui_actions/public/actions/action.ts +++ b/src/plugins/ui_actions/public/actions/action.ts @@ -18,15 +18,9 @@ */ import { UiComponent } from 'src/plugins/kibana_utils/public'; -import { ActionType, ActionContextMapping, BaseContext } from '../types'; import { Presentable } from '../util/presentable'; import { Trigger } from '../triggers'; -export type ActionByType = Action; -export type ActionDefinitionByType = ActionDefinition< - ActionContextMapping[T] ->; - /** * During action execution we can provide additional information, * for example, trigger, that caused the action execution @@ -41,19 +35,18 @@ export interface ActionExecutionMeta { /** * Action methods are executed with Context from trigger + {@link ActionExecutionMeta} */ -export type ActionExecutionContext = Context & - ActionExecutionMeta; +export type ActionExecutionContext = Context & ActionExecutionMeta; /** * Simplified action context for {@link ActionDefinition} * When defining action consumer may use either it's own Context * or an ActionExecutionContext to get access to {@link ActionExecutionMeta} params */ -export type ActionDefinitionContext = +export type ActionDefinitionContext = | Context | ActionExecutionContext; -export interface Action +export interface Action extends Partial>> { /** * Determined the order when there is more than one action matched to a trigger. @@ -69,7 +62,7 @@ export interface Action /** * The action type is what determines the context shape. */ - readonly type: T; + readonly type: string; /** * Optional EUI icon type that can be displayed along with the title. @@ -117,7 +110,7 @@ export interface Action /** * A convenience interface used to register an action. */ -export interface ActionDefinition +export interface ActionDefinition extends Partial>> { /** * ID of the action that uniquely identifies this action in the actions registry. @@ -127,7 +120,7 @@ export interface ActionDefinition /** * ID of the factory for this action. Used to construct dynamic actions. */ - readonly type?: ActionType; + readonly type?: string; /** * Returns a promise that resolves to true if this item is compatible given diff --git a/src/plugins/ui_actions/public/actions/action_internal.ts b/src/plugins/ui_actions/public/actions/action_internal.ts index fe7c986bdb7ef..7cae0f68bd004 100644 --- a/src/plugins/ui_actions/public/actions/action_internal.ts +++ b/src/plugins/ui_actions/public/actions/action_internal.ts @@ -22,7 +22,6 @@ import React from 'react'; import { Action, ActionContext as Context, ActionDefinition } from './action'; import { Presentable, PresentableGrouping } from '../util/presentable'; import { uiToReactComponent } from '../../../kibana_react/public'; -import { ActionType } from '../types'; /** * @internal @@ -32,7 +31,7 @@ export class ActionInternal
constructor(public readonly definition: A) {} public readonly id: string = this.definition.id; - public readonly type: ActionType = this.definition.type || ''; + public readonly type: string = this.definition.type || ''; public readonly order: number = this.definition.order || 0; public readonly MenuItem? = this.definition.MenuItem; public readonly ReactMenuItem? = this.MenuItem ? uiToReactComponent(this.MenuItem) : undefined; diff --git a/src/plugins/ui_actions/public/actions/create_action.ts b/src/plugins/ui_actions/public/actions/create_action.ts index dea21678eccea..0199812c40802 100644 --- a/src/plugins/ui_actions/public/actions/create_action.ts +++ b/src/plugins/ui_actions/public/actions/create_action.ts @@ -17,25 +17,16 @@ * under the License. */ -import { ActionContextMapping } from '../types'; -import { ActionByType } from './action'; -import { ActionType } from '../types'; -import { ActionDefinition } from './action'; +import { ActionDefinition, Action } from './action'; -interface ActionDefinitionByType - extends Omit, 'id'> { - id?: string; -} - -export function createAction( - action: ActionDefinitionByType -): ActionByType { +export function createAction( + action: ActionDefinition +): Action { return { getIconType: () => undefined, order: 0, - id: action.type, isCompatible: () => Promise.resolve(true), getDisplayName: () => '', ...action, - } as ActionByType; + } as Action; } diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts index 3111a0b55084c..ac19889aa6532 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts @@ -34,6 +34,7 @@ const createTestAction = ({ grouping?: PresentableGrouping; }) => createAction({ + id: type as any, // mapping doesn't matter for this test type: type as any, // mapping doesn't matter for this test getDisplayName: () => dispayName, order, diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index 63586ca3da1f7..aa3fd57be695a 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -24,7 +24,6 @@ import { i18n } from '@kbn/i18n'; import { uiToReactComponent } from '../../../kibana_react/public'; import { Action, ActionExecutionContext } from '../actions'; import { Trigger } from '../triggers'; -import { BaseContext } from '../types'; export const defaultTitle = i18n.translate('uiActions.actionPanel.title', { defaultMessage: 'Options', @@ -34,7 +33,7 @@ export const txtMore = i18n.translate('uiActions.actionPanel.more', { defaultMessage: 'More', }); -interface ActionWithContext { +interface ActionWithContext { action: Action; context: Context; diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index d223c0abcccb7..9ac5c19033e45 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -39,13 +39,6 @@ export { } from './util'; export { Trigger, - TriggerContext, - SELECT_RANGE_TRIGGER, - selectRangeTrigger, - VALUE_CLICK_TRIGGER, - valueClickTrigger, - APPLY_FILTER_TRIGGER, - applyFilterTrigger, VISUALIZE_FIELD_TRIGGER, visualizeFieldTrigger, VISUALIZE_GEO_FIELD_TRIGGER, @@ -55,18 +48,9 @@ export { RowClickContext, } from './triggers'; export { - TriggerContextMapping, - TriggerId, - ActionContextMapping, - ActionType, VisualizeFieldContext, ACTION_VISUALIZE_FIELD, ACTION_VISUALIZE_GEO_FIELD, ACTION_VISUALIZE_LENS_FIELD, } from './types'; -export { - ActionByType, - ActionDefinitionByType, - ActionExecutionContext, - ActionExecutionMeta, -} from './actions'; +export { ActionExecutionContext, ActionExecutionMeta } from './actions'; diff --git a/src/plugins/ui_actions/public/mocks.ts b/src/plugins/ui_actions/public/mocks.ts index 759430169b613..fa24738014910 100644 --- a/src/plugins/ui_actions/public/mocks.ts +++ b/src/plugins/ui_actions/public/mocks.ts @@ -21,7 +21,6 @@ import { CoreSetup, CoreStart } from 'src/core/public'; import { UiActionsSetup, UiActionsStart } from '.'; import { plugin as pluginInitializer } from '.'; import { coreMock } from '../../../core/public/mocks'; -import { TriggerId } from './types'; export type Setup = jest.Mocked; export type Start = jest.Mocked; @@ -50,7 +49,7 @@ const createStartContract = (): Start => { getAction: jest.fn(), hasAction: jest.fn(), getTrigger: jest.fn(), - getTriggerActions: jest.fn((id: TriggerId) => []), + getTriggerActions: jest.fn((id: string) => []), getTriggerCompatibleActions: jest.fn(), registerAction: jest.fn(), registerTrigger: jest.fn(), diff --git a/src/plugins/ui_actions/public/plugin.ts b/src/plugins/ui_actions/public/plugin.ts index fdb75e9a426e9..84a7ae45fc7b8 100644 --- a/src/plugins/ui_actions/public/plugin.ts +++ b/src/plugins/ui_actions/public/plugin.ts @@ -20,14 +20,7 @@ import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/public'; import { PublicMethodsOf } from '@kbn/utility-types'; import { UiActionsService } from './service'; -import { - selectRangeTrigger, - valueClickTrigger, - rowClickTrigger, - applyFilterTrigger, - visualizeFieldTrigger, - visualizeGeoFieldTrigger, -} from './triggers'; +import { rowClickTrigger, visualizeFieldTrigger, visualizeGeoFieldTrigger } from './triggers'; export type UiActionsSetup = Pick< UiActionsService, @@ -47,10 +40,7 @@ export class UiActionsPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup): UiActionsSetup { - this.service.registerTrigger(selectRangeTrigger); - this.service.registerTrigger(valueClickTrigger); this.service.registerTrigger(rowClickTrigger); - this.service.registerTrigger(applyFilterTrigger); this.service.registerTrigger(visualizeFieldTrigger); this.service.registerTrigger(visualizeGeoFieldTrigger); return this.service; diff --git a/src/plugins/ui_actions/public/public.api.md b/src/plugins/ui_actions/public/public.api.md index 2384dfab13c8c..0d3ab1086904d 100644 --- a/src/plugins/ui_actions/public/public.api.md +++ b/src/plugins/ui_actions/public/public.api.md @@ -8,21 +8,17 @@ import { CoreSetup } from 'src/core/public'; import { CoreStart } from 'src/core/public'; import { EnvironmentMode } from '@kbn/config'; import { EuiContextMenuPanelDescriptor } from '@elastic/eui'; -import { EventEmitter } from 'events'; -import { Observable } from 'rxjs'; import { PackageInfo } from '@kbn/config'; import { Plugin } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PublicMethodsOf } from '@kbn/utility-types'; import React from 'react'; -import * as Rx from 'rxjs'; import { UiComponent } from 'src/plugins/kibana_utils/public'; -// Warning: (ae-forgotten-export) The symbol "BaseContext" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Action" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface Action extends Partial>> { +export interface Action extends Partial>> { execute(context: ActionExecutionContext): Promise; getDisplayName(context: ActionExecutionContext): string; getHref?(context: ActionExecutionContext): Promise; @@ -34,7 +30,7 @@ export interface Action extend }>; order?: number; shouldAutoExecute?(context: ActionExecutionContext): Promise; - readonly type: T; + readonly type: string; } // Warning: (ae-missing-release-tag) "ACTION_VISUALIZE_FIELD" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -52,36 +48,10 @@ export const ACTION_VISUALIZE_GEO_FIELD = "ACTION_VISUALIZE_GEO_FIELD"; // @public (undocumented) export const ACTION_VISUALIZE_LENS_FIELD = "ACTION_VISUALIZE_LENS_FIELD"; -// Warning: (ae-missing-release-tag) "ActionByType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ActionByType = Action; - -// Warning: (ae-missing-release-tag) "ActionContextMapping" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface ActionContextMapping { - // Warning: (ae-forgotten-export) The symbol "DEFAULT_ACTION" needs to be exported by the entry point index.d.ts - // - // (undocumented) - [DEFAULT_ACTION]: BaseContext; - // (undocumented) - [ACTION_VISUALIZE_FIELD]: VisualizeFieldContext; - // (undocumented) - [ACTION_VISUALIZE_GEO_FIELD]: VisualizeFieldContext; - // (undocumented) - [ACTION_VISUALIZE_LENS_FIELD]: VisualizeFieldContext; -} - -// Warning: (ae-missing-release-tag) "ActionDefinitionByType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ActionDefinitionByType = UiActionsActionDefinition; - // Warning: (ae-missing-release-tag) "ActionExecutionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type ActionExecutionContext = Context & ActionExecutionMeta; +export type ActionExecutionContext = Context & ActionExecutionMeta; // Warning: (ae-missing-release-tag) "ActionExecutionMeta" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -90,32 +60,16 @@ export interface ActionExecutionMeta { trigger: Trigger; } -// Warning: (ae-missing-release-tag) "ActionType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ActionType = keyof ActionContextMapping; - -// Warning: (ae-missing-release-tag) "APPLY_FILTER_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const APPLY_FILTER_TRIGGER = "FILTER_TRIGGER"; - -// Warning: (ae-missing-release-tag) "applyFilterTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const applyFilterTrigger: Trigger<'FILTER_TRIGGER'>; - // Warning: (ae-forgotten-export) The symbol "BuildContextMenuParams" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "buildContextMenuForActions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public export function buildContextMenuForActions({ actions, title, closeMenu, }: BuildContextMenuParams): Promise; -// Warning: (ae-forgotten-export) The symbol "ActionDefinitionByType" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "createAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createAction(action: ActionDefinitionByType_2): ActionByType; +export function createAction(action: UiActionsActionDefinition): Action; // Warning: (ae-missing-release-tag) "IncompatibleActionError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -148,92 +102,41 @@ export interface RowClickContext { table: Datatable; columns?: string[]; }; - // Warning: (ae-forgotten-export) The symbol "IEmbeddable" needs to be exported by the entry point index.d.ts - // // (undocumented) - embeddable?: IEmbeddable; + embeddable?: unknown; } // Warning: (ae-missing-release-tag) "rowClickTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const rowClickTrigger: Trigger<'ROW_CLICK_TRIGGER'>; - -// Warning: (ae-missing-release-tag) "SELECT_RANGE_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const SELECT_RANGE_TRIGGER = "SELECT_RANGE_TRIGGER"; - -// Warning: (ae-missing-release-tag) "selectRangeTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'>; +export const rowClickTrigger: Trigger; // Warning: (ae-missing-release-tag) "Trigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface Trigger { +export interface Trigger { description?: string; - id: ID; + id: string; title?: string; } -// Warning: (ae-missing-release-tag) "TriggerContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type TriggerContext = T extends TriggerId ? TriggerContextMapping[T] : never; - -// Warning: (ae-missing-release-tag) "TriggerContextMapping" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface TriggerContextMapping { - // Warning: (ae-forgotten-export) The symbol "DEFAULT_TRIGGER" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "TriggerContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - [DEFAULT_TRIGGER]: TriggerContext_2; - // Warning: (ae-forgotten-export) The symbol "ApplyGlobalFilterActionContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - [APPLY_FILTER_TRIGGER]: ApplyGlobalFilterActionContext; - // (undocumented) - [ROW_CLICK_TRIGGER]: RowClickContext; - // Warning: (ae-forgotten-export) The symbol "RangeSelectContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - [SELECT_RANGE_TRIGGER]: RangeSelectContext; - // Warning: (ae-forgotten-export) The symbol "ValueClickContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - [VALUE_CLICK_TRIGGER]: ValueClickContext; - // (undocumented) - [VISUALIZE_FIELD_TRIGGER]: VisualizeFieldContext; - // (undocumented) - [VISUALIZE_GEO_FIELD_TRIGGER]: VisualizeFieldContext; -} - -// Warning: (ae-missing-release-tag) "TriggerId" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type TriggerId = keyof TriggerContextMapping; - // Warning: (ae-forgotten-export) The symbol "ActionDefinitionContext" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ActionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface UiActionsActionDefinition extends Partial>> { +export interface UiActionsActionDefinition extends Partial>> { execute(context: ActionDefinitionContext): Promise; getHref?(context: ActionDefinitionContext): Promise; readonly id: string; isCompatible?(context: ActionDefinitionContext): Promise; shouldAutoExecute?(context: ActionDefinitionContext): Promise; - readonly type?: ActionType; + readonly type?: string; } // Warning: (ae-missing-release-tag) "Presentable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface UiActionsPresentable { +export interface UiActionsPresentable { getDisplayName(context: Context): string; getDisplayNameTooltip(context: Context): string; getHref?(context: Context): Promise; @@ -251,7 +154,7 @@ export interface UiActionsPresentable { // Warning: (ae-missing-release-tag) "PresentableGrouping" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type UiActionsPresentableGrouping = Array>; +export type UiActionsPresentableGrouping = Array>; // Warning: (ae-missing-release-tag) "UiActionsService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -262,35 +165,35 @@ export class UiActionsService { // // (undocumented) protected readonly actions: ActionRegistry; - readonly addTriggerAction: (triggerId: T, action: UiActionsActionDefinition | Action) => void; + readonly addTriggerAction: (triggerId: string, action: UiActionsActionDefinition) => void; // (undocumented) - readonly attachAction: (triggerId: T, actionId: string) => void; + readonly attachAction: (triggerId: string, actionId: string) => void; readonly clear: () => void; // (undocumented) - readonly detachAction: (triggerId: TriggerId, actionId: string) => void; + readonly detachAction: (triggerId: string, actionId: string) => void; // @deprecated (undocumented) - readonly executeTriggerActions: (triggerId: T, context: TriggerContext) => Promise; + readonly executeTriggerActions: (triggerId: string, context: object) => Promise; // Warning: (ae-forgotten-export) The symbol "UiActionsExecutionService" needs to be exported by the entry point index.d.ts // // (undocumented) readonly executionService: UiActionsExecutionService; readonly fork: () => UiActionsService; // (undocumented) - readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">; + readonly getAction: >(id: string) => Action>; // Warning: (ae-forgotten-export) The symbol "TriggerContract" needs to be exported by the entry point index.d.ts // // (undocumented) - readonly getTrigger: (triggerId: T) => TriggerContract; + readonly getTrigger: (triggerId: string) => TriggerContract; // (undocumented) - readonly getTriggerActions: (triggerId: T) => Action[]; + readonly getTriggerActions: (triggerId: string) => Action[]; // (undocumented) - readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; + readonly getTriggerCompatibleActions: (triggerId: string, context: object) => Promise; // (undocumented) readonly hasAction: (actionId: string) => boolean; // Warning: (ae-forgotten-export) The symbol "ActionContext" needs to be exported by the entry point index.d.ts // // (undocumented) - readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_EXPORT_CSV">; + readonly registerAction: >(definition: A) => Action>; // (undocumented) readonly registerTrigger: (trigger: Trigger) => void; // Warning: (ae-forgotten-export) The symbol "TriggerRegistry" needs to be exported by the entry point index.d.ts @@ -326,16 +229,6 @@ export type UiActionsSetup = Pick; -// Warning: (ae-missing-release-tag) "VALUE_CLICK_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const VALUE_CLICK_TRIGGER = "VALUE_CLICK_TRIGGER"; - -// Warning: (ae-missing-release-tag) "valueClickTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'>; - // Warning: (ae-missing-release-tag) "VISUALIZE_FIELD_TRIGGER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -361,17 +254,17 @@ export interface VisualizeFieldContext { // Warning: (ae-missing-release-tag) "visualizeFieldTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const visualizeFieldTrigger: Trigger<'VISUALIZE_FIELD_TRIGGER'>; +export const visualizeFieldTrigger: Trigger; // Warning: (ae-missing-release-tag) "visualizeGeoFieldTrigger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const visualizeGeoFieldTrigger: Trigger<'VISUALIZE_GEO_FIELD_TRIGGER'>; +export const visualizeGeoFieldTrigger: Trigger; // Warnings were encountered during analysis: // -// src/plugins/ui_actions/public/triggers/row_click_trigger.ts:45:5 - (ae-forgotten-export) The symbol "Datatable" needs to be exported by the entry point index.d.ts +// src/plugins/ui_actions/public/triggers/row_click_trigger.ts:46:5 - (ae-forgotten-export) The symbol "Datatable" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts index 59616dcf3f38d..ea44448092a72 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -19,14 +19,13 @@ import { uniqBy } from 'lodash'; import { Action } from '../actions'; -import { BaseContext } from '../types'; import { defer as createDefer, Defer } from '../../../kibana_utils/public'; import { buildContextMenuForActions, openContextMenu } from '../context_menu'; import { Trigger } from '../triggers'; interface ExecuteActionTask { action: Action; - context: BaseContext; + context: object; trigger: Trigger; defer: Defer; alwaysShowPopup?: boolean; @@ -44,8 +43,8 @@ export class UiActionsExecutionService { context, trigger, }: { - action: Action; - context: BaseContext; + action: Action; + context: object; trigger: Trigger; }, alwaysShowPopup?: boolean diff --git a/src/plugins/ui_actions/public/service/ui_actions_service.test.ts b/src/plugins/ui_actions/public/service/ui_actions_service.test.ts index 39502c3dd17fc..137cfaeac4b67 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.test.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.test.ts @@ -20,19 +20,17 @@ import { UiActionsService } from './ui_actions_service'; import { Action, ActionInternal, createAction } from '../actions'; import { createHelloWorldAction } from '../tests/test_samples'; -import { TriggerRegistry, TriggerId, ActionType, ActionRegistry } from '../types'; +import { TriggerRegistry, ActionRegistry } from '../types'; import { Trigger } from '../triggers'; -// Casting to ActionType or TriggerId is a hack - in a real situation use -// declare module and add this id to the appropriate context mapping. -const FOO_TRIGGER: TriggerId = 'FOO_TRIGGER' as TriggerId; -const BAR_TRIGGER: TriggerId = 'BAR_TRIGGER' as TriggerId; -const MY_TRIGGER: TriggerId = 'MY_TRIGGER' as TriggerId; +const FOO_TRIGGER = 'FOO_TRIGGER'; +const BAR_TRIGGER = 'BAR_TRIGGER'; +const MY_TRIGGER = 'MY_TRIGGER'; const testAction1: Action = { id: 'action1', order: 1, - type: 'type1' as ActionType, + type: 'type1', execute: async () => {}, getDisplayName: () => 'test1', getIconType: () => '', @@ -42,7 +40,7 @@ const testAction1: Action = { const testAction2: Action = { id: 'action2', order: 2, - type: 'type2' as ActionType, + type: 'type2', execute: async () => {}, getDisplayName: () => 'test2', getIconType: () => '', @@ -99,7 +97,7 @@ describe('UiActionsService', () => { getDisplayName: () => 'test', getIconType: () => '', isCompatible: async () => true, - type: 'test' as ActionType, + type: 'test', }); }); @@ -111,7 +109,7 @@ describe('UiActionsService', () => { getDisplayName: () => 'test', getIconType: () => '', isCompatible: async () => true, - type: 'test' as ActionType, + type: 'test', }); expect(action).toBeInstanceOf(ActionInternal); @@ -123,7 +121,7 @@ describe('UiActionsService', () => { const action1: Action = { id: 'action1', order: 1, - type: 'type1' as ActionType, + type: 'type1', execute: async () => {}, getDisplayName: () => 'test', getIconType: () => '', @@ -132,7 +130,7 @@ describe('UiActionsService', () => { const action2: Action = { id: 'action2', order: 2, - type: 'type2' as ActionType, + type: 'type2', execute: async () => {}, getDisplayName: () => 'test', getIconType: () => '', @@ -207,7 +205,8 @@ describe('UiActionsService', () => { test('filters out actions not applicable based on the context', async () => { const service = new UiActionsService(); const action = createAction({ - type: 'test' as ActionType, + id: 'test', + type: 'test', isCompatible: ({ accept }: { accept: boolean }) => Promise.resolve(accept), execute: () => Promise.resolve(), }); @@ -238,16 +237,15 @@ describe('UiActionsService', () => { test(`throws an error with an invalid trigger ID`, async () => { const service = new UiActionsService(); - // Without the cast "as TriggerId" typescript will happily throw an error! - await expect( - service.getTriggerCompatibleActions('I do not exist' as TriggerId, {}) - ).rejects.toMatchObject(new Error('Trigger [triggerId = I do not exist] does not exist.')); + await expect(service.getTriggerCompatibleActions('I do not exist', {})).rejects.toMatchObject( + new Error('Trigger [triggerId = I do not exist] does not exist.') + ); }); test('returns empty list if trigger not attached to any action', async () => { const service = new UiActionsService(); const testTrigger: Trigger = { - id: '123' as TriggerId, + id: '123', title: '123', }; service.registerTrigger(testTrigger); @@ -445,9 +443,7 @@ describe('UiActionsService', () => { } as any; service.registerAction(action); - expect(() => - service.detachAction('i do not exist' as TriggerId, ACTION_HELLO_WORLD) - ).toThrowError( + expect(() => service.detachAction('i do not exist', ACTION_HELLO_WORLD)).toThrowError( 'No trigger [triggerId = i do not exist] exists, for detaching action [actionId = ACTION_HELLO_WORLD].' ); }); @@ -461,7 +457,7 @@ describe('UiActionsService', () => { } as any; service.registerAction(action); - expect(() => service.addTriggerAction('i do not exist' as TriggerId, action)).toThrowError( + expect(() => service.addTriggerAction('i do not exist', action)).toThrowError( 'No trigger [triggerId = i do not exist] exists, for attaching action [actionId = ACTION_HELLO_WORLD].' ); }); diff --git a/src/plugins/ui_actions/public/service/ui_actions_service.ts b/src/plugins/ui_actions/public/service/ui_actions_service.ts index ec5f3afa19c94..456341d98c5b5 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.ts @@ -17,15 +17,9 @@ * under the License. */ -import { - TriggerRegistry, - ActionRegistry, - TriggerToActionsRegistry, - TriggerId, - TriggerContextMapping, -} from '../types'; +import { TriggerRegistry, ActionRegistry, TriggerToActionsRegistry } from '../types'; import { ActionInternal, Action, ActionDefinition, ActionContext } from '../actions'; -import { Trigger, TriggerContext } from '../triggers/trigger'; +import { Trigger } from '../triggers/trigger'; import { TriggerInternal } from '../triggers/trigger_internal'; import { TriggerContract } from '../triggers/trigger_contract'; import { UiActionsExecutionService } from './ui_actions_execution_service'; @@ -67,7 +61,7 @@ export class UiActionsService { this.triggerToActions.set(trigger.id, []); }; - public readonly getTrigger = (triggerId: T): TriggerContract => { + public readonly getTrigger = (triggerId: string): TriggerContract => { const trigger = this.triggers.get(triggerId); if (!trigger) { @@ -103,7 +97,7 @@ export class UiActionsService { return this.actions.has(actionId); }; - public readonly attachAction = (triggerId: T, actionId: string): void => { + public readonly attachAction = (triggerId: string, actionId: string): void => { const trigger = this.triggers.get(triggerId); if (!trigger) { @@ -119,7 +113,7 @@ export class UiActionsService { } }; - public readonly detachAction = (triggerId: TriggerId, actionId: string) => { + public readonly detachAction = (triggerId: string, actionId: string) => { const trigger = this.triggers.get(triggerId); if (!trigger) { @@ -139,14 +133,10 @@ export class UiActionsService { /** * `addTriggerAction` is similar to `attachAction` as it attaches action to a * trigger, but it also registers the action, if it has not been registered, yet. - * - * `addTriggerAction` also infers better typing of the `action` argument. */ - public readonly addTriggerAction = ( - triggerId: T, - // The action can accept partial or no context, but if it needs context not provided - // by this type of trigger, typescript will complain. yay! - action: ActionDefinition | Action // TODO: remove `Action` https://github.com/elastic/kibana/issues/74501 + public readonly addTriggerAction = ( + triggerId: string, + action: ActionDefinition // TODO: remove `Action` https://github.com/elastic/kibana/issues/74501 ): void => { if (!this.actions.has(action.id)) this.registerAction(action); this.attachAction(triggerId, action.id); @@ -162,9 +152,7 @@ export class UiActionsService { return this.actions.get(id) as ActionInternal; }; - public readonly getTriggerActions = ( - triggerId: T - ): Array> => { + public readonly getTriggerActions = (triggerId: string): Action[] => { // This line checks if trigger exists, otherwise throws. this.getTrigger!(triggerId); @@ -174,13 +162,13 @@ export class UiActionsService { .map((actionId) => this.actions.get(actionId) as ActionInternal) .filter(Boolean); - return actions as Array>>; + return actions as Action[]; }; - public readonly getTriggerCompatibleActions = async ( - triggerId: T, - context: TriggerContextMapping[T] - ): Promise>> => { + public readonly getTriggerCompatibleActions = async ( + triggerId: string, + context: object + ): Promise => { const actions = this.getTriggerActions!(triggerId); const isCompatibles = await Promise.all( actions.map((action) => @@ -191,8 +179,7 @@ export class UiActionsService { ) ); return actions.reduce( - (acc: Array>, action, i) => - isCompatibles[i] ? [...acc, action] : acc, + (acc: Action[], action, i) => (isCompatibles[i] ? [...acc, action] : acc), [] ); }; @@ -202,11 +189,8 @@ export class UiActionsService { * * Use `plugins.uiActions.getTrigger(triggerId).exec(params)` instead. */ - public readonly executeTriggerActions = async ( - triggerId: T, - context: TriggerContext - ) => { - const trigger = this.getTrigger(triggerId); + public readonly executeTriggerActions = async (triggerId: string, context: object) => { + const trigger = this.getTrigger(triggerId); await trigger.exec(context); }; diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts index 51ba165ba730b..6f8a45cc2e40a 100644 --- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts @@ -21,7 +21,6 @@ import { Action, createAction } from '../actions'; import { openContextMenu } from '../context_menu'; import { uiActionsPluginMock } from '../mocks'; import { Trigger } from '../triggers'; -import { TriggerId, ActionType } from '../types'; import { waitFor } from '@testing-library/dom'; jest.mock('../context_menu'); @@ -31,17 +30,13 @@ const openContextMenuSpy = (openContextMenu as any) as jest.SpyInstance; const CONTACT_USER_TRIGGER = 'CONTACT_USER_TRIGGER'; -// Casting to ActionType is a hack - in a real situation use -// declare module and add this id to ActionContextMapping. -const TEST_ACTION_TYPE = 'TEST_ACTION_TYPE' as ActionType; - function createTestAction( type: string, checkCompatibility: (context: C) => boolean, autoExecutable = false ): Action { - return createAction({ - type: type as ActionType, + return createAction({ + type, id: type, isCompatible: (context: C) => Promise.resolve(checkCompatibility(context)), execute: (context) => executeFn(context), @@ -67,7 +62,7 @@ beforeEach(reset); test('executes a single action mapped to a trigger', async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action = createTestAction('test1', () => true); @@ -77,7 +72,7 @@ test('executes a single action mapped to a trigger', async () => { const context = {}; const start = doStart(); - await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + await start.executeTriggerActions('MY-TRIGGER', context); jest.runAllTimers(); @@ -88,7 +83,7 @@ test('executes a single action mapped to a trigger', async () => { test("doesn't throw an error if there are no compatible actions to execute", async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; @@ -96,15 +91,13 @@ test("doesn't throw an error if there are no compatible actions to execute", asy const context = {}; const start = doStart(); - await expect( - start.executeTriggerActions('MY-TRIGGER' as TriggerId, context) - ).resolves.toBeUndefined(); + await expect(start.executeTriggerActions('MY-TRIGGER', context)).resolves.toBeUndefined(); }); test('does not execute an incompatible action', async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action = createTestAction<{ name: string }>( @@ -119,7 +112,7 @@ test('does not execute an incompatible action', async () => { const context = { name: 'executeme', }; - await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + await start.executeTriggerActions('MY-TRIGGER', context); jest.runAllTimers(); @@ -129,7 +122,7 @@ test('does not execute an incompatible action', async () => { test('shows a context menu when more than one action is mapped to a trigger', async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action1 = createTestAction('test1', () => true); @@ -143,7 +136,7 @@ test('shows a context menu when more than one action is mapped to a trigger', as const start = doStart(); const context = {}; - await start.getTrigger('MY-TRIGGER' as TriggerId)!.exec(context); + await start.getTrigger('MY-TRIGGER')!.exec(context); jest.runAllTimers(); @@ -156,7 +149,7 @@ test('shows a context menu when more than one action is mapped to a trigger', as test('shows a context menu when there is only one action mapped to a trigger and "alwaysShowPopup" is set', async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action1 = createTestAction('test1', () => true); @@ -168,7 +161,7 @@ test('shows a context menu when there is only one action mapped to a trigger and const start = doStart(); const context = {}; - await start.getTrigger('MY-TRIGGER' as TriggerId)!.exec(context, true); + await start.getTrigger('MY-TRIGGER')!.exec(context, true); jest.runAllTimers(); @@ -181,7 +174,7 @@ test('shows a context menu when there is only one action mapped to a trigger and test('passes whole action context to isCompatible()', async () => { const { setup, doStart } = uiActions; const trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action = createTestAction<{ foo: string }>('test', ({ foo }) => { @@ -195,14 +188,14 @@ test('passes whole action context to isCompatible()', async () => { const start = doStart(); const context = { foo: 'bar' }; - await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + await start.executeTriggerActions('MY-TRIGGER', context); jest.runAllTimers(); }); test("doesn't show a context menu for auto executable actions", async () => { const { setup, doStart } = uiActions; const trigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action1 = createTestAction('test1', () => true, true); @@ -216,7 +209,7 @@ test("doesn't show a context menu for auto executable actions", async () => { const start = doStart(); const context = {}; - await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + await start.executeTriggerActions('MY-TRIGGER', context); jest.runAllTimers(); @@ -229,7 +222,7 @@ test("doesn't show a context menu for auto executable actions", async () => { test('passes trigger into execute', async () => { const { setup, doStart } = uiActions; const trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; const action = createTestAction<{ foo: string }>('test', () => true); @@ -240,7 +233,7 @@ test('passes trigger into execute', async () => { const start = doStart(); const context = { foo: 'bar' }; - await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + await start.executeTriggerActions('MY-TRIGGER', context); jest.runAllTimers(); expect(executeFn).toBeCalledWith({ ...context, diff --git a/src/plugins/ui_actions/public/tests/get_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/get_trigger_actions.test.ts index 55ccac42ff255..ddae251bb83d2 100644 --- a/src/plugins/ui_actions/public/tests/get_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/get_trigger_actions.test.ts @@ -19,17 +19,16 @@ import { ActionInternal, Action } from '../actions'; import { uiActionsPluginMock } from '../mocks'; -import { TriggerId, ActionType } from '../types'; const action1: Action = { id: 'action1', order: 1, - type: 'type1' as ActionType, + type: 'type1', } as any; const action2: Action = { id: 'action2', order: 2, - type: 'type2' as ActionType, + type: 'type2', } as any; test('returns actions set on trigger', () => { @@ -38,24 +37,24 @@ test('returns actions set on trigger', () => { setup.registerAction(action2); setup.registerTrigger({ description: 'foo', - id: 'trigger' as TriggerId, + id: 'trigger', title: 'baz', }); const start = doStart(); - const list0 = start.getTriggerActions('trigger' as TriggerId); + const list0 = start.getTriggerActions('trigger'); expect(list0).toHaveLength(0); - setup.addTriggerAction('trigger' as TriggerId, action1); - const list1 = start.getTriggerActions('trigger' as TriggerId); + setup.addTriggerAction('trigger', action1); + const list1 = start.getTriggerActions('trigger'); expect(list1).toHaveLength(1); expect(list1[0]).toBeInstanceOf(ActionInternal); expect(list1[0].id).toBe(action1.id); - setup.addTriggerAction('trigger' as TriggerId, action2); - const list2 = start.getTriggerActions('trigger' as TriggerId); + setup.addTriggerAction('trigger', action2); + const list2 = start.getTriggerActions('trigger'); expect(list2).toHaveLength(2); expect(!!list2.find(({ id }: any) => id === 'action1')).toBe(true); diff --git a/src/plugins/ui_actions/public/tests/get_trigger_compatible_actions.test.ts b/src/plugins/ui_actions/public/tests/get_trigger_compatible_actions.test.ts index 21dd17ed82e3f..400a9453fe267 100644 --- a/src/plugins/ui_actions/public/tests/get_trigger_compatible_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/get_trigger_compatible_actions.test.ts @@ -21,23 +21,23 @@ import { uiActionsPluginMock } from '../mocks'; import { createHelloWorldAction } from '../tests/test_samples'; import { Action, createAction } from '../actions'; import { Trigger } from '../triggers'; -import { TriggerId, ActionType } from '../types'; -let action: Action<{ name: string }, ActionType>; +let action: Action<{ name: string }>; let uiActions: ReturnType; beforeEach(() => { uiActions = uiActionsPluginMock.createPlugin(); action = createAction({ - type: 'test' as ActionType, + id: 'test', + type: 'test', execute: () => Promise.resolve(), }); uiActions.setup.registerAction(action); uiActions.setup.registerTrigger({ - id: 'trigger' as TriggerId, + id: 'trigger', title: 'trigger', }); - uiActions.setup.addTriggerAction('trigger' as TriggerId, action); + uiActions.setup.addTriggerAction('trigger', action); }); test('can register action', async () => { @@ -54,14 +54,14 @@ test('getTriggerCompatibleActions returns attached actions', async () => { setup.registerAction(helloWorldAction); const testTrigger: Trigger = { - id: 'MY-TRIGGER' as TriggerId, + id: 'MY-TRIGGER', title: 'My trigger', }; setup.registerTrigger(testTrigger); - setup.addTriggerAction('MY-TRIGGER' as TriggerId, helloWorldAction); + setup.addTriggerAction('MY-TRIGGER', helloWorldAction); const start = doStart(); - const actions = await start.getTriggerCompatibleActions('MY-TRIGGER' as TriggerId, {}); + const actions = await start.getTriggerCompatibleActions('MY-TRIGGER', {}); expect(actions.length).toBe(1); expect(actions[0].id).toBe(helloWorldAction.id); @@ -70,7 +70,8 @@ test('getTriggerCompatibleActions returns attached actions', async () => { test('filters out actions not applicable based on the context', async () => { const { setup, doStart } = uiActions; const action1 = createAction({ - type: 'test1' as ActionType, + id: 'test1', + type: 'test1', isCompatible: async (context: { accept: boolean }) => { return Promise.resolve(context.accept); }, @@ -78,7 +79,7 @@ test('filters out actions not applicable based on the context', async () => { }); const testTrigger: Trigger = { - id: 'MY-TRIGGER2' as TriggerId, + id: 'MY-TRIGGER2', title: 'My trigger', }; @@ -100,15 +101,15 @@ test(`throws an error with an invalid trigger ID`, async () => { const { doStart } = uiActions; const start = doStart(); - await expect( - start.getTriggerCompatibleActions('I do not exist' as TriggerId, {}) - ).rejects.toMatchObject(new Error('Trigger [triggerId = I do not exist] does not exist.')); + await expect(start.getTriggerCompatibleActions('I do not exist', {})).rejects.toMatchObject( + new Error('Trigger [triggerId = I do not exist] does not exist.') + ); }); test(`with a trigger mapping that maps to an non-existing action returns empty list`, async () => { const { setup, doStart } = uiActions; const testTrigger: Trigger = { - id: '123' as TriggerId, + id: '123', title: '123', }; setup.registerTrigger(testTrigger); diff --git a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx index a4cfe172dd109..f9e1c0261e1a1 100644 --- a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx +++ b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx @@ -20,9 +20,8 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiFlyoutBody } from '@elastic/eui'; import { CoreStart } from 'src/core/public'; -import { createAction, ActionByType } from '../../actions'; +import { createAction, Action } from '../../actions'; import { toMountPoint, reactToUiComponent } from '../../../../kibana_react/public'; -import { ActionType } from '../../types'; const ReactMenuItem: React.FC = () => { return ( @@ -37,14 +36,11 @@ const ReactMenuItem: React.FC = () => { const UiMenuItem = reactToUiComponent(ReactMenuItem); -// Casting to ActionType is a hack - in a real situation use -// declare module and add this id to ActionContextMapping. -export const ACTION_HELLO_WORLD = 'ACTION_HELLO_WORLD' as ActionType; +export const ACTION_HELLO_WORLD = 'ACTION_HELLO_WORLD'; -export function createHelloWorldAction( - overlays: CoreStart['overlays'] -): ActionByType { - return createAction({ +export function createHelloWorldAction(overlays: CoreStart['overlays']): Action { + return createAction({ + id: ACTION_HELLO_WORLD, type: ACTION_HELLO_WORLD, getIconType: () => 'lock', MenuItem: UiMenuItem, diff --git a/src/plugins/ui_actions/public/triggers/default_trigger.ts b/src/plugins/ui_actions/public/triggers/default_trigger.ts index 74be0243bdac5..107cb3bda5b7d 100644 --- a/src/plugins/ui_actions/public/triggers/default_trigger.ts +++ b/src/plugins/ui_actions/public/triggers/default_trigger.ts @@ -20,7 +20,7 @@ import { Trigger } from '.'; export const DEFAULT_TRIGGER = ''; -export const defaultTrigger: Trigger<''> = { +export const defaultTrigger: Trigger = { id: DEFAULT_TRIGGER, title: 'Unknown', description: 'Unknown trigger.', diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index ecbf4d1f7b988..6bba87e85eb95 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -20,10 +20,7 @@ export * from './trigger'; export * from './trigger_contract'; export * from './trigger_internal'; -export * from './select_range_trigger'; -export * from './value_click_trigger'; export * from './row_click_trigger'; -export * from './apply_filter_trigger'; export * from './visualize_field_trigger'; export * from './visualize_geo_field_trigger'; export * from './default_trigger'; diff --git a/src/plugins/ui_actions/public/triggers/row_click_trigger.ts b/src/plugins/ui_actions/public/triggers/row_click_trigger.ts index 87bca03f8c3ba..3d47e017675c3 100644 --- a/src/plugins/ui_actions/public/triggers/row_click_trigger.ts +++ b/src/plugins/ui_actions/public/triggers/row_click_trigger.ts @@ -18,13 +18,12 @@ */ import { i18n } from '@kbn/i18n'; -import { IEmbeddable } from '../../../embeddable/public'; import { Trigger } from '.'; import { Datatable } from '../../../expressions'; export const ROW_CLICK_TRIGGER = 'ROW_CLICK_TRIGGER'; -export const rowClickTrigger: Trigger<'ROW_CLICK_TRIGGER'> = { +export const rowClickTrigger: Trigger = { id: ROW_CLICK_TRIGGER, title: i18n.translate('uiActions.triggers.rowClickTitle', { defaultMessage: 'Table row click', @@ -35,7 +34,9 @@ export const rowClickTrigger: Trigger<'ROW_CLICK_TRIGGER'> = { }; export interface RowClickContext { - embeddable?: IEmbeddable; + // Need to make this unknown to prevent circular dependencies. + // Apps using this property will need to cast to `IEmbeddable`. + embeddable?: unknown; data: { /** * Row index, starting from 0, where user clicked. diff --git a/src/plugins/ui_actions/public/triggers/trigger.ts b/src/plugins/ui_actions/public/triggers/trigger.ts index 2c019b09881d1..b4def56d21395 100644 --- a/src/plugins/ui_actions/public/triggers/trigger.ts +++ b/src/plugins/ui_actions/public/triggers/trigger.ts @@ -17,8 +17,6 @@ * under the License. */ -import { TriggerContextMapping, TriggerId } from '../types'; - /** * This is a convenience interface used to register a *trigger*. * @@ -30,12 +28,11 @@ import { TriggerContextMapping, TriggerId } from '../types'; * trigger is *called* it first displays a context menu for user to pick a * single action to execute. */ -export interface Trigger { +export interface Trigger { /** - * Unique name of the trigger as identified in `ui_actions` plugin trigger - * registry, such as "SELECT_RANGE_TRIGGER" or "VALUE_CLICK_TRIGGER". + * Unique name of the trigger as identified in `ui_actions` plugin trigger registry. */ - id: ID; + id: string; /** * User friendly name of the trigger. @@ -47,5 +44,3 @@ export interface Trigger { */ description?: string; } - -export type TriggerContext = T extends TriggerId ? TriggerContextMapping[T] : never; diff --git a/src/plugins/ui_actions/public/triggers/trigger_contract.ts b/src/plugins/ui_actions/public/triggers/trigger_contract.ts index 04a75cb3a53d0..95e856f4d3eaa 100644 --- a/src/plugins/ui_actions/public/triggers/trigger_contract.ts +++ b/src/plugins/ui_actions/public/triggers/trigger_contract.ts @@ -18,17 +18,15 @@ */ import { TriggerInternal } from './trigger_internal'; -import { TriggerId, TriggerContextMapping } from '../types'; /** * This is a public representation of a trigger that is provided to other plugins. */ -export class TriggerContract { +export class TriggerContract { /** - * Unique name of the trigger as identified in `ui_actions` plugin trigger - * registry, such as "SELECT_RANGE_TRIGGER" or "VALUE_CLICK_TRIGGER". + * Unique name of the trigger as identified in `ui_actions` plugin trigger registry. */ - public readonly id: T; + public readonly id: string; /** * User friendly name of the trigger. @@ -40,7 +38,7 @@ export class TriggerContract { */ public readonly description?: string; - constructor(private readonly internal: TriggerInternal) { + constructor(private readonly internal: TriggerInternal) { this.id = this.internal.trigger.id; this.title = this.internal.trigger.title; this.description = this.internal.trigger.description; @@ -49,7 +47,7 @@ export class TriggerContract { /** * Use this method to execute action attached to this trigger. */ - public readonly exec = async (context: TriggerContextMapping[T], alwaysShowPopup?: boolean) => { + public readonly exec = async (context: Context, alwaysShowPopup?: boolean) => { await this.internal.execute(context, alwaysShowPopup); }; } diff --git a/src/plugins/ui_actions/public/triggers/trigger_internal.ts b/src/plugins/ui_actions/public/triggers/trigger_internal.ts index fd43a020504c0..e78b2beaabc8e 100644 --- a/src/plugins/ui_actions/public/triggers/trigger_internal.ts +++ b/src/plugins/ui_actions/public/triggers/trigger_internal.ts @@ -20,18 +20,17 @@ import { Trigger } from './trigger'; import { TriggerContract } from './trigger_contract'; import { UiActionsService } from '../service'; -import { TriggerId, TriggerContextMapping } from '../types'; /** * Internal representation of a trigger kept for consumption only internally * within `ui_actions` plugin. */ -export class TriggerInternal { - public readonly contract = new TriggerContract(this); +export class TriggerInternal { + public readonly contract: TriggerContract = new TriggerContract(this); - constructor(public readonly service: UiActionsService, public readonly trigger: Trigger) {} + constructor(public readonly service: UiActionsService, public readonly trigger: Trigger) {} - public async execute(context: TriggerContextMapping[T], alwaysShowPopup?: boolean) { + public async execute(context: Context, alwaysShowPopup?: boolean) { const triggerId = this.trigger.id; const actions = await this.service.getTriggerCompatibleActions!(triggerId, context); diff --git a/src/plugins/ui_actions/public/triggers/visualize_field_trigger.ts b/src/plugins/ui_actions/public/triggers/visualize_field_trigger.ts index 4f3c5f613eddf..0c85f4d38dee4 100644 --- a/src/plugins/ui_actions/public/triggers/visualize_field_trigger.ts +++ b/src/plugins/ui_actions/public/triggers/visualize_field_trigger.ts @@ -20,7 +20,7 @@ import { Trigger } from '.'; export const VISUALIZE_FIELD_TRIGGER = 'VISUALIZE_FIELD_TRIGGER'; -export const visualizeFieldTrigger: Trigger<'VISUALIZE_FIELD_TRIGGER'> = { +export const visualizeFieldTrigger: Trigger = { id: VISUALIZE_FIELD_TRIGGER, title: 'Visualize field', description: 'Triggered when user wants to visualize a field.', diff --git a/src/plugins/ui_actions/public/triggers/visualize_geo_field_trigger.ts b/src/plugins/ui_actions/public/triggers/visualize_geo_field_trigger.ts index 5582b3b42660c..0ee0be3a644d4 100644 --- a/src/plugins/ui_actions/public/triggers/visualize_geo_field_trigger.ts +++ b/src/plugins/ui_actions/public/triggers/visualize_geo_field_trigger.ts @@ -20,7 +20,7 @@ import { Trigger } from '.'; export const VISUALIZE_GEO_FIELD_TRIGGER = 'VISUALIZE_GEO_FIELD_TRIGGER'; -export const visualizeGeoFieldTrigger: Trigger<'VISUALIZE_GEO_FIELD_TRIGGER'> = { +export const visualizeGeoFieldTrigger: Trigger = { id: VISUALIZE_GEO_FIELD_TRIGGER, title: 'Visualize Geo field', description: 'Triggered when user wants to visualize a geo field.', diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 0266a755be926..dc3b25f69f513 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -19,22 +19,10 @@ import { ActionInternal } from './actions/action_internal'; import { TriggerInternal } from './triggers/trigger_internal'; -import { - SELECT_RANGE_TRIGGER, - VALUE_CLICK_TRIGGER, - ROW_CLICK_TRIGGER, - APPLY_FILTER_TRIGGER, - VISUALIZE_FIELD_TRIGGER, - VISUALIZE_GEO_FIELD_TRIGGER, - DEFAULT_TRIGGER, - RowClickContext, -} from './triggers'; -import type { RangeSelectContext, ValueClickContext } from '../../embeddable/public'; -import type { ApplyGlobalFilterActionContext } from '../../data/public'; -export type TriggerRegistry = Map>; +export type TriggerRegistry = Map>; export type ActionRegistry = Map; -export type TriggerToActionsRegistry = Map; +export type TriggerToActionsRegistry = Map; export interface VisualizeFieldContext { fieldName: string; @@ -42,30 +30,6 @@ export interface VisualizeFieldContext { contextualFields?: string[]; } -export type TriggerId = keyof TriggerContextMapping; - -export type BaseContext = object; -export type TriggerContext = BaseContext; - -export interface TriggerContextMapping { - [DEFAULT_TRIGGER]: TriggerContext; - [SELECT_RANGE_TRIGGER]: RangeSelectContext; - [VALUE_CLICK_TRIGGER]: ValueClickContext; - [ROW_CLICK_TRIGGER]: RowClickContext; - [APPLY_FILTER_TRIGGER]: ApplyGlobalFilterActionContext; - [VISUALIZE_FIELD_TRIGGER]: VisualizeFieldContext; - [VISUALIZE_GEO_FIELD_TRIGGER]: VisualizeFieldContext; -} - -const DEFAULT_ACTION = ''; export const ACTION_VISUALIZE_FIELD = 'ACTION_VISUALIZE_FIELD'; export const ACTION_VISUALIZE_GEO_FIELD = 'ACTION_VISUALIZE_GEO_FIELD'; export const ACTION_VISUALIZE_LENS_FIELD = 'ACTION_VISUALIZE_LENS_FIELD'; -export type ActionType = keyof ActionContextMapping; - -export interface ActionContextMapping { - [DEFAULT_ACTION]: BaseContext; - [ACTION_VISUALIZE_FIELD]: VisualizeFieldContext; - [ACTION_VISUALIZE_GEO_FIELD]: VisualizeFieldContext; - [ACTION_VISUALIZE_LENS_FIELD]: VisualizeFieldContext; -} diff --git a/src/plugins/ui_actions/public/util/presentable.ts b/src/plugins/ui_actions/public/util/presentable.ts index 59440d6c75976..c586a996920ac 100644 --- a/src/plugins/ui_actions/public/util/presentable.ts +++ b/src/plugins/ui_actions/public/util/presentable.ts @@ -22,7 +22,7 @@ import { UiComponent } from 'src/plugins/kibana_utils/public'; /** * Represents something that can be displayed to user in UI. */ -export interface Presentable { +export interface Presentable { /** * ID that uniquely identifies this object. */ @@ -77,11 +77,11 @@ export interface Presentable { readonly grouping?: PresentableGrouping; } -export interface PresentableGroup +export interface PresentableGroup extends Partial< Pick, 'getDisplayName' | 'getDisplayNameTooltip' | 'getIconType' | 'order'> > { id: string; } -export type PresentableGrouping = Array>; +export type PresentableGrouping = Array>; diff --git a/src/plugins/vis_default_editor/kibana.json b/src/plugins/vis_default_editor/kibana.json index 35ad0a3a8be9a..9664b14821c0d 100644 --- a/src/plugins/vis_default_editor/kibana.json +++ b/src/plugins/vis_default_editor/kibana.json @@ -2,5 +2,6 @@ "id": "visDefaultEditor", "version": "kibana", "ui": true, + "optionalPlugins": ["visualize"], "requiredBundles": ["kibanaUtils", "kibanaReact", "data"] } diff --git a/src/plugins/vis_default_editor/public/components/agg_add.tsx b/src/plugins/vis_default_editor/public/components/agg_add.tsx index e78f2fcc4453c..2da7b33139a8e 100644 --- a/src/plugins/vis_default_editor/public/components/agg_add.tsx +++ b/src/plugins/vis_default_editor/public/components/agg_add.tsx @@ -76,10 +76,17 @@ function DefaultEditorAggAdd({ ); - const isSchemaDisabled = (schema: Schema): boolean => { + const isMaxedCount = (schema: Schema): boolean => { const count = group.filter((agg) => agg.schema === schema.name).length; return count >= schema.max; }; + const isSchemaDisabled = (schema: Schema, maxedCount: boolean): boolean => { + return schema.disabled ?? maxedCount; + }; + const maxTooltipText = i18n.translate('visDefaultEditor.aggAdd.maxBuckets', { + defaultMessage: 'Max {groupNameLabel} count reached', + values: { groupNameLabel }, + }); return ( @@ -109,16 +116,21 @@ function DefaultEditorAggAdd({ )} ( - onSelectSchema(schema)} - > - {schema.title} - - ))} + items={schemas.map((schema) => { + const maxedCount = isMaxedCount(schema); + + return ( + onSelectSchema(schema)} + toolTipContent={schema.tooltip ?? (maxedCount ? maxTooltipText : undefined)} + > + {schema.title} + + ); + })} /> diff --git a/src/plugins/charts/public/static/components/basic_options.tsx b/src/plugins/vis_default_editor/public/components/options/basic_options.tsx similarity index 86% rename from src/plugins/charts/public/static/components/basic_options.tsx rename to src/plugins/vis_default_editor/public/components/options/basic_options.tsx index cac4c8d70d796..f67a9997cb5e2 100644 --- a/src/plugins/charts/public/static/components/basic_options.tsx +++ b/src/plugins/vis_default_editor/public/components/options/basic_options.tsx @@ -18,9 +18,10 @@ */ import React from 'react'; + import { i18n } from '@kbn/i18n'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; +import { VisOptionsProps } from '../../vis_options_props'; import { SwitchOption } from './switch'; import { SelectOption } from './select'; @@ -37,7 +38,7 @@ function BasicOptions({ return ( <> ({ setValue={setValue} /> void; @@ -71,7 +71,7 @@ function ColorRanges({ return ( ( paramName: T, @@ -67,7 +66,7 @@ function ColorSchemaOptions({ }} > @@ -80,11 +79,11 @@ function ColorSchemaOptions({ disabled={disabled} helpText={ showHelpText && - i18n.translate('charts.controls.colorSchema.howToChangeColorsDescription', { + i18n.translate('visDefaultEditor.options.colorSchema.howToChangeColorsDescription', { defaultMessage: 'Individual colors can be changed in the legend.', }) } - label={i18n.translate('charts.controls.colorSchema.colorSchemaLabel', { + label={i18n.translate('visDefaultEditor.options.colorSchema.colorSchemaLabel', { defaultMessage: 'Color schema', })} labelAppend={isCustomColors && resetColorsButton} @@ -96,7 +95,7 @@ function ColorSchemaOptions({ ({ const [stateValue, setStateValue] = useState(value); const [isValidState, setIsValidState] = useState(true); - const error = i18n.translate('charts.controls.rangeErrorMessage', { + const error = i18n.translate('visDefaultEditor.options.rangeErrorMessage', { defaultMessage: 'Values must be on or between {min} and {max}', values: { min, max }, }); diff --git a/src/plugins/charts/public/static/components/required_number_input.tsx b/src/plugins/vis_default_editor/public/components/options/required_number_input.tsx similarity index 100% rename from src/plugins/charts/public/static/components/required_number_input.tsx rename to src/plugins/vis_default_editor/public/components/options/required_number_input.tsx diff --git a/src/plugins/charts/public/static/components/select.tsx b/src/plugins/vis_default_editor/public/components/options/select.tsx similarity index 100% rename from src/plugins/charts/public/static/components/select.tsx rename to src/plugins/vis_default_editor/public/components/options/select.tsx diff --git a/src/plugins/charts/public/static/components/switch.tsx b/src/plugins/vis_default_editor/public/components/options/switch.tsx similarity index 100% rename from src/plugins/charts/public/static/components/switch.tsx rename to src/plugins/vis_default_editor/public/components/options/switch.tsx diff --git a/src/plugins/charts/public/static/components/text_input.tsx b/src/plugins/vis_default_editor/public/components/options/text_input.tsx similarity index 100% rename from src/plugins/charts/public/static/components/text_input.tsx rename to src/plugins/vis_default_editor/public/components/options/text_input.tsx diff --git a/src/plugins/vis_default_editor/public/components/sidebar/use_option_tabs.ts b/src/plugins/vis_default_editor/public/components/sidebar/use_option_tabs.ts index 337533df50fad..90e2d792d3597 100644 --- a/src/plugins/vis_default_editor/public/components/sidebar/use_option_tabs.ts +++ b/src/plugins/vis_default_editor/public/components/sidebar/use_option_tabs.ts @@ -20,9 +20,10 @@ import { useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { Vis } from 'src/plugins/visualizations/public'; -import { DefaultEditorDataTab, DefaultEditorDataTabProps } from './data_tab'; +import { Vis } from '../../../../visualizations/public'; + import { VisOptionsProps } from '../../vis_options_props'; +import { DefaultEditorDataTab, DefaultEditorDataTabProps } from './data_tab'; export interface OptionTab { editor: React.ComponentType; diff --git a/src/plugins/vis_default_editor/public/default_editor_controller.tsx b/src/plugins/vis_default_editor/public/default_editor_controller.tsx index 707b14c23ea75..f44ea3e203b05 100644 --- a/src/plugins/vis_default_editor/public/default_editor_controller.tsx +++ b/src/plugins/vis_default_editor/public/default_editor_controller.tsx @@ -25,6 +25,7 @@ import { EuiErrorBoundary, EuiLoadingChart } from '@elastic/eui'; import { EditorRenderProps, IEditorController } from 'src/plugins/visualize/public'; import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public'; +// @ts-ignore const DefaultEditor = lazy(() => import('./default_editor')); class DefaultEditorController implements IEditorController { diff --git a/src/plugins/vis_default_editor/public/index.ts b/src/plugins/vis_default_editor/public/index.ts index d7eb5eda7bdfe..fd1bdf8b2e65d 100644 --- a/src/plugins/vis_default_editor/public/index.ts +++ b/src/plugins/vis_default_editor/public/index.ts @@ -17,18 +17,19 @@ * under the License. */ -export { DefaultEditorController } from './default_editor_controller'; +import { PluginInitializerContext } from 'kibana/public'; +import { DefaultEditorController } from './default_editor_controller'; +import { VisDefaultEditorPlugin } from './plugin'; + +export { DefaultEditorController }; export { useValidation } from './components/controls/utils'; +export * from './components/options'; export { RangesParamEditor, RangeValues } from './components/controls/ranges'; export * from './editor_size'; export * from './vis_options_props'; export * from './utils'; export { ISchemas, Schemas, Schema } from './schemas'; -/** dummy plugin, we just want visDefaultEditor to have its own bundle */ -export function plugin() { - return new (class VisDefaultEditor { - setup() {} - start() {} - })(); -} +export const plugin = (context: PluginInitializerContext) => { + return new VisDefaultEditorPlugin(); +}; diff --git a/src/plugins/vis_default_editor/public/plugin.ts b/src/plugins/vis_default_editor/public/plugin.ts new file mode 100644 index 0000000000000..a7a5c6146a6e8 --- /dev/null +++ b/src/plugins/vis_default_editor/public/plugin.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreSetup, Plugin } from 'kibana/public'; + +import { VisualizePluginSetup } from '../../visualize/public'; +import { DefaultEditorController } from './default_editor_controller'; + +export interface VisDefaultEditorSetupDependencies { + visualize: VisualizePluginSetup; +} + +export class VisDefaultEditorPlugin + implements Plugin { + public setup(core: CoreSetup, { visualize }: VisDefaultEditorSetupDependencies) { + if (visualize) { + visualize.setDefaultEditor(DefaultEditorController); + } + } + + public start() {} + + stop() {} +} diff --git a/src/plugins/vis_default_editor/public/schemas.ts b/src/plugins/vis_default_editor/public/schemas.ts index d95a6252331bf..7ecb4e54726b8 100644 --- a/src/plugins/vis_default_editor/public/schemas.ts +++ b/src/plugins/vis_default_editor/public/schemas.ts @@ -17,6 +17,7 @@ * under the License. */ +import { ReactNode } from 'react'; import _, { defaults } from 'lodash'; import { Optional } from '@kbn/utility-types'; @@ -42,6 +43,8 @@ export interface Schema { hideCustomLabel?: boolean; mustBeFirst?: boolean; aggSettings?: any; + disabled?: boolean; + tooltip?: ReactNode; } export class Schemas implements ISchemas { diff --git a/src/plugins/vis_type_markdown/kibana.json b/src/plugins/vis_type_markdown/kibana.json index c0afcb0e99d13..6cfedf60687ef 100644 --- a/src/plugins/vis_type_markdown/kibana.json +++ b/src/plugins/vis_type_markdown/kibana.json @@ -4,5 +4,5 @@ "ui": true, "server": true, "requiredPlugins": ["expressions", "visualizations"], - "requiredBundles": ["kibanaReact", "charts", "visualizations", "expressions", "visDefaultEditor"] + "requiredBundles": ["kibanaReact", "visualizations", "expressions", "visDefaultEditor"] } diff --git a/src/plugins/vis_type_markdown/public/__snapshots__/markdown_options.test.tsx.snap b/src/plugins/vis_type_markdown/public/__snapshots__/markdown_options.test.tsx.snap new file mode 100644 index 0000000000000..03431fe2437b7 --- /dev/null +++ b/src/plugins/vis_type_markdown/public/__snapshots__/markdown_options.test.tsx.snap @@ -0,0 +1,68 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MarkdownOptions should match snapshot 1`] = ` + + + + + + +

+ +

+
+
+ + + + + + + +
+
+ + + +
+
+`; diff --git a/src/plugins/vis_type_markdown/public/markdown_options.test.tsx b/src/plugins/vis_type_markdown/public/markdown_options.test.tsx new file mode 100644 index 0000000000000..170dde7ee91e6 --- /dev/null +++ b/src/plugins/vis_type_markdown/public/markdown_options.test.tsx @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; +import { MarkdownVisParams } from './types'; +import { MarkdownOptions } from './markdown_options'; + +describe('MarkdownOptions', () => { + const props = ({ + stateParams: { + fontSize: 12, + markdown: 'hello from 2020 🥳', + openLinksInNewTab: false, + }, + setValue: jest.fn(), + } as unknown) as VisOptionsProps; + + it('should match snapshot', () => { + const comp = shallow(); + expect(comp).toMatchSnapshot(); + }); + + it('should update markdown on change', () => { + const comp = shallow(); + const value = 'see you in 2021 😎'; + const textArea = comp.find('EuiTextArea'); + const onChange = textArea.prop('onChange'); + onChange?.({ + target: { + // @ts-expect-error + value, + }, + }); + + expect(props.setValue).toHaveBeenCalledWith('markdown', value); + }); +}); diff --git a/src/plugins/vis_type_markdown/public/markdown_options.tsx b/src/plugins/vis_type_markdown/public/markdown_options.tsx index a6349793619a0..674fbeb517510 100644 --- a/src/plugins/vis_type_markdown/public/markdown_options.tsx +++ b/src/plugins/vis_type_markdown/public/markdown_options.tsx @@ -22,7 +22,6 @@ import { EuiPanel, EuiTitle, EuiLink, - EuiIcon, EuiTextArea, EuiFlexGroup, EuiFlexItem, @@ -35,7 +34,7 @@ import { MarkdownVisParams } from './types'; function MarkdownOptions({ stateParams, setValue }: VisOptionsProps) { const onMarkdownUpdate = useCallback( - (value: MarkdownVisParams['markdown']) => setValue('markdown', value), + ({ target: { value } }: React.ChangeEvent) => setValue('markdown', value), [setValue] ); @@ -61,8 +60,7 @@ function MarkdownOptions({ stateParams, setValue }: VisOptionsProps{' '} - + /> @@ -74,7 +72,7 @@ function MarkdownOptions({ stateParams, setValue }: VisOptionsProps onMarkdownUpdate(value)} + onChange={onMarkdownUpdate} fullWidth={true} data-test-subj="markdownTextarea" resize="none" diff --git a/src/plugins/vis_type_markdown/public/settings_options.tsx b/src/plugins/vis_type_markdown/public/settings_options.tsx index bf4570db5d4a0..1b793ca573f82 100644 --- a/src/plugins/vis_type_markdown/public/settings_options.tsx +++ b/src/plugins/vis_type_markdown/public/settings_options.tsx @@ -21,8 +21,7 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { RangeOption, SwitchOption } from '../../charts/public'; +import { VisOptionsProps, SwitchOption, RangeOption } from '../../vis_default_editor/public'; import { MarkdownVisParams } from './types'; function SettingsOptions({ stateParams, setValue }: VisOptionsProps) { diff --git a/src/plugins/vis_type_markdown/public/to_ast.test.ts b/src/plugins/vis_type_markdown/public/to_ast.test.ts index 1ad1fa0ee2517..4c7b570aef05d 100644 --- a/src/plugins/vis_type_markdown/public/to_ast.test.ts +++ b/src/plugins/vis_type_markdown/public/to_ast.test.ts @@ -42,12 +42,14 @@ describe('markdown vis toExpressionAst function', () => { it('without params', () => { vis.params = {}; + // @ts-expect-error const actual = toExpressionAst(vis); expect(actual).toMatchSnapshot(); }); it('with params', () => { vis.params = { markdown: '### my markdown', fontSize: 15, openLinksInNewTab: true }; + // @ts-expect-error const actual = toExpressionAst(vis); expect(actual).toMatchSnapshot(); }); diff --git a/src/plugins/vis_type_markdown/public/to_ast.ts b/src/plugins/vis_type_markdown/public/to_ast.ts index 9b481218b42ea..dc61acf722ad4 100644 --- a/src/plugins/vis_type_markdown/public/to_ast.ts +++ b/src/plugins/vis_type_markdown/public/to_ast.ts @@ -17,11 +17,11 @@ * under the License. */ -import { Vis } from '../../visualizations/public'; +import { VisToExpressionAst } from '../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../expressions/public'; import { MarkdownVisExpressionFunctionDefinition } from './markdown_fn'; -export const toExpressionAst = (vis: Vis) => { +export const toExpressionAst: VisToExpressionAst = (vis) => { const { markdown, fontSize, openLinksInNewTab } = vis.params; const markdownVis = buildExpressionFunction( diff --git a/src/plugins/vis_type_metric/public/components/metric_vis_options.tsx b/src/plugins/vis_type_metric/public/components/metric_vis_options.tsx index d0a7412238871..58c486dfa90ab 100644 --- a/src/plugins/vis_type_metric/public/components/metric_vis_options.tsx +++ b/src/plugins/vis_type_metric/public/components/metric_vis_options.tsx @@ -29,16 +29,16 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; import { - ColorModes, ColorRanges, - ColorSchemaOptions, + SetColorRangeValue, + VisOptionsProps, SwitchOption, - RangeOption, SetColorSchemaOptionsValue, - SetColorRangeValue, -} from '../../../charts/public'; + ColorSchemaOptions, + RangeOption, +} from '../../../vis_default_editor/public'; +import { ColorMode } from '../../../charts/public'; import { MetricVisParam, VisParams } from '../types'; function MetricVisOptions({ @@ -86,7 +86,7 @@ function MetricVisOptions({ ); const setColorMode: EuiButtonGroupProps['onChange'] = useCallback( - (id: string) => setMetricValue('metricColorMode', id as ColorModes), + (id: string) => setMetricValue('metricColorMode', id as ColorMode), [setMetricValue] ); @@ -158,7 +158,7 @@ function MetricVisOptions({ colorSchemas={vis.type.editorConfig.collections.colorSchemas} disabled={ stateParams.metric.colorsRange.length === 1 || - stateParams.metric.metricColorMode === ColorModes.NONE + stateParams.metric.metricColorMode === ColorMode.None } invertColors={stateParams.metric.invertColors} setValue={setMetricValue as SetColorSchemaOptionsValue} diff --git a/src/plugins/vis_type_metric/public/metric_vis_fn.ts b/src/plugins/vis_type_metric/public/metric_vis_fn.ts index 20de22f50e63a..783ca3d3906ea 100644 --- a/src/plugins/vis_type_metric/public/metric_vis_fn.ts +++ b/src/plugins/vis_type_metric/public/metric_vis_fn.ts @@ -27,14 +27,14 @@ import { Style, } from '../../expressions/public'; import { visType, DimensionsVisParam, VisParams } from './types'; -import { ColorSchemas, vislibColorMaps, ColorModes } from '../../charts/public'; +import { ColorSchemas, vislibColorMaps, ColorMode } from '../../charts/public'; export type Input = Datatable; interface Arguments { percentageMode: boolean; colorSchema: ColorSchemas; - colorMode: ColorModes; + colorMode: ColorMode; useRanges: boolean; invertColors: boolean; showLabels: boolean; @@ -86,7 +86,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ colorMode: { types: ['string'], default: '"None"', - options: [ColorModes.NONE, ColorModes.LABELS, ColorModes.BACKGROUND], + options: [ColorMode.None, ColorMode.Labels, ColorMode.Background], help: i18n.translate('visTypeMetric.function.colorMode.help', { defaultMessage: 'Which part of metric to color', }), @@ -160,7 +160,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ }), }, }, - fn(input, args) { + fn(input, args, handlers) { const dimensions: DimensionsVisParam = { metrics: args.metric, }; @@ -175,6 +175,9 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ const fontSize = Number.parseInt(args.font.spec.fontSize || '', 10); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'metric_vis', @@ -194,8 +197,8 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ invertColors: args.invertColors, style: { bgFill: args.bgFill, - bgColor: args.colorMode === ColorModes.BACKGROUND, - labelColor: args.colorMode === ColorModes.LABELS, + bgColor: args.colorMode === ColorMode.Background, + labelColor: args.colorMode === ColorMode.Labels, subText: args.subText, fontSize, }, diff --git a/src/plugins/vis_type_metric/public/metric_vis_type.ts b/src/plugins/vis_type_metric/public/metric_vis_type.ts index f7c74e324053e..ba8f27b9412a2 100644 --- a/src/plugins/vis_type_metric/public/metric_vis_type.ts +++ b/src/plugins/vis_type_metric/public/metric_vis_type.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { BaseVisTypeOptions } from 'src/plugins/visualizations/public'; import { MetricVisOptions } from './components/metric_vis_options'; -import { ColorSchemas, colorSchemas, ColorModes } from '../../charts/public'; +import { ColorSchemas, colorSchemas, ColorMode } from '../../charts/public'; import { AggGroupNames } from '../../data/public'; import { Schemas } from '../../vis_default_editor/public'; import { toExpressionAst } from './to_ast'; @@ -42,7 +42,7 @@ export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({ percentageMode: false, useRanges: false, colorSchema: ColorSchemas.GreenToRed, - metricColorMode: ColorModes.NONE, + metricColorMode: ColorMode.None, colorsRange: [{ from: 0, to: 10000 }], labels: { show: true, @@ -62,19 +62,19 @@ export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({ collections: { metricColorMode: [ { - id: ColorModes.NONE, + id: ColorMode.None, label: i18n.translate('visTypeMetric.colorModes.noneOptionLabel', { defaultMessage: 'None', }), }, { - id: ColorModes.LABELS, + id: ColorMode.Labels, label: i18n.translate('visTypeMetric.colorModes.labelsOptionLabel', { defaultMessage: 'Labels', }), }, { - id: ColorModes.BACKGROUND, + id: ColorMode.Background, label: i18n.translate('visTypeMetric.colorModes.backgroundOptionLabel', { defaultMessage: 'Background', }), diff --git a/src/plugins/vis_type_metric/public/types.ts b/src/plugins/vis_type_metric/public/types.ts index e1f2c7721a426..e0ebfb36fa37d 100644 --- a/src/plugins/vis_type_metric/public/types.ts +++ b/src/plugins/vis_type_metric/public/types.ts @@ -19,7 +19,7 @@ import { Range } from '../../expressions/public'; import { SchemaConfig } from '../../visualizations/public'; -import { ColorModes, Labels, Style, ColorSchemas } from '../../charts/public'; +import { ColorMode, Labels, Style, ColorSchemas } from '../../charts/public'; export const visType = 'metric'; @@ -32,7 +32,7 @@ export interface MetricVisParam { percentageMode: boolean; useRanges: boolean; colorSchema: ColorSchemas; - metricColorMode: ColorModes; + metricColorMode: ColorMode; colorsRange: Range[]; labels: Labels; invertColors: boolean; diff --git a/src/plugins/vis_type_table/kibana.json b/src/plugins/vis_type_table/kibana.json index dce9bce0e8886..1fb8516851ebd 100644 --- a/src/plugins/vis_type_table/kibana.json +++ b/src/plugins/vis_type_table/kibana.json @@ -13,7 +13,6 @@ "kibanaUtils", "kibanaReact", "share", - "charts", "visDefaultEditor" ], "optionalPlugins": ["usageCollection"] diff --git a/src/plugins/vis_type_table/public/components/table_vis_options.tsx b/src/plugins/vis_type_table/public/components/table_vis_options.tsx index b81f0425011da..3932db1262acf 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_options.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_options.tsx @@ -23,9 +23,13 @@ import { EuiIconTip, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; import { search } from '../../../data/public'; -import { SwitchOption, SelectOption, NumberInputOption } from '../../../charts/public'; +import { + SwitchOption, + SelectOption, + NumberInputOption, + VisOptionsProps, +} from '../../../vis_default_editor/public'; import { TableVisParams } from '../types'; import { totalAggregations } from './utils'; diff --git a/src/plugins/vis_type_table/public/components/table_visualization.tsx b/src/plugins/vis_type_table/public/components/table_visualization.tsx index 2d38acc57519f..a1e4fad719dc4 100644 --- a/src/plugins/vis_type_table/public/components/table_visualization.tsx +++ b/src/plugins/vis_type_table/public/components/table_visualization.tsx @@ -23,6 +23,7 @@ import classNames from 'classnames'; import { CoreStart } from 'kibana/public'; import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import type { PersistedState } from 'src/plugins/visualizations/public'; import { KibanaContextProvider } from '../../../kibana_react/public'; import { TableVisConfig } from '../types'; import { TableContext } from '../table_vis_response_handler'; @@ -47,7 +48,7 @@ const TableVisualizationComponent = ({ handlers.done(); }, [handlers]); - const uiStateProps = useUiState(handlers.uiState); + const uiStateProps = useUiState(handlers.uiState as PersistedState); const className = classNames('tbvChart', { // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/src/plugins/vis_type_table/public/table_vis_fn.ts b/src/plugins/vis_type_table/public/table_vis_fn.ts index 28990f28caf31..530f50ffd89b6 100644 --- a/src/plugins/vis_type_table/public/table_vis_fn.ts +++ b/src/plugins/vis_type_table/public/table_vis_fn.ts @@ -55,10 +55,13 @@ export const createTableVisFn = (): TableExpressionFunctionDefinition => ({ help: '', }, }, - fn(input, args) { + fn(input, args, handlers) { const visConfig = args.visConfig && JSON.parse(args.visConfig); const convertedData = tableVisResponseHandler(input, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'table_vis', diff --git a/src/plugins/vis_type_table/public/utils/use/use_ui_state.ts b/src/plugins/vis_type_table/public/utils/use/use_ui_state.ts index 68bad16972ec2..cc43fc6bcb582 100644 --- a/src/plugins/vis_type_table/public/utils/use/use_ui_state.ts +++ b/src/plugins/vis_type_table/public/utils/use/use_ui_state.ts @@ -19,7 +19,7 @@ import { debounce, isEqual } from 'lodash'; import { useCallback, useEffect, useRef, useState } from 'react'; -import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import type { PersistedState } from 'src/plugins/visualizations/public'; import { ColumnWidthData, TableVisUiState, TableVisUseUiStateProps } from '../../types'; @@ -28,9 +28,7 @@ const defaultSort = { direction: null, }; -export const useUiState = ( - uiState: IInterpreterRenderHandlers['uiState'] -): TableVisUseUiStateProps => { +export const useUiState = (uiState: PersistedState): TableVisUseUiStateProps => { const [sort, setSortState] = useState( uiState?.get('vis.params.sort') || defaultSort ); diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx index d33576e4e5529..5d5f499d650b4 100644 --- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx +++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx @@ -20,9 +20,8 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { VisOptionsProps } from '../../../vis_default_editor/public'; +import { VisOptionsProps, SelectOption, SwitchOption } from '../../../vis_default_editor/public'; import { ValidatedDualRange } from '../../../kibana_react/public'; -import { SelectOption, SwitchOption } from '../../../charts/public'; import { TagCloudVisParams } from '../types'; function TagCloudOptions({ stateParams, setValue, vis }: VisOptionsProps) { diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts b/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts index ff59572e0817d..3ed203dd22ef4 100644 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts +++ b/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts @@ -95,7 +95,7 @@ export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({ }), }, }, - fn(input, args) { + fn(input, args, handlers) { const visParams = { scale: args.scale, orientation: args.orientation, @@ -109,6 +109,9 @@ export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({ visParams.bucket = args.bucket; } + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'tagloud_vis', diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap index 7ded8e2254aa9..fceb9c3fdb819 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap +++ b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`src/legacy/core_plugins/metrics/public/visualizations/views/timeseries/decorators/area_decorator.js should render and match a snapshot 1`] = ` - should render and match a snapshot 1`] = ` - , domNode diff --git a/src/plugins/vis_type_timeseries/server/routes/fields.ts b/src/plugins/vis_type_timeseries/server/routes/fields.ts index a9a890845d154..e787fd8d08a29 100644 --- a/src/plugins/vis_type_timeseries/server/routes/fields.ts +++ b/src/plugins/vis_type_timeseries/server/routes/fields.ts @@ -39,7 +39,7 @@ export const fieldsRoutes = (framework: Framework) => { return res.customError({ body: err.output.payload, statusCode: err.output.statusCode, - headers: err.output.headers, + headers: err.output.headers as { [key: string]: string }, }); } diff --git a/src/plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_type_timeseries/server/routes/vis.ts index bba086720da0a..3ed9aaaaea226 100644 --- a/src/plugins/vis_type_timeseries/server/routes/vis.ts +++ b/src/plugins/vis_type_timeseries/server/routes/vis.ts @@ -19,6 +19,7 @@ import { IRouter, KibanaRequest } from 'kibana/server'; import { schema } from '@kbn/config-schema'; +import { ensureNoUnsafeProperties } from '@kbn/std'; import { getVisData, GetVisDataOptions } from '../lib/get_vis_data'; import { visPayloadSchema } from '../../common/vis_schema'; import { ROUTES } from '../../common/constants'; @@ -40,6 +41,14 @@ export const visDataRoutes = ( }, }, async (requestContext, request, response) => { + try { + ensureNoUnsafeProperties(request.body); + } catch (error) { + return response.badRequest({ + body: error.message, + }); + } + try { visPayloadSchema.validate(request.body); } catch (error) { diff --git a/src/plugins/vis_type_vislib/kibana.json b/src/plugins/vis_type_vislib/kibana.json index 720abff16b7c7..175c21f47c182 100644 --- a/src/plugins/vis_type_vislib/kibana.json +++ b/src/plugins/vis_type_vislib/kibana.json @@ -4,6 +4,5 @@ "server": true, "ui": true, "requiredPlugins": ["charts", "data", "expressions", "visualizations", "kibanaLegacy"], - "optionalPlugins": ["visTypeXy"], - "requiredBundles": ["kibanaUtils", "visDefaultEditor"] + "requiredBundles": ["kibanaUtils", "visDefaultEditor", "visTypeXy"] } diff --git a/src/plugins/vis_type_vislib/public/area.ts b/src/plugins/vis_type_vislib/public/area.ts index ec7bce254f586..389daca6d1776 100644 --- a/src/plugins/vis_type_vislib/public/area.ts +++ b/src/plugins/vis_type_vislib/public/area.ts @@ -17,172 +17,14 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { palettes } from '@elastic/eui/lib/services'; -// @ts-ignore -import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; +import { xyVisTypes } from '../../vis_type_xy/public'; +import { BaseVisTypeOptions } from '../../visualizations/public'; -import { AggGroupNames } from '../../data/public'; -import { Schemas } from '../../vis_default_editor/public'; -import { - Positions, - ChartTypes, - ChartModes, - InterpolationModes, - AxisTypes, - ScaleTypes, - AxisModes, - ThresholdLineStyles, - getConfigCollections, -} from './utils/collections'; -import { getAreaOptionTabs, countLabel } from './utils/common_config'; -import { Rotates } from '../../charts/public'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; export const areaVisTypeDefinition: BaseVisTypeOptions = { - name: 'area', - title: i18n.translate('visTypeVislib.area.areaTitle', { defaultMessage: 'Area' }), - icon: 'visArea', - description: i18n.translate('visTypeVislib.area.areaDescription', { - defaultMessage: 'Emphasize the data between an axis and a line.', - }), - getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush], + ...(xyVisTypes.area() as BaseVisTypeOptions), toExpressionAst, - visConfig: { - defaults: { - type: 'area', - grid: { - categoryLines: false, - }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: AxisTypes.CATEGORY, - position: Positions.BOTTOM, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - }, - labels: { - show: true, - filter: true, - truncate: 100, - }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: AxisTypes.VALUE, - position: Positions.LEFT, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - mode: AxisModes.NORMAL, - }, - labels: { - show: true, - rotate: Rotates.HORIZONTAL, - filter: false, - truncate: 100, - }, - title: { - text: countLabel, - }, - }, - ], - seriesParams: [ - { - show: true, - type: ChartTypes.AREA, - mode: ChartModes.STACKED, - data: { - label: countLabel, - id: '1', - }, - drawLinesBetweenPoints: true, - lineWidth: 2, - showCircles: true, - interpolate: InterpolationModes.LINEAR, - valueAxis: 'ValueAxis-1', - }, - ], - addTooltip: true, - addLegend: true, - legendPosition: Positions.RIGHT, - times: [], - addTimeMarker: false, - thresholdLine: { - show: false, - value: 10, - width: 1, - style: ThresholdLineStyles.FULL, - color: euiPaletteColorBlind()[9], - }, - labels: {}, - }, - }, - editorConfig: { - collections: getConfigCollections(), - optionTabs: getAreaOptionTabs(), - schemas: new Schemas([ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeVislib.area.metricsTitle', { - defaultMessage: 'Y-axis', - }), - aggFilter: ['!geo_centroid', '!geo_bounds'], - min: 1, - defaults: [{ schema: 'metric', type: 'count' }], - }, - { - group: AggGroupNames.Metrics, - name: 'radius', - title: i18n.translate('visTypeVislib.area.radiusTitle', { - defaultMessage: 'Dot size', - }), - min: 0, - max: 1, - aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'], - }, - { - group: AggGroupNames.Buckets, - name: 'segment', - title: i18n.translate('visTypeVislib.area.segmentTitle', { - defaultMessage: 'X-axis', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'group', - title: i18n.translate('visTypeVislib.area.groupTitle', { - defaultMessage: 'Split series', - }), - min: 0, - max: 3, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'split', - title: i18n.translate('visTypeVislib.area.splitTitle', { - defaultMessage: 'Split chart', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - ]), - }, + visualization: undefined, }; diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx b/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx deleted file mode 100644 index 63881fea1ad88..0000000000000 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; -import { mount, shallow } from 'enzyme'; - -import { IAggConfig, IAggType } from 'src/plugins/data/public'; -import MetricsAxisOptions from './index'; -import { BasicVislibParams, SeriesParam, ValueAxis } from '../../../types'; -import { ValidationVisOptionsProps } from '../../common'; -import { Positions } from '../../../utils/collections'; -import { ValueAxesPanel } from './value_axes_panel'; -import { CategoryAxisPanel } from './category_axis_panel'; -import { ChartTypes } from '../../../utils/collections'; -import { defaultValueAxisId, valueAxis, seriesParam, categoryAxis } from './mocks'; - -jest.mock('./series_panel', () => ({ - SeriesPanel: () => 'SeriesPanel', -})); -jest.mock('./category_axis_panel', () => ({ - CategoryAxisPanel: () => 'CategoryAxisPanel', -})); -jest.mock('./value_axes_panel', () => ({ - ValueAxesPanel: () => 'ValueAxesPanel', -})); - -const SERIES_PARAMS = 'seriesParams'; -const VALUE_AXES = 'valueAxes'; - -const aggCount: IAggConfig = { - id: '1', - type: { name: 'count' }, - makeLabel: () => 'Count', -} as IAggConfig; - -const aggAverage: IAggConfig = { - id: '2', - type: { name: 'average' } as IAggType, - makeLabel: () => 'Average', -} as IAggConfig; - -const createAggs = (aggs: any[]) => ({ - aggs, - bySchemaName: () => aggs, -}); - -describe('MetricsAxisOptions component', () => { - let setValue: jest.Mock; - let defaultProps: ValidationVisOptionsProps; - let axis: ValueAxis; - let axisRight: ValueAxis; - let chart: SeriesParam; - - beforeEach(() => { - setValue = jest.fn(); - - axis = { - ...valueAxis, - name: 'LeftAxis-1', - position: Positions.LEFT, - }; - axisRight = { - ...valueAxis, - id: 'ValueAxis-2', - name: 'RightAxis-1', - position: Positions.RIGHT, - }; - chart = { - ...seriesParam, - type: ChartTypes.AREA, - }; - - defaultProps = { - aggs: createAggs([aggCount]), - isTabSelected: true, - vis: { - type: { - type: ChartTypes.AREA, - schemas: { metrics: [{ name: 'metric' }] }, - }, - setState: jest.fn(), - serialize: jest.fn(), - }, - stateParams: { - valueAxes: [axis], - seriesParams: [chart], - categoryAxes: [categoryAxis], - grid: { valueAxis: defaultValueAxisId }, - }, - setValue, - } as any; - }); - - it('should init with the default set of props', () => { - const comp = shallow(); - - expect(comp).toMatchSnapshot(); - }); - - describe('useEffect', () => { - it('should update series when new agg is added', () => { - const comp = mount(); - comp.setProps({ - aggs: createAggs([aggCount, aggAverage]), - }); - - const updatedSeries = [chart, { ...chart, data: { id: '2', label: aggAverage.makeLabel() } }]; - expect(setValue).toHaveBeenLastCalledWith(SERIES_PARAMS, updatedSeries); - }); - - it('should update series when new agg label is changed', () => { - const comp = mount(); - const agg = { id: aggCount.id, makeLabel: () => 'New label' }; - comp.setProps({ - aggs: createAggs([agg]), - }); - - const updatedSeries = [{ ...chart, data: { id: agg.id, label: agg.makeLabel() } }]; - expect(setValue).toHaveBeenCalledWith(SERIES_PARAMS, updatedSeries); - }); - }); - - describe('updateAxisTitle', () => { - it('should not update the value axis title if custom title was set', () => { - defaultProps.stateParams.valueAxes[0].title.text = 'Custom title'; - const comp = mount(); - const newAgg = { - ...aggCount, - makeLabel: () => 'Custom label', - }; - comp.setProps({ - aggs: createAggs([newAgg]), - }); - const updatedValues = [{ ...axis, title: { text: newAgg.makeLabel() } }]; - expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES, updatedValues); - }); - - it('should set the custom title to match the value axis label when only one agg exists for that axis', () => { - const comp = mount(); - const agg = { - id: aggCount.id, - params: { customLabel: 'Custom label' }, - makeLabel: () => 'Custom label', - }; - comp.setProps({ - aggs: createAggs([agg]), - }); - - const updatedSeriesParams = [{ ...chart, data: { ...chart.data, label: agg.makeLabel() } }]; - const updatedValues = [{ ...axis, title: { text: agg.makeLabel() } }]; - - expect(setValue).toHaveBeenCalledTimes(5); - expect(setValue).toHaveBeenNthCalledWith(3, SERIES_PARAMS, updatedSeriesParams); - expect(setValue).toHaveBeenNthCalledWith(5, SERIES_PARAMS, updatedSeriesParams); - expect(setValue).toHaveBeenNthCalledWith(4, VALUE_AXES, updatedValues); - }); - - it('should not set the custom title to match the value axis label when more than one agg exists for that axis', () => { - const comp = mount(); - const agg = { id: aggCount.id, makeLabel: () => 'Custom label' }; - comp.setProps({ - aggs: createAggs([agg, aggAverage]), - stateParams: { - ...defaultProps.stateParams, - seriesParams: [chart, chart], - }, - }); - - expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES); - }); - - it('should not overwrite the custom title with the value axis label if the custom title has been changed', () => { - defaultProps.stateParams.valueAxes[0].title.text = 'Custom title'; - const comp = mount(); - const agg = { - id: aggCount.id, - params: { customLabel: 'Custom label' }, - makeLabel: () => 'Custom label', - }; - comp.setProps({ - aggs: createAggs([agg]), - }); - - expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES); - }); - }); - - it('should add value axis', () => { - const comp = shallow(); - comp.find(ValueAxesPanel).prop('addValueAxis')(); - - expect(setValue).toHaveBeenCalledWith(VALUE_AXES, [axis, axisRight]); - }); - - describe('removeValueAxis', () => { - beforeEach(() => { - defaultProps.stateParams.valueAxes = [axis, axisRight]; - }); - - it('should remove value axis', () => { - const comp = shallow(); - comp.find(ValueAxesPanel).prop('removeValueAxis')(axis); - - expect(setValue).toHaveBeenCalledWith(VALUE_AXES, [axisRight]); - }); - - it('should update seriesParams "valueAxis" prop', () => { - const updatedSeriesParam = { ...chart, valueAxis: 'ValueAxis-2' }; - const comp = shallow(); - comp.find(ValueAxesPanel).prop('removeValueAxis')(axis); - - expect(setValue).toHaveBeenCalledWith(SERIES_PARAMS, [updatedSeriesParam]); - }); - - it('should reset grid "valueAxis" prop', () => { - const updatedGrid = { valueAxis: undefined }; - defaultProps.stateParams.seriesParams[0].valueAxis = 'ValueAxis-2'; - const comp = shallow(); - comp.find(ValueAxesPanel).prop('removeValueAxis')(axis); - - expect(setValue).toHaveBeenCalledWith('grid', updatedGrid); - }); - }); - - it('should update axis value when when category position chnaged', () => { - const comp = shallow(); - comp.find(CategoryAxisPanel).prop('onPositionChanged')(Positions.LEFT); - - const updatedValues = [{ ...axis, name: 'BottomAxis-1', position: Positions.BOTTOM }]; - expect(setValue).toHaveBeenCalledWith(VALUE_AXES, updatedValues); - }); -}); diff --git a/src/plugins/vis_type_vislib/public/editor/collections.ts b/src/plugins/vis_type_vislib/public/editor/collections.ts new file mode 100644 index 0000000000000..f1caa0754b0b3 --- /dev/null +++ b/src/plugins/vis_type_vislib/public/editor/collections.ts @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +import { colorSchemas } from '../../../charts/public'; +import { getPositions, getScaleTypes } from '../../../vis_type_xy/public'; + +import { Alignment, GaugeType } from '../types'; + +export const getGaugeTypes = () => [ + { + text: i18n.translate('visTypeVislib.gauge.gaugeTypes.arcText', { + defaultMessage: 'Arc', + }), + value: GaugeType.Arc, + }, + { + text: i18n.translate('visTypeVislib.gauge.gaugeTypes.circleText', { + defaultMessage: 'Circle', + }), + value: GaugeType.Circle, + }, +]; + +export const getAlignments = () => [ + { + text: i18n.translate('visTypeVislib.gauge.alignmentAutomaticTitle', { + defaultMessage: 'Automatic', + }), + value: Alignment.Automatic, + }, + { + text: i18n.translate('visTypeVislib.gauge.alignmentHorizontalTitle', { + defaultMessage: 'Horizontal', + }), + value: Alignment.Horizontal, + }, + { + text: i18n.translate('visTypeVislib.gauge.alignmentVerticalTitle', { + defaultMessage: 'Vertical', + }), + value: Alignment.Vertical, + }, +]; + +export const getGaugeCollections = () => ({ + gaugeTypes: getGaugeTypes(), + alignments: getAlignments(), + colorSchemas, +}); + +export const getHeatmapCollections = () => ({ + legendPositions: getPositions(), + scales: getScaleTypes(), + colorSchemas, +}); diff --git a/src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx b/src/plugins/vis_type_vislib/public/editor/components/gauge/index.tsx similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx rename to src/plugins/vis_type_vislib/public/editor/components/gauge/index.tsx diff --git a/src/plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx b/src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx rename to src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx index 0bd5694f71021..e02f62fa6ed6b 100644 --- a/src/plugins/vis_type_vislib/public/components/options/gauge/labels_panel.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx @@ -21,8 +21,7 @@ import React from 'react'; import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; - -import { SwitchOption, TextInputOption } from '../../../../../charts/public'; +import { SwitchOption, TextInputOption } from '../../../../../vis_default_editor/public'; import { GaugeOptionsInternalProps } from '../gauge'; function LabelsPanel({ stateParams, setValue, setGaugeValue }: GaugeOptionsInternalProps) { diff --git a/src/plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx b/src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx similarity index 97% rename from src/plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx rename to src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx index c297fb08e4b68..ec5201af2e7d0 100644 --- a/src/plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx @@ -21,15 +21,13 @@ import React, { useCallback } from 'react'; import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; - import { ColorRanges, - ColorSchemaOptions, - ColorSchemaParams, SetColorRangeValue, SwitchOption, - ColorSchemas, -} from '../../../../../charts/public'; + ColorSchemaOptions, +} from '../../../../../vis_default_editor/public'; +import { ColorSchemaParams, ColorSchemas } from '../../../../../charts/public'; import { GaugeOptionsInternalProps } from '../gauge'; import { Gauge } from '../../../gauge'; diff --git a/src/plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx b/src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx rename to src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx index b299b2e86ca40..9cb807aac5759 100644 --- a/src/plugins/vis_type_vislib/public/components/options/gauge/style_panel.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx @@ -22,7 +22,7 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SelectOption } from '../../../../../charts/public'; +import { SelectOption } from '../../../../../vis_default_editor/public'; import { GaugeOptionsInternalProps } from '../gauge'; import { AggGroupNames } from '../../../../../data/public'; diff --git a/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx b/src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx similarity index 97% rename from src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx rename to src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx index 312cf60fda6b0..a409762b30f9f 100644 --- a/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx @@ -23,19 +23,20 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; +import { ValueAxis } from '../../../../../vis_type_xy/public'; import { + VisOptionsProps, BasicOptions, - ColorRanges, - ColorSchemaOptions, - NumberInputOption, SelectOption, SwitchOption, - SetColorSchemaOptionsValue, + ColorRanges, SetColorRangeValue, -} from '../../../../../charts/public'; + SetColorSchemaOptionsValue, + ColorSchemaOptions, + NumberInputOption, +} from '../../../../../vis_default_editor/public'; + import { HeatmapVisParams } from '../../../heatmap'; -import { ValueAxis } from '../../../types'; import { LabelsPanel } from './labels_panel'; function HeatmapOptions(props: VisOptionsProps) { diff --git a/src/plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx b/src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx similarity index 95% rename from src/plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx rename to src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx index 4998a8fd02521..506e5f74dc972 100644 --- a/src/plugins/vis_type_vislib/public/components/options/heatmap/labels_panel.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx @@ -23,10 +23,10 @@ import { EuiColorPicker, EuiFormRow, EuiPanel, EuiSpacer, EuiTitle } from '@elas import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { ValueAxis } from '../../../types'; +import { VisOptionsProps, SwitchOption } from '../../../../../vis_default_editor/public'; +import { ValueAxis } from '../../../../../vis_type_xy/public'; + import { HeatmapVisParams } from '../../../heatmap'; -import { SwitchOption } from '../../../../../charts/public'; const VERTICAL_ROTATION = 270; diff --git a/src/plugins/vis_type_vislib/public/components/options/index.tsx b/src/plugins/vis_type_vislib/public/editor/components/index.tsx similarity index 71% rename from src/plugins/vis_type_vislib/public/components/options/index.tsx rename to src/plugins/vis_type_vislib/public/editor/components/index.tsx index 18c41bf289b11..ed8c8239a07b6 100644 --- a/src/plugins/vis_type_vislib/public/components/options/index.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/index.tsx @@ -19,18 +19,15 @@ import React, { lazy } from 'react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { ValidationVisOptionsProps } from '../common'; +import { VisOptionsProps } from '../../../../vis_default_editor/public'; + import { GaugeVisParams } from '../../gauge'; import { PieVisParams } from '../../pie'; -import { BasicVislibParams } from '../../types'; import { HeatmapVisParams } from '../../heatmap'; const GaugeOptionsLazy = lazy(() => import('./gauge')); const PieOptionsLazy = lazy(() => import('./pie')); -const PointSeriesOptionsLazy = lazy(() => import('./point_series')); const HeatmapOptionsLazy = lazy(() => import('./heatmap')); -const MetricsAxisOptionsLazy = lazy(() => import('./metrics_axes')); export const GaugeOptions = (props: VisOptionsProps) => ( @@ -38,14 +35,6 @@ export const GaugeOptions = (props: VisOptionsProps) => ( export const PieOptions = (props: VisOptionsProps) => ; -export const PointSeriesOptions = (props: ValidationVisOptionsProps) => ( - -); - export const HeatmapOptions = (props: VisOptionsProps) => ( ); - -export const MetricsAxisOptions = (props: ValidationVisOptionsProps) => ( - -); diff --git a/src/plugins/vis_type_vislib/public/components/options/pie.tsx b/src/plugins/vis_type_vislib/public/editor/components/pie.tsx similarity index 94% rename from src/plugins/vis_type_vislib/public/components/options/pie.tsx rename to src/plugins/vis_type_vislib/public/editor/components/pie.tsx index 30828bfc6a3ea..01516630287ec 100644 --- a/src/plugins/vis_type_vislib/public/components/options/pie.tsx +++ b/src/plugins/vis_type_vislib/public/editor/components/pie.tsx @@ -22,9 +22,9 @@ import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { TruncateLabelsOption } from '../common'; -import { BasicOptions, SwitchOption } from '../../../../charts/public'; +import { BasicOptions, SwitchOption, VisOptionsProps } from '../../../../vis_default_editor/public'; +import { TruncateLabelsOption } from '../../../../vis_type_xy/public'; + import { PieVisParams } from '../../pie'; function PieOptions(props: VisOptionsProps) { diff --git a/src/plugins/vis_type_vislib/public/editor/index.ts b/src/plugins/vis_type_vislib/public/editor/index.ts new file mode 100644 index 0000000000000..2a73b1ad8fa68 --- /dev/null +++ b/src/plugins/vis_type_vislib/public/editor/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './collections'; +export * from './components'; diff --git a/src/plugins/vis_type_vislib/public/gauge.ts b/src/plugins/vis_type_vislib/public/gauge.ts index 7cc8e03c9e4c2..de32ee17a21bf 100644 --- a/src/plugins/vis_type_vislib/public/gauge.ts +++ b/src/plugins/vis_type_vislib/public/gauge.ts @@ -19,24 +19,25 @@ import { i18n } from '@kbn/i18n'; +import { ColorMode, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public'; import { RangeValues, Schemas } from '../../vis_default_editor/public'; import { AggGroupNames } from '../../data/public'; -import { GaugeOptions } from './components/options'; -import { getGaugeCollections, Alignments, GaugeTypes } from './utils/collections'; -import { ColorModes, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public'; -import { toExpressionAst } from './to_ast'; import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; -import { BasicVislibParams } from './types'; + +import { Alignment, GaugeType, BasicVislibParams, VislibChartType } from './types'; +import { getGaugeCollections } from './editor'; +import { toExpressionAst } from './to_ast'; +import { GaugeOptions } from './editor/components'; export interface Gauge extends ColorSchemaParams { backStyle: 'Full'; gaugeStyle: 'Full'; orientation: 'vertical'; type: 'meter'; - alignment: Alignments; + alignment: Alignment; colorsRange: RangeValues[]; extendRange: boolean; - gaugeType: GaugeTypes; + gaugeType: GaugeType; labels: Labels; percentageMode: boolean; outline?: boolean; @@ -67,20 +68,20 @@ export const gaugeVisTypeDefinition: BaseVisTypeOptions = { toExpressionAst, visConfig: { defaults: { - type: 'gauge', + type: VislibChartType.Gauge, addTooltip: true, addLegend: true, isDisplayWarning: false, gauge: { - alignment: Alignments.AUTOMATIC, + alignment: Alignment.Automatic, extendRange: true, percentageMode: false, - gaugeType: GaugeTypes.ARC, + gaugeType: GaugeType.Arc, gaugeStyle: 'Full', backStyle: 'Full', orientation: 'vertical', colorSchema: ColorSchemas.GreenToRed, - gaugeColorMode: ColorModes.LABELS, + gaugeColorMode: ColorMode.Labels, colorsRange: [ { from: 0, to: 50 }, { from: 50, to: 75 }, diff --git a/src/plugins/vis_type_vislib/public/goal.ts b/src/plugins/vis_type_vislib/public/goal.ts index 46878ca82e45a..56361421261fc 100644 --- a/src/plugins/vis_type_vislib/public/goal.ts +++ b/src/plugins/vis_type_vislib/public/goal.ts @@ -19,14 +19,14 @@ import { i18n } from '@kbn/i18n'; -import { GaugeOptions } from './components/options'; -import { getGaugeCollections, GaugeTypes } from './utils/collections'; -import { ColorModes, ColorSchemas } from '../../charts/public'; import { AggGroupNames } from '../../data/public'; import { Schemas } from '../../vis_default_editor/public'; -import { toExpressionAst } from './to_ast'; +import { ColorMode, ColorSchemas } from '../../charts/public'; import { BaseVisTypeOptions } from '../../visualizations/public'; -import { BasicVislibParams } from './types'; + +import { getGaugeCollections, GaugeOptions } from './editor'; +import { toExpressionAst } from './to_ast'; +import { GaugeType, BasicVislibParams } from './types'; export const goalVisTypeDefinition: BaseVisTypeOptions = { name: 'goal', @@ -46,13 +46,13 @@ export const goalVisTypeDefinition: BaseVisTypeOptions = { verticalSplit: false, autoExtend: false, percentageMode: true, - gaugeType: GaugeTypes.ARC, + gaugeType: GaugeType.Arc, gaugeStyle: 'Full', backStyle: 'Full', orientation: 'vertical', useRanges: false, colorSchema: ColorSchemas.GreenToRed, - gaugeColorMode: ColorModes.NONE, + gaugeColorMode: ColorMode.None, colorsRange: [{ from: 0, to: 10000 }], invertColors: false, labels: { diff --git a/src/plugins/vis_type_vislib/public/heatmap.ts b/src/plugins/vis_type_vislib/public/heatmap.ts index c408ac140dd46..4a815fd8b2c73 100644 --- a/src/plugins/vis_type_vislib/public/heatmap.ts +++ b/src/plugins/vis_type_vislib/public/heatmap.ts @@ -18,15 +18,17 @@ */ import { i18n } from '@kbn/i18n'; +import { Position } from '@elastic/charts'; import { RangeValues, Schemas } from '../../vis_default_editor/public'; import { AggGroupNames } from '../../data/public'; -import { AxisTypes, getHeatmapCollections, Positions, ScaleTypes } from './utils/collections'; -import { HeatmapOptions } from './components/options'; -import { TimeMarker } from './vislib/visualizations/time_marker'; -import { BasicVislibParams, CommonVislibParams, ValueAxis } from './types'; import { ColorSchemas, ColorSchemaParams } from '../../charts/public'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; +import { VIS_EVENT_TO_TRIGGER, BaseVisTypeOptions } from '../../visualizations/public'; +import { ValueAxis, ScaleType, AxisType } from '../../vis_type_xy/public'; + +import { HeatmapOptions, getHeatmapCollections } from './editor'; +import { TimeMarker } from './vislib/visualizations/time_marker'; +import { CommonVislibParams, BasicVislibParams, VislibChartType } from './types'; import { toExpressionAst } from './to_ast'; export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams { @@ -48,15 +50,15 @@ export const heatmapVisTypeDefinition: BaseVisTypeOptions = { description: i18n.translate('visTypeVislib.heatmap.heatmapDescription', { defaultMessage: 'Shade data in cells in a matrix.', }), - getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter], toExpressionAst, + getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter], visConfig: { defaults: { - type: 'heatmap', + type: VislibChartType.Heatmap, addTooltip: true, addLegend: true, enableHover: false, - legendPosition: Positions.RIGHT, + legendPosition: Position.Right, times: [], colorsNumber: 4, colorSchema: ColorSchemas.Greens, @@ -68,9 +70,9 @@ export const heatmapVisTypeDefinition: BaseVisTypeOptions = { { show: false, id: 'ValueAxis-1', - type: AxisTypes.VALUE, + type: AxisType.Value, scale: { - type: ScaleTypes.LINEAR, + type: ScaleType.Linear, defaultYExtents: false, }, labels: { diff --git a/src/plugins/vis_type_vislib/public/histogram.ts b/src/plugins/vis_type_vislib/public/histogram.ts index de4855ba9aa2b..7424ef5c4df27 100644 --- a/src/plugins/vis_type_vislib/public/histogram.ts +++ b/src/plugins/vis_type_vislib/public/histogram.ts @@ -17,174 +17,14 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { palettes } from '@elastic/eui/lib/services'; -// @ts-ignore -import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; +import { xyVisTypes } from '../../vis_type_xy/public'; +import { BaseVisTypeOptions } from '../../visualizations/public'; -import { AggGroupNames } from '../../data/public'; -import { Schemas } from '../../vis_default_editor/public'; -import { - Positions, - ChartTypes, - ChartModes, - AxisTypes, - ScaleTypes, - AxisModes, - ThresholdLineStyles, - getConfigCollections, -} from './utils/collections'; -import { getAreaOptionTabs, countLabel } from './utils/common_config'; -import { Rotates } from '../../charts/public'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; -import { BasicVislibParams } from './types'; import { toExpressionAst } from './to_ast'; +import { BasicVislibParams } from './types'; export const histogramVisTypeDefinition: BaseVisTypeOptions = { - name: 'histogram', - title: i18n.translate('visTypeVislib.histogram.histogramTitle', { - defaultMessage: 'Vertical bar', - }), - icon: 'visBarVertical', - description: i18n.translate('visTypeVislib.histogram.histogramDescription', { - defaultMessage: 'Present data in vertical bars on an axis.', - }), - getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush], + ...(xyVisTypes.histogram() as BaseVisTypeOptions), toExpressionAst, - visConfig: { - defaults: { - type: 'histogram', - grid: { - categoryLines: false, - }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: AxisTypes.CATEGORY, - position: Positions.BOTTOM, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - }, - labels: { - show: true, - filter: true, - truncate: 100, - }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: AxisTypes.VALUE, - position: Positions.LEFT, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - mode: AxisModes.NORMAL, - }, - labels: { - show: true, - rotate: Rotates.HORIZONTAL, - filter: false, - truncate: 100, - }, - title: { - text: countLabel, - }, - }, - ], - seriesParams: [ - { - show: true, - type: ChartTypes.HISTOGRAM, - mode: ChartModes.STACKED, - data: { - label: countLabel, - id: '1', - }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - lineWidth: 2, - showCircles: true, - }, - ], - addTooltip: true, - addLegend: true, - legendPosition: Positions.RIGHT, - times: [], - addTimeMarker: false, - labels: { - show: false, - }, - thresholdLine: { - show: false, - value: 10, - width: 1, - style: ThresholdLineStyles.FULL, - color: euiPaletteColorBlind()[9], - }, - }, - }, - editorConfig: { - collections: getConfigCollections(), - optionTabs: getAreaOptionTabs(), - schemas: new Schemas([ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeVislib.histogram.metricTitle', { - defaultMessage: 'Y-axis', - }), - min: 1, - aggFilter: ['!geo_centroid', '!geo_bounds'], - defaults: [{ schema: 'metric', type: 'count' }], - }, - { - group: AggGroupNames.Metrics, - name: 'radius', - title: i18n.translate('visTypeVislib.histogram.radiusTitle', { - defaultMessage: 'Dot size', - }), - min: 0, - max: 1, - aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'], - }, - { - group: AggGroupNames.Buckets, - name: 'segment', - title: i18n.translate('visTypeVislib.histogram.segmentTitle', { - defaultMessage: 'X-axis', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'group', - title: i18n.translate('visTypeVislib.histogram.groupTitle', { - defaultMessage: 'Split series', - }), - min: 0, - max: 3, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'split', - title: i18n.translate('visTypeVislib.histogram.splitTitle', { - defaultMessage: 'Split chart', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - ]), - }, + visualization: undefined, }; diff --git a/src/plugins/vis_type_vislib/public/horizontal_bar.ts b/src/plugins/vis_type_vislib/public/horizontal_bar.ts index 144e63224533b..9e919c66cb365 100644 --- a/src/plugins/vis_type_vislib/public/horizontal_bar.ts +++ b/src/plugins/vis_type_vislib/public/horizontal_bar.ts @@ -17,171 +17,14 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { palettes, euiPaletteColorBlind } from '@elastic/eui/lib/services'; +import { xyVisTypes } from '../../vis_type_xy/public'; +import { BaseVisTypeOptions } from '../../visualizations/public'; -import { AggGroupNames } from '../../data/public'; -import { Schemas } from '../../vis_default_editor/public'; -import { - Positions, - ChartTypes, - ChartModes, - AxisTypes, - ScaleTypes, - AxisModes, - ThresholdLineStyles, - getConfigCollections, -} from './utils/collections'; -import { getAreaOptionTabs, countLabel } from './utils/common_config'; -import { Rotates } from '../../charts/public'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; -import { BasicVislibParams } from './types'; import { toExpressionAst } from './to_ast'; +import { BasicVislibParams } from './types'; export const horizontalBarVisTypeDefinition: BaseVisTypeOptions = { - name: 'horizontal_bar', - title: i18n.translate('visTypeVislib.horizontalBar.horizontalBarTitle', { - defaultMessage: 'Horizontal bar', - }), - icon: 'visBarHorizontal', - description: i18n.translate('visTypeVislib.horizontalBar.horizontalBarDescription', { - defaultMessage: 'Present data in horizontal bars on an axis.', - }), - getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush], + ...(xyVisTypes.horizontalBar() as BaseVisTypeOptions), toExpressionAst, - visConfig: { - defaults: { - type: 'histogram', - grid: { - categoryLines: false, - }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: AxisTypes.CATEGORY, - position: Positions.LEFT, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - }, - labels: { - show: true, - rotate: Rotates.HORIZONTAL, - filter: false, - truncate: 200, - }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: AxisTypes.VALUE, - position: Positions.BOTTOM, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - mode: AxisModes.NORMAL, - }, - labels: { - show: true, - rotate: Rotates.ANGLED, - filter: true, - truncate: 100, - }, - title: { - text: countLabel, - }, - }, - ], - seriesParams: [ - { - show: true, - type: ChartTypes.HISTOGRAM, - mode: ChartModes.NORMAL, - data: { - label: countLabel, - id: '1', - }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - lineWidth: 2, - showCircles: true, - }, - ], - addTooltip: true, - addLegend: true, - legendPosition: Positions.RIGHT, - times: [], - addTimeMarker: false, - labels: {}, - thresholdLine: { - show: false, - value: 10, - width: 1, - style: ThresholdLineStyles.FULL, - color: euiPaletteColorBlind()[9], - }, - }, - }, - editorConfig: { - collections: getConfigCollections(), - optionTabs: getAreaOptionTabs(), - schemas: new Schemas([ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeVislib.horizontalBar.metricTitle', { - defaultMessage: 'Y-axis', - }), - min: 1, - aggFilter: ['!geo_centroid', '!geo_bounds'], - defaults: [{ schema: 'metric', type: 'count' }], - }, - { - group: AggGroupNames.Metrics, - name: 'radius', - title: i18n.translate('visTypeVislib.horizontalBar.radiusTitle', { - defaultMessage: 'Dot size', - }), - min: 0, - max: 1, - aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'], - }, - { - group: AggGroupNames.Buckets, - name: 'segment', - title: i18n.translate('visTypeVislib.horizontalBar.segmentTitle', { - defaultMessage: 'X-axis', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'group', - title: i18n.translate('visTypeVislib.horizontalBar.groupTitle', { - defaultMessage: 'Split series', - }), - min: 0, - max: 3, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'split', - title: i18n.translate('visTypeVislib.horizontalBar.splitTitle', { - defaultMessage: 'Split chart', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - ]), - }, + visualization: undefined, }; diff --git a/src/plugins/vis_type_vislib/public/line.ts b/src/plugins/vis_type_vislib/public/line.ts index ffa40c8c29980..15f20edd359dd 100644 --- a/src/plugins/vis_type_vislib/public/line.ts +++ b/src/plugins/vis_type_vislib/public/line.ts @@ -17,164 +17,14 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { palettes, euiPaletteColorBlind } from '@elastic/eui/lib/services'; +import { xyVisTypes } from '../../vis_type_xy/public'; +import { BaseVisTypeOptions } from '../../visualizations/public'; -import { AggGroupNames } from '../../data/public'; -import { Schemas } from '../../vis_default_editor/public'; -import { - Positions, - ChartTypes, - ChartModes, - AxisTypes, - ScaleTypes, - AxisModes, - ThresholdLineStyles, - InterpolationModes, - getConfigCollections, -} from './utils/collections'; -import { getAreaOptionTabs, countLabel } from './utils/common_config'; -import { Rotates } from '../../charts/public'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; export const lineVisTypeDefinition: BaseVisTypeOptions = { - name: 'line', - title: i18n.translate('visTypeVislib.line.lineTitle', { defaultMessage: 'Line' }), - icon: 'visLine', - description: i18n.translate('visTypeVislib.line.lineDescription', { - defaultMessage: 'Display data as a series of points.', - }), - getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush], + ...(xyVisTypes.line() as BaseVisTypeOptions), toExpressionAst, - visConfig: { - defaults: { - type: 'line', - grid: { - categoryLines: false, - }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: AxisTypes.CATEGORY, - position: Positions.BOTTOM, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - }, - labels: { - show: true, - filter: true, - truncate: 100, - }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: AxisTypes.VALUE, - position: Positions.LEFT, - show: true, - style: {}, - scale: { - type: ScaleTypes.LINEAR, - mode: AxisModes.NORMAL, - }, - labels: { - show: true, - rotate: Rotates.HORIZONTAL, - filter: false, - truncate: 100, - }, - title: { - text: countLabel, - }, - }, - ], - seriesParams: [ - { - show: true, - type: ChartTypes.LINE, - mode: ChartModes.NORMAL, - data: { - label: countLabel, - id: '1', - }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - lineWidth: 2, - interpolate: InterpolationModes.LINEAR, - showCircles: true, - }, - ], - addTooltip: true, - addLegend: true, - legendPosition: Positions.RIGHT, - times: [], - addTimeMarker: false, - labels: {}, - thresholdLine: { - show: false, - value: 10, - width: 1, - style: ThresholdLineStyles.FULL, - color: euiPaletteColorBlind()[9], - }, - }, - }, - editorConfig: { - collections: getConfigCollections(), - optionTabs: getAreaOptionTabs(), - schemas: new Schemas([ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeVislib.line.metricTitle', { defaultMessage: 'Y-axis' }), - min: 1, - aggFilter: ['!geo_centroid', '!geo_bounds'], - defaults: [{ schema: 'metric', type: 'count' }], - }, - { - group: AggGroupNames.Metrics, - name: 'radius', - title: i18n.translate('visTypeVislib.line.radiusTitle', { defaultMessage: 'Dot size' }), - min: 0, - max: 1, - aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits'], - }, - { - group: AggGroupNames.Buckets, - name: 'segment', - title: i18n.translate('visTypeVislib.line.segmentTitle', { defaultMessage: 'X-axis' }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'group', - title: i18n.translate('visTypeVislib.line.groupTitle', { - defaultMessage: 'Split series', - }), - min: 0, - max: 3, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'split', - title: i18n.translate('visTypeVislib.line.splitTitle', { - defaultMessage: 'Split chart', - }), - min: 0, - max: 1, - aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'], - }, - ]), - }, + visualization: undefined, }; diff --git a/src/plugins/vis_type_vislib/public/pie.ts b/src/plugins/vis_type_vislib/public/pie.ts index 41b271054d59f..aa5a3ceaaba98 100644 --- a/src/plugins/vis_type_vislib/public/pie.ts +++ b/src/plugins/vis_type_vislib/public/pie.ts @@ -18,13 +18,15 @@ */ import { i18n } from '@kbn/i18n'; +import { Position } from '@elastic/charts'; import { AggGroupNames } from '../../data/public'; import { Schemas } from '../../vis_default_editor/public'; -import { PieOptions } from './components/options'; -import { getPositions, Positions } from './utils/collections'; +import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; +import { getPositions } from '../../vis_type_xy/public'; + import { CommonVislibParams } from './types'; -import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; +import { PieOptions } from './editor'; import { toExpressionAst } from './to_ast_pie'; export interface PieVisParams extends CommonVislibParams { @@ -52,7 +54,7 @@ export const pieVisTypeDefinition: BaseVisTypeOptions = { type: 'pie', addTooltip: true, addLegend: true, - legendPosition: Positions.RIGHT, + legendPosition: Position.Right, isDonut: true, labels: { show: false, diff --git a/src/plugins/vis_type_vislib/public/pie_fn.ts b/src/plugins/vis_type_vislib/public/pie_fn.ts index c9da9e9bd9fab..8b16d8eb0982f 100644 --- a/src/plugins/vis_type_vislib/public/pie_fn.ts +++ b/src/plugins/vis_type_vislib/public/pie_fn.ts @@ -24,6 +24,7 @@ import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressio // @ts-ignore import { vislibSlicesResponseHandler } from './vislib/response_handler'; import { PieVisParams } from './pie'; +import { VislibChartType } from './types'; import { vislibVisName } from './vis_type_vislib_vis_fn'; export const vislibPieName = 'vislib_pie_vis'; @@ -32,9 +33,9 @@ interface Arguments { visConfig: string; } -interface RenderValue { +export interface PieRenderValue { + visType: Extract; visData: unknown; - visType: string; visConfig: PieVisParams; } @@ -42,7 +43,7 @@ export type VisTypeVislibPieExpressionFunctionDefinition = ExpressionFunctionDef typeof vislibPieName, Datatable, Arguments, - Render + Render >; export const createPieVisFn = (): VisTypeVislibPieExpressionFunctionDefinition => ({ @@ -59,17 +60,21 @@ export const createPieVisFn = (): VisTypeVislibPieExpressionFunctionDefinition = help: 'vislib pie vis config', }, }, - fn(input, args) { + fn(input, args, handlers) { const visConfig = JSON.parse(args.visConfig) as PieVisParams; const visData = vislibSlicesResponseHandler(input, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } + return { type: 'render', as: vislibVisName, value: { visData, visConfig, - visType: 'pie', + visType: VislibChartType.Pie, }, }; }, diff --git a/src/plugins/vis_type_vislib/public/plugin.ts b/src/plugins/vis_type_vislib/public/plugin.ts index f183042fd5201..0f849c1833230 100644 --- a/src/plugins/vis_type_vislib/public/plugin.ts +++ b/src/plugins/vis_type_vislib/public/plugin.ts @@ -19,25 +19,28 @@ import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public'; -import { VisTypeXyPluginSetup } from 'src/plugins/vis_type_xy/public'; import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; -import { BaseVisTypeOptions, VisualizationsSetup } from '../../visualizations/public'; -import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn'; -import { createPieVisFn } from './pie_fn'; -import { visLibVisTypeDefinitions, pieVisTypeDefinition } from './vis_type_vislib_vis_types'; +import { VisualizationsSetup } from '../../visualizations/public'; import { ChartsPluginSetup } from '../../charts/public'; import { DataPublicPluginStart } from '../../data/public'; import { KibanaLegacyStart } from '../../kibana_legacy/public'; +import { LEGACY_CHARTS_LIBRARY } from '../../vis_type_xy/public'; + +import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn'; +import { createPieVisFn } from './pie_fn'; +import { + convertedTypeDefinitions, + pieVisTypeDefinition, + visLibVisTypeDefinitions, +} from './vis_type_vislib_vis_types'; import { setFormatService, setDataActions } from './services'; import { getVislibVisRenderer } from './vis_renderer'; -import { BasicVislibParams } from './types'; /** @internal */ export interface VisTypeVislibPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; charts: ChartsPluginSetup; - visTypeXy?: VisTypeXyPluginSetup; } /** @internal */ @@ -56,23 +59,21 @@ export class VisTypeVislibPlugin public async setup( core: VisTypeVislibCoreSetup, - { expressions, visualizations, charts, visTypeXy }: VisTypeVislibPluginSetupDependencies + { expressions, visualizations, charts }: VisTypeVislibPluginSetupDependencies ) { - // if visTypeXy plugin is disabled it's config will be undefined - if (!visTypeXy) { - const convertedTypes: Array> = []; - const convertedFns: any[] = []; - - // Register legacy vislib types that have been converted - convertedFns.forEach(expressions.registerFunction); - convertedTypes.forEach(visualizations.createBaseVisualization); + if (!core.uiSettings.get(LEGACY_CHARTS_LIBRARY, false)) { + // Register only non-replaced vis types + convertedTypeDefinitions.forEach(visualizations.createBaseVisualization); + visualizations.createBaseVisualization(pieVisTypeDefinition); + expressions.registerRenderer(getVislibVisRenderer(core, charts)); + [createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction); + } else { + // Register all vis types + visLibVisTypeDefinitions.forEach(visualizations.createBaseVisualization); + visualizations.createBaseVisualization(pieVisTypeDefinition); expressions.registerRenderer(getVislibVisRenderer(core, charts)); + [createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction); } - // Register non-converted types - visLibVisTypeDefinitions.forEach(visualizations.createBaseVisualization); - visualizations.createBaseVisualization(pieVisTypeDefinition); - expressions.registerRenderer(getVislibVisRenderer(core, charts)); - [createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction); } public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { diff --git a/src/plugins/vis_type_vislib/public/to_ast.ts b/src/plugins/vis_type_vislib/public/to_ast.ts index 3a05410ff006b..30ed2e4ca1bb4 100644 --- a/src/plugins/vis_type_vislib/public/to_ast.ts +++ b/src/plugins/vis_type_vislib/public/to_ast.ts @@ -21,14 +21,11 @@ import moment from 'moment'; import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import type { Dimensions, DateHistogramParams, HistogramParams } from '../../vis_type_xy/public'; +import { BUCKET_TYPES } from '../../data/public'; import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_type_vislib_vis_fn'; -import { BasicVislibParams } from './types'; -import { - DateHistogramParams, - Dimensions, - HistogramParams, -} from './vislib/helpers/point_series/point_series'; +import { BasicVislibParams, VislibChartType } from './types'; import { getEsaggsFn } from './to_ast_esaggs'; export const toExpressionAst: VisToExpressionAst = async (vis, params) => { @@ -47,7 +44,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis if (dimensions.x) { const xAgg = responseAggs[dimensions.x.accessor] as any; - if (xAgg.type.name === 'date_histogram') { + if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { (dimensions.x.params as DateHistogramParams).date = true; const { esUnit, esValue } = xAgg.buckets.getInterval(); (dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit; @@ -57,7 +54,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis .asMilliseconds(); (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat(); (dimensions.x.params as DateHistogramParams).bounds = xAgg.buckets.getBounds(); - } else if (xAgg.type.name === 'histogram') { + } else if (xAgg.type.name === BUCKET_TYPES.HISTOGRAM) { const intervalParam = xAgg.type.paramByName('interval'); const output = { params: {} as any }; await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { @@ -88,15 +85,15 @@ export const toExpressionAst: VisToExpressionAst = async (vis visConfig.dimensions = dimensions; - const visTypeXy = buildExpressionFunction( + const visTypeVislib = buildExpressionFunction( vislibVisName, { - type: vis.type.name, + type: vis.type.name as Exclude, visConfig: JSON.stringify(visConfig), } ); - const ast = buildExpression([getEsaggsFn(vis), visTypeXy]); + const ast = buildExpression([getEsaggsFn(vis), visTypeVislib]); return ast.toAst(); }; diff --git a/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts b/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts index 2835e5cc1c255..d23f1ab3626d3 100644 --- a/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts +++ b/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts @@ -29,6 +29,8 @@ import { BasicVislibParams } from './types'; /** * Get esaggs expressions function + * TODO: replace this with vis.data.aggs!.toExpressionAst(); + * https://github.com/elastic/kibana/issues/61768 * @param vis */ export function getEsaggsFn(vis: Vis | Vis) { diff --git a/src/plugins/vis_type_vislib/public/types.ts b/src/plugins/vis_type_vislib/public/types.ts index c0311edf76154..4f6c427669324 100644 --- a/src/plugins/vis_type_vislib/public/types.ts +++ b/src/plugins/vis_type_vislib/public/types.ts @@ -17,87 +17,71 @@ * under the License. */ -import { TimeMarker } from './vislib/visualizations/time_marker'; +import { $Values } from '@kbn/utility-types'; +import { Position } from '@elastic/charts'; + +import { Labels } from '../../charts/public'; import { - Positions, - ChartModes, - ChartTypes, - AxisModes, - AxisTypes, - InterpolationModes, - ScaleTypes, - ThresholdLineStyles, -} from './utils/collections'; -import { Labels, Style } from '../../charts/public'; -import { Dimensions } from './vislib/helpers/point_series/point_series'; + CategoryAxis, + Dimensions, + Grid, + SeriesParam, + ThresholdLine, + ValueAxis, +} from '../../vis_type_xy/public'; +import { TimeMarker } from './vislib/visualizations/time_marker'; + +/** + * Gauge title alignment + */ +export const Alignment = Object.freeze({ + Automatic: 'automatic' as const, + Horizontal: 'horizontal' as const, + Vertical: 'vertical' as const, +}); +export type Alignment = $Values; + +export const GaugeType = Object.freeze({ + Arc: 'Arc' as const, + Circle: 'Circle' as const, +}); +export type GaugeType = $Values; + +export const VislibChartType = Object.freeze({ + Histogram: 'histogram' as const, + HorizontalBar: 'horizontal_bar' as const, + Line: 'line' as const, + Pie: 'pie' as const, + Area: 'area' as const, + PointSeries: 'point_series' as const, + Heatmap: 'heatmap' as const, + Gauge: 'gauge' as const, + Goal: 'goal' as const, + Metric: 'metric' as const, +}); +export type VislibChartType = $Values; export interface CommonVislibParams { addTooltip: boolean; addLegend: boolean; - legendPosition: Positions; + legendPosition: Position; dimensions: Dimensions; } -export interface Scale { - boundsMargin?: number | ''; - defaultYExtents?: boolean; - max?: number | null; - min?: number | null; - mode?: AxisModes; - setYExtents?: boolean; - type: ScaleTypes; -} - -interface ThresholdLine { - show: boolean; - value: number | null; - width: number | null; - style: ThresholdLineStyles; - color: string; -} - -export interface Axis { - id: string; - labels: Labels; - position: Positions; - scale: Scale; - show: boolean; - style: Style; - title: { text: string }; - type: AxisTypes; -} - -export interface ValueAxis extends Axis { - name: string; -} - -export interface SeriesParam { - data: { label: string; id: string }; - drawLinesBetweenPoints: boolean; - interpolate: InterpolationModes; - lineWidth?: number; - mode: ChartModes; - show: boolean; - showCircles: boolean; - type: ChartTypes; - valueAxis: string; -} - export interface BasicVislibParams extends CommonVislibParams { + type: VislibChartType; + addLegend: boolean; addTimeMarker: boolean; - categoryAxes: Axis[]; + categoryAxes: CategoryAxis[]; orderBucketsBySum?: boolean; labels: Labels; thresholdLine: ThresholdLine; valueAxes: ValueAxis[]; + grid: Grid; gauge?: { percentageMode: boolean; }; - grid: { - categoryLines: boolean; - valueAxis?: string; - }; seriesParams: SeriesParam[]; times: TimeMarker[]; - type: string; + radiusRatio: number; } diff --git a/src/plugins/vis_type_vislib/public/utils/collections.ts b/src/plugins/vis_type_vislib/public/utils/collections.ts deleted file mode 100644 index 44df4864bfd68..0000000000000 --- a/src/plugins/vis_type_vislib/public/utils/collections.ts +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { $Values } from '@kbn/utility-types'; - -import { colorSchemas, Rotates } from '../../../charts/public'; - -export const Positions = Object.freeze({ - RIGHT: 'right' as 'right', - LEFT: 'left' as 'left', - TOP: 'top' as 'top', - BOTTOM: 'bottom' as 'bottom', -}); -export type Positions = $Values; - -const getPositions = () => [ - { - text: i18n.translate('visTypeVislib.legendPositions.topText', { - defaultMessage: 'Top', - }), - value: Positions.TOP, - }, - { - text: i18n.translate('visTypeVislib.legendPositions.leftText', { - defaultMessage: 'Left', - }), - value: Positions.LEFT, - }, - { - text: i18n.translate('visTypeVislib.legendPositions.rightText', { - defaultMessage: 'Right', - }), - value: Positions.RIGHT, - }, - { - text: i18n.translate('visTypeVislib.legendPositions.bottomText', { - defaultMessage: 'Bottom', - }), - value: Positions.BOTTOM, - }, -]; - -export const ChartTypes = Object.freeze({ - LINE: 'line' as 'line', - AREA: 'area' as 'area', - HISTOGRAM: 'histogram' as 'histogram', -}); -export type ChartTypes = $Values; - -const getChartTypes = () => [ - { - text: i18n.translate('visTypeVislib.chartTypes.lineText', { - defaultMessage: 'Line', - }), - value: ChartTypes.LINE, - }, - { - text: i18n.translate('visTypeVislib.chartTypes.areaText', { - defaultMessage: 'Area', - }), - value: ChartTypes.AREA, - }, - { - text: i18n.translate('visTypeVislib.chartTypes.barText', { - defaultMessage: 'Bar', - }), - value: ChartTypes.HISTOGRAM, - }, -]; - -export const ChartModes = Object.freeze({ - NORMAL: 'normal' as 'normal', - STACKED: 'stacked' as 'stacked', -}); -export type ChartModes = $Values; - -const getChartModes = () => [ - { - text: i18n.translate('visTypeVislib.chartModes.normalText', { - defaultMessage: 'Normal', - }), - value: ChartModes.NORMAL, - }, - { - text: i18n.translate('visTypeVislib.chartModes.stackedText', { - defaultMessage: 'Stacked', - }), - value: ChartModes.STACKED, - }, -]; - -export const InterpolationModes = Object.freeze({ - LINEAR: 'linear' as 'linear', - CARDINAL: 'cardinal' as 'cardinal', - STEP_AFTER: 'step-after' as 'step-after', -}); -export type InterpolationModes = $Values; - -const getInterpolationModes = () => [ - { - text: i18n.translate('visTypeVislib.interpolationModes.straightText', { - defaultMessage: 'Straight', - }), - value: InterpolationModes.LINEAR, - }, - { - text: i18n.translate('visTypeVislib.interpolationModes.smoothedText', { - defaultMessage: 'Smoothed', - }), - value: InterpolationModes.CARDINAL, - }, - { - text: i18n.translate('visTypeVislib.interpolationModes.steppedText', { - defaultMessage: 'Stepped', - }), - value: InterpolationModes.STEP_AFTER, - }, -]; - -export const AxisTypes = Object.freeze({ - CATEGORY: 'category' as 'category', - VALUE: 'value' as 'value', -}); -export type AxisTypes = $Values; - -export const ScaleTypes = Object.freeze({ - LINEAR: 'linear' as 'linear', - LOG: 'log' as 'log', - SQUARE_ROOT: 'square root' as 'square root', -}); -export type ScaleTypes = $Values; - -const getScaleTypes = () => [ - { - text: i18n.translate('visTypeVislib.scaleTypes.linearText', { - defaultMessage: 'Linear', - }), - value: ScaleTypes.LINEAR, - }, - { - text: i18n.translate('visTypeVislib.scaleTypes.logText', { - defaultMessage: 'Log', - }), - value: ScaleTypes.LOG, - }, - { - text: i18n.translate('visTypeVislib.scaleTypes.squareRootText', { - defaultMessage: 'Square root', - }), - value: ScaleTypes.SQUARE_ROOT, - }, -]; - -export const AxisModes = Object.freeze({ - NORMAL: 'normal' as 'normal', - PERCENTAGE: 'percentage' as 'percentage', - WIGGLE: 'wiggle' as 'wiggle', - SILHOUETTE: 'silhouette' as 'silhouette', -}); -export type AxisModes = $Values; - -const getAxisModes = () => [ - { - text: i18n.translate('visTypeVislib.axisModes.normalText', { - defaultMessage: 'Normal', - }), - value: AxisModes.NORMAL, - }, - { - text: i18n.translate('visTypeVislib.axisModes.percentageText', { - defaultMessage: 'Percentage', - }), - value: AxisModes.PERCENTAGE, - }, - { - text: i18n.translate('visTypeVislib.axisModes.wiggleText', { - defaultMessage: 'Wiggle', - }), - value: AxisModes.WIGGLE, - }, - { - text: i18n.translate('visTypeVislib.axisModes.silhouetteText', { - defaultMessage: 'Silhouette', - }), - value: AxisModes.SILHOUETTE, - }, -]; - -export const ThresholdLineStyles = Object.freeze({ - FULL: 'full' as 'full', - DASHED: 'dashed' as 'dashed', - DOT_DASHED: 'dot-dashed' as 'dot-dashed', -}); -export type ThresholdLineStyles = $Values; - -const getThresholdLineStyles = () => [ - { - value: ThresholdLineStyles.FULL, - text: i18n.translate('visTypeVislib.thresholdLine.style.fullText', { - defaultMessage: 'Full', - }), - }, - { - value: ThresholdLineStyles.DASHED, - text: i18n.translate('visTypeVislib.thresholdLine.style.dashedText', { - defaultMessage: 'Dashed', - }), - }, - { - value: ThresholdLineStyles.DOT_DASHED, - text: i18n.translate('visTypeVislib.thresholdLine.style.dotdashedText', { - defaultMessage: 'Dot-dashed', - }), - }, -]; - -const getRotateOptions = () => [ - { - text: i18n.translate('visTypeVislib.categoryAxis.rotate.horizontalText', { - defaultMessage: 'Horizontal', - }), - value: Rotates.HORIZONTAL, - }, - { - text: i18n.translate('visTypeVislib.categoryAxis.rotate.verticalText', { - defaultMessage: 'Vertical', - }), - value: Rotates.VERTICAL, - }, - { - text: i18n.translate('visTypeVislib.categoryAxis.rotate.angledText', { - defaultMessage: 'Angled', - }), - value: Rotates.ANGLED, - }, -]; - -export const GaugeTypes = Object.freeze({ - ARC: 'Arc' as 'Arc', - CIRCLE: 'Circle' as 'Circle', -}); -export type GaugeTypes = $Values; - -const getGaugeTypes = () => [ - { - text: i18n.translate('visTypeVislib.gauge.gaugeTypes.arcText', { - defaultMessage: 'Arc', - }), - value: GaugeTypes.ARC, - }, - { - text: i18n.translate('visTypeVislib.gauge.gaugeTypes.circleText', { - defaultMessage: 'Circle', - }), - value: GaugeTypes.CIRCLE, - }, -]; - -export const Alignments = Object.freeze({ - AUTOMATIC: 'automatic' as 'automatic', - HORIZONTAL: 'horizontal' as 'horizontal', - VERTICAL: 'vertical' as 'vertical', -}); -export type Alignments = $Values; - -const getAlignments = () => [ - { - text: i18n.translate('visTypeVislib.gauge.alignmentAutomaticTitle', { - defaultMessage: 'Automatic', - }), - value: Alignments.AUTOMATIC, - }, - { - text: i18n.translate('visTypeVislib.gauge.alignmentHorizontalTitle', { - defaultMessage: 'Horizontal', - }), - value: Alignments.HORIZONTAL, - }, - { - text: i18n.translate('visTypeVislib.gauge.alignmentVerticalTitle', { - defaultMessage: 'Vertical', - }), - value: Alignments.VERTICAL, - }, -]; - -const getConfigCollections = () => ({ - legendPositions: getPositions(), - positions: getPositions(), - chartTypes: getChartTypes(), - axisModes: getAxisModes(), - scaleTypes: getScaleTypes(), - chartModes: getChartModes(), - interpolationModes: getInterpolationModes(), - thresholdLineStyles: getThresholdLineStyles(), -}); - -const getGaugeCollections = () => ({ - gaugeTypes: getGaugeTypes(), - alignments: getAlignments(), - colorSchemas, -}); - -const getHeatmapCollections = () => ({ - legendPositions: getPositions(), - scales: getScaleTypes(), - colorSchemas, -}); - -export { - getConfigCollections, - getGaugeCollections, - getHeatmapCollections, - getPositions, - getRotateOptions, - getScaleTypes, - getInterpolationModes, - getChartTypes, - getChartModes, - getAxisModes, -}; diff --git a/src/plugins/vis_type_vislib/public/vis_controller.tsx b/src/plugins/vis_type_vislib/public/vis_controller.tsx index 1804d0d52ae7a..2a32d19874c22 100644 --- a/src/plugins/vis_type_vislib/public/vis_controller.tsx +++ b/src/plugins/vis_type_vislib/public/vis_controller.tsx @@ -22,7 +22,7 @@ import React, { RefObject } from 'react'; import { mountReactNode } from '../../../core/public/utils'; import { ChartsPluginSetup } from '../../charts/public'; -import { PersistedState } from '../../visualizations/public'; +import type { PersistedState } from '../../visualizations/public'; import { IInterpreterRenderHandlers } from '../../expressions/public'; import { VisTypeVislibCoreSetup } from './plugin'; @@ -115,7 +115,7 @@ export const createVislibVisController = ( }) .addClass((legendClassName as any)[visParams.legendPosition]); - this.mountLegend(esResponse, visParams, fireEvent, uiState); + this.mountLegend(esResponse, visParams, fireEvent, uiState as PersistedState); } this.vislibVis.render(esResponse, uiState); @@ -128,7 +128,7 @@ export const createVislibVisController = ( CUSTOM_LEGEND_VIS_TYPES.includes(this.vislibVis.visConfigArgs.type) ) { this.unmountLegend?.(); - this.mountLegend(esResponse, visParams, fireEvent, uiState); + this.mountLegend(esResponse, visParams, fireEvent, uiState as PersistedState); this.vislibVis.render(esResponse, uiState); } } diff --git a/src/plugins/vis_type_vislib/public/vis_renderer.tsx b/src/plugins/vis_type_vislib/public/vis_renderer.tsx index 9c697f481e63e..205c22092ac61 100644 --- a/src/plugins/vis_type_vislib/public/vis_renderer.tsx +++ b/src/plugins/vis_type_vislib/public/vis_renderer.tsx @@ -26,9 +26,13 @@ import { ChartsPluginSetup } from '../../charts/public'; import { VisTypeVislibCoreSetup } from './plugin'; import { VislibRenderValue, vislibVisName } from './vis_type_vislib_vis_fn'; +import { VislibChartType } from './types'; +import { PieRenderValue } from './pie_fn'; -function shouldShowNoResultsMessage(visData: any, visType: string): boolean { - if (['goal', 'gauge'].includes(visType)) { +const VislibWrapper = lazy(() => import('./vis_wrapper')); + +function shouldShowNoResultsMessage(visData: any, visType: VislibChartType): boolean { + if (['goal', 'gauge'].includes(visType as string)) { return false; } @@ -38,13 +42,12 @@ function shouldShowNoResultsMessage(visData: any, visType: string): boolean { return Boolean(isZeroHits); } -const VislibWrapper = lazy(() => import('./vis_wrapper')); - export const getVislibVisRenderer: ( core: VisTypeVislibCoreSetup, charts: ChartsPluginSetup -) => ExpressionRenderDefinition = (core, charts) => ({ +) => ExpressionRenderDefinition = (core, charts) => ({ name: vislibVisName, + displayName: 'Vislib visualization', reuseDomNode: true, render: async (domNode, config, handlers) => { const showNoResult = shouldShowNoResultsMessage(config.visData, config.visType); diff --git a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts index c5fa8f36f43e3..d627b8587882a 100644 --- a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts +++ b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts @@ -23,18 +23,18 @@ import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressio // @ts-ignore import { vislibSeriesResponseHandler } from './vislib/response_handler'; -import { BasicVislibParams } from './types'; +import { BasicVislibParams, VislibChartType } from './types'; export const vislibVisName = 'vislib_vis'; interface Arguments { - type: string; + type: Exclude; visConfig: string; } export interface VislibRenderValue { - visData: any; - visType: string; + visType: Exclude; + visData: unknown; visConfig: BasicVislibParams; } @@ -64,11 +64,15 @@ export const createVisTypeVislibVisFn = (): VisTypeVislibExpressionFunctionDefin help: 'vislib vis config', }, }, - fn(context, args) { - const visType = args.type; + fn(context, args, handlers) { + const visType = args.type as Exclude; const visConfig = JSON.parse(args.visConfig) as BasicVislibParams; const visData = vislibSeriesResponseHandler(context, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } + return { type: 'render', as: vislibVisName, diff --git a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts index 1b43a213c618d..28415e3e2fa8c 100644 --- a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts +++ b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts @@ -36,3 +36,9 @@ export const visLibVisTypeDefinitions = [ gaugeVisTypeDefinition, goalVisTypeDefinition, ]; + +export const convertedTypeDefinitions = [ + heatmapVisTypeDefinition, + gaugeVisTypeDefinition, + goalVisTypeDefinition, +]; diff --git a/src/plugins/vis_type_vislib/public/vis_wrapper.tsx b/src/plugins/vis_type_vislib/public/vis_wrapper.tsx index 980ba1c175885..e2e8a98a9a8b6 100644 --- a/src/plugins/vis_type_vislib/public/vis_wrapper.tsx +++ b/src/plugins/vis_type_vislib/public/vis_wrapper.tsx @@ -22,15 +22,17 @@ import { EuiResizeObserver } from '@elastic/eui'; import { debounce } from 'lodash'; import { IInterpreterRenderHandlers } from '../../expressions/public'; +import type { PersistedState } from '../../visualizations/public'; import { ChartsPluginSetup } from '../../charts/public'; import { VislibRenderValue } from './vis_type_vislib_vis_fn'; import { createVislibVisController, VislibVisController } from './vis_controller'; import { VisTypeVislibCoreSetup } from './plugin'; +import { PieRenderValue } from './pie_fn'; import './index.scss'; -type VislibWrapperProps = VislibRenderValue & { +type VislibWrapperProps = (VislibRenderValue | PieRenderValue) & { core: VisTypeVislibCoreSetup; charts: ChartsPluginSetup; handlers: IInterpreterRenderHandlers; @@ -59,16 +61,18 @@ const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWra visController.current?.destroy(); visController.current = null; }; - }, [core, charts, handlers]); + }, [core, charts]); useEffect(updateChart, [updateChart]); useEffect(() => { if (handlers.uiState) { - handlers.uiState.on('change', updateChart); + const uiState = handlers.uiState as PersistedState; + + uiState.on('change', updateChart); return () => { - handlers.uiState?.off('change', updateChart); + uiState?.off('change', updateChart); }; } }, [handlers.uiState, updateChart]); diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss b/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss index a06f0cb00787b..cb63811800c2d 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss @@ -3,8 +3,6 @@ // NOTE: Some of the styles attempt to align with the TSVB legend $visLegendWidth: 150px; -$visColorPickerWidth: $euiSizeM * 10; -$visLegendLineHeight: $euiSize; .visLegend__toggle { border-radius: $euiBorderRadius; @@ -81,20 +79,3 @@ $visLegendLineHeight: $euiSize; visibility: hidden; } } - -.visLegend__valueColorPicker { - width: ($euiSizeL * 8); // 8 columns -} - -.visLegend__valueColorPickerDot { - cursor: pointer; - - &:hover { - transform: scale(1.4); - } - - &-isSelected { - border: $euiSizeXS solid; - border-radius: 100%; - } -} diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index 7acc97404c11c..5b1a2b3975367 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -243,7 +243,7 @@ describe('VisLegend Component', () => { const first = getLegendItems(wrapper).first(); first.simulate('click'); - expect(wrapper.exists('.visLegend__valueDetails')).toBe(true); + expect(wrapper.exists('.visColorPicker')).toBe(true); }); }); @@ -256,8 +256,8 @@ describe('VisLegend Component', () => { const first = getLegendItems(wrapper).first(); first.simulate('click'); - const popover = wrapper.find('.visLegend__valueDetails').first(); - const firstColor = popover.find('.visLegend__valueColorPickerDot').first(); + const popover = wrapper.find('.visColorPicker').first(); + const firstColor = popover.find('.visColorPicker__valueDot').first(); firstColor.simulate('click'); const colors = mockState.get('vis.colors'); diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index cec97f0cadf11..5065642d88c6b 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -78,18 +78,20 @@ export class VisLegend extends PureComponent { }); }; - setColor = (label: string, color: string) => (event: BaseSyntheticEvent) => { + setColor = (label: string | number, color: string | null, event: BaseSyntheticEvent) => { if ((event as KeyboardEvent).key && (event as KeyboardEvent).key !== keys.ENTER) { return; } - const colors = this.props.uiState?.get('vis.colors') || {}; - if (colors[label] === color) delete colors[label]; - else colors[label] = color; - this.props.uiState?.setSilent('vis.colors', null); - this.props.uiState?.set('vis.colors', colors); - this.props.uiState?.emit('colorChanged'); - this.refresh(); + this.setState({ selectedLabel: null }, () => { + const colors = this.props.uiState?.get('vis.colors') || {}; + if (colors[label] === color || !color) delete colors[label]; + else colors[label] = color; + this.props.uiState?.setSilent('vis.colors', null); + this.props.uiState?.set('vis.colors', colors); + this.props.uiState?.emit('colorChanged'); + this.refresh(); + }); }; filter = ({ values: data }: LegendItem, negate: boolean) => { diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx index 39e6fb2d2aff4..6c7e343a22d8f 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx @@ -18,10 +18,8 @@ */ import React, { memo, useState, BaseSyntheticEvent, KeyboardEvent } from 'react'; -import classNames from 'classnames'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPopover, keys, @@ -33,7 +31,8 @@ import { EuiButtonGroupOptionProps, } from '@elastic/eui'; -import { legendColors, LegendItem } from './models'; +import { LegendItem } from './models'; +import { ColorPicker } from '../../../../../charts/public'; interface Props { item: LegendItem; @@ -45,7 +44,7 @@ interface Props { onSelect: (label: string | null) => (event?: BaseSyntheticEvent) => void; onHighlight: (event: BaseSyntheticEvent) => void; onUnhighlight: (event: BaseSyntheticEvent) => void; - setColor: (label: string, color: string) => (event: BaseSyntheticEvent) => void; + setColor: (label: string, color: string | null, event: BaseSyntheticEvent) => void; getColor: (label: string) => string; } @@ -159,40 +158,14 @@ const VisLegendItemComponent = ({ closePopover={onSelect(null)} panelPaddingSize="s" > -
- {canFilter && renderFilterBar()} + {canFilter && renderFilterBar()} -
- - - - {legendColors.map((color) => ( - - ))} -
-
+ setColor(item.label, c, e)} + /> ); diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts index ae6b365efc0cd..1b51fb8a53d11 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts @@ -17,9 +17,10 @@ * under the License. */ +import type { Dimension } from '../../../../../vis_type_xy/public'; + import { addToSiri, Serie } from './_add_to_siri'; import { Point } from './_get_point'; -import { Dimension } from './point_series'; describe('addToSiri', function () { it('creates a new series the first time it sees an id', function () { diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts index 5e5185d6c31ab..2e04e916e85f2 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts @@ -17,8 +17,10 @@ * under the License. */ +import { getAggId } from '../../../../../vis_type_xy/public'; +import type { Dimension } from '../../../../../vis_type_xy/public'; + import { Point } from './_get_point'; -import { Dimension } from './point_series'; export interface Serie { id: string; @@ -48,7 +50,7 @@ export function addToSiri( } series.set(id, { - id: id.split('-').pop() as string, + id: getAggId(id), rawId: id, label: yLabel == null ? id : yLabel, count: 0, diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts index fb14b04357f8f..5efde63427573 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts @@ -17,8 +17,10 @@ * under the License. */ +import type { Dimension, Dimensions } from '../../../../../vis_type_xy/public'; + import { getAspects } from './_get_aspects'; -import { Dimension, Dimensions, Aspect } from './point_series'; +import { Aspect } from './point_series'; import { Table, Row } from '../../types'; describe('getAspects', function () { diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts index 87819aa9b2a5c..e4094a4549841 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts @@ -17,8 +17,10 @@ * under the License. */ +import type { Dimensions } from '../../../../../vis_type_xy/public'; + import { makeFakeXAspect } from './_fake_x_aspect'; -import { Dimensions, Aspects } from './point_series'; +import { Aspects } from './point_series'; import { Table } from '../../types'; /** diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts index be44975bd4eb0..03d41096a8c6f 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts @@ -18,6 +18,7 @@ */ import { IFieldFormatsRegistry } from '../../../../../data/common'; + import { getPoint } from './_get_point'; import { setFormatService } from '../../../services'; import { Aspect } from './point_series'; @@ -94,7 +95,12 @@ describe('getPoint', function () { it('should call deserialize', function () { const seriesAspect = [ - { accessor: '1', format: { id: 'number', params: { pattern: '$' } } } as Aspect, + { + title: 'series', + accessor: '1', + format: { id: 'number', params: { pattern: '$' } }, + params: {}, + } as Aspect, ]; getPoint(table, xAspect, seriesAspect, row, 0, yAspect); diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts index 5eb1e65965318..fb42416abe249 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts @@ -41,7 +41,7 @@ export interface Point { table: Table; column: number; row: number; - value: number; + value: string; title: string; }; parent: Aspect | null; @@ -94,7 +94,7 @@ export function getPoint( table: table.$parent.table, column: table.$parent.column, row: table.$parent.row, - value: table.$parent.key, + value: table.$parent.formattedKey, title: table.$parent.name, }, parent: series ? series[0] : null, diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts index 3f0560c2c9f28..aa24530b025dc 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts @@ -18,16 +18,12 @@ */ import moment from 'moment'; + +import type { DateHistogramParams, HistogramParams } from '../../../../../vis_type_xy/public'; + import { initXAxis } from './_init_x_axis'; import { makeFakeXAspect } from './_fake_x_aspect'; -import { - Aspects, - Chart, - DateHistogramOrdered, - DateHistogramParams, - HistogramOrdered, - HistogramParams, -} from './point_series'; +import { Aspects, Chart, DateHistogramOrdered, HistogramOrdered } from './point_series'; import { Table, Column } from '../../types'; describe('initXAxis', function () { @@ -110,7 +106,7 @@ describe('initXAxis', function () { it('reads the date interval param from the x agg', function () { const dateHistogramParams = chart.aspects.x[0].params as DateHistogramParams; - dateHistogramParams.interval = 'P1D'; + dateHistogramParams.interval = moment.duration(1, 'd').asMilliseconds(); dateHistogramParams.intervalESValue = 1; dateHistogramParams.intervalESUnit = 'd'; dateHistogramParams.date = true; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts index b2e4d6e4b40c9..7dd1dd259f785 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts @@ -19,8 +19,11 @@ import moment from 'moment'; import _ from 'lodash'; + +import type { DateHistogramParams } from '../../../../../vis_type_xy/public/types'; + import { orderedDateAxis } from './_ordered_date_axis'; -import { DateHistogramParams, OrderedChart } from './point_series'; +import { OrderedChart } from './point_series'; describe('orderedDateAxis', function () { const baseArgs = { diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts index 2a5ab197c9ab7..7c343af7840ee 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts @@ -18,7 +18,10 @@ */ import _ from 'lodash'; -import { buildPointSeriesData, Dimensions } from './point_series'; + +import type { Dimensions } from '../../../../../vis_type_xy/public'; + +import { buildPointSeriesData } from './point_series'; import { Table, Column } from '../../types'; import { setFormatService } from '../../../services'; import { Serie } from './_add_to_siri'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts index f40d01e6a8123..2bc669e0b77a3 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts @@ -18,6 +18,14 @@ */ import { Duration } from 'moment'; + +import type { + Dimension, + Dimensions, + DateHistogramParams, + HistogramParams, +} from '../../../../../vis_type_xy/public'; + import { getSeries } from './_get_series'; import { getAspects } from './_get_aspects'; import { initYAxis } from './_init_y_axis'; @@ -26,41 +34,6 @@ import { orderedDateAxis } from './_ordered_date_axis'; import { Serie } from './_add_to_siri'; import { Column, Table } from '../../types'; -export interface DateHistogramParams { - date: boolean; - interval: number | string; - intervalESValue: number; - intervalESUnit: string; - format: string; - bounds?: { - min: string | number; - max: string | number; - }; -} -export interface HistogramParams { - interval: number; -} -export interface FakeParams { - defaultValue: string; -} -export interface Dimension { - accessor: number; - format: { - id?: string; - params?: { pattern?: string; [key: string]: any }; - }; - params: DateHistogramParams | HistogramParams | FakeParams | {}; -} - -export interface Dimensions { - x: Dimension | null; - y: Dimension[]; - z?: Dimension[]; - series?: Dimension | Dimension[]; - width?: Dimension[]; - splitRow?: Dimension[]; - splitColumn?: Dimension[]; -} export interface Aspect { accessor: Column['id']; column?: Dimension['accessor']; diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/handler.js b/src/plugins/vis_type_vislib/public/vislib/lib/handler.js index 938ea3adcb9b5..e1908a8483feb 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/handler.js +++ b/src/plugins/vis_type_vislib/public/vislib/lib/handler.js @@ -21,15 +21,16 @@ import d3 from 'd3'; import _ from 'lodash'; import MarkdownIt from 'markdown-it'; +import { dispatchRenderComplete } from '../../../../kibana_utils/public'; + +import { visTypes as chartTypes } from '../visualizations/vis_types'; import { NoResults } from '../errors'; import { Layout } from './layout/layout'; import { ChartTitle } from './chart_title'; import { Alerts } from './alerts'; import { Axis } from './axis/axis'; import { ChartGrid as Grid } from './chart_grid'; -import { visTypes as chartTypes } from '../visualizations/vis_types'; import { Binder } from './binder'; -import { dispatchRenderComplete } from '../../../../kibana_utils/public'; const markdownIt = new MarkdownIt({ html: false, diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json index d52cb18727c05..50d6eab03e3f7 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json +++ b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json @@ -31,7 +31,7 @@ }, "params": { "date": true, - "interval": "P1D", + "interval": 86400000, "format": "YYYY-MM-DD", "bounds": { "min": "2019-05-10T04:00:00.000Z", @@ -128,7 +128,7 @@ }, "xAxisLabel": "timestamp per day", "ordered": { - "interval": "P1D", + "interval": 86400000, "date": true, "min": 1557460800000, "max": 1557656337342 diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json index 6e1a707229974..1987c59f6722b 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json +++ b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json @@ -31,7 +31,7 @@ }, "params": { "date": true, - "interval": "P1D", + "interval": 86400000, "format": "YYYY-MM-DD", "bounds": { "min": "2019-05-10T04:00:00.000Z", @@ -128,7 +128,7 @@ }, "xAxisLabel": "timestamp per day", "ordered": { - "interval": "P1D", + "interval": 86400000, "date": true, "min": 1557460800000, "max": 1557656337342 @@ -460,4 +460,4 @@ "50th percentile of AvgTicketPrice" ] } -} \ No newline at end of file +} diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json index f7dd18f5eb712..ae1f3cbf24c33 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json +++ b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json @@ -32,7 +32,7 @@ }, "params": { "date": true, - "interval": "P1D", + "interval": 86400000, "format": "YYYY-MM-DD", "bounds": { "min": "2019-05-10T04:00:00.000Z", @@ -453,4 +453,4 @@ } ], "enableHover": true -} \ No newline at end of file +} diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json index 02062c987564e..f2ee245a8431f 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json +++ b/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json @@ -32,7 +32,7 @@ }, "params": { "date": true, - "interval": "P1D", + "interval": 86400000, "format": "YYYY-MM-DD", "bounds": { "min": "2019-05-10T04:00:00.000Z", @@ -455,4 +455,4 @@ } ], "enableHover": true -} \ No newline at end of file +} diff --git a/src/plugins/vis_type_vislib/public/vislib/response_handler.js b/src/plugins/vis_type_vislib/public/vislib/response_handler.js index 871ce97ad4480..9028b53fbd003 100644 --- a/src/plugins/vis_type_vislib/public/vislib/response_handler.js +++ b/src/plugins/vis_type_vislib/public/vislib/response_handler.js @@ -34,14 +34,16 @@ function tableResponseHandler(table, dimensions) { table.rows.forEach((row, rowIndex) => { const splitValue = row[splitColumn.id]; + const formattedValue = splitColumnFormatter.convert(splitValue); if (!splitMap.hasOwnProperty(splitValue)) { splitMap[splitValue] = splitIndex++; const tableGroup = { $parent: converted, - title: `${splitColumnFormatter.convert(splitValue)}: ${splitColumn.name}`, + title: `${formattedValue}: ${splitColumn.name}`, name: splitColumn.name, key: splitValue, + formattedKey: formattedValue, column: splitColumnIndex, row: rowIndex, table, diff --git a/src/plugins/vis_type_vislib/public/vislib/types.ts b/src/plugins/vis_type_vislib/public/vislib/types.ts index ad59603663b84..5096015c99a90 100644 --- a/src/plugins/vis_type_vislib/public/vislib/types.ts +++ b/src/plugins/vis_type_vislib/public/vislib/types.ts @@ -33,6 +33,7 @@ export interface TableParent { column: number; row: number; key: number; + formattedKey: string; name: string; } export interface Table { diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js b/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js index a2b830ffaa781..40d15733b418d 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js +++ b/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js @@ -22,8 +22,8 @@ import { Chart } from './_chart'; import { gaugeTypes } from './gauges/gauge_types'; export class GaugeChart extends Chart { - constructor(handler, chartEl, chartData, deps) { - super(handler, chartEl, chartData, deps); + constructor(handler, chartEl, chartData, uiSettings) { + super(handler, chartEl, chartData, uiSettings); this.gaugeConfig = handler.visConfig.get('gauge', {}); this.gauge = new gaugeTypes[this.gaugeConfig.type](this); } diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js b/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js index 4564721464767..d725c29eef310 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js +++ b/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js @@ -40,8 +40,8 @@ const defaults = { * @param chartData {Object} Elasticsearch query results for this specific chart */ export class HeatmapChart extends PointSeries { - constructor(handler, chartEl, chartData, seriesConfigArgs, deps) { - super(handler, chartEl, chartData, seriesConfigArgs, deps); + constructor(handler, chartEl, chartData, seriesConfigArgs, core) { + super(handler, chartEl, chartData, seriesConfigArgs, core); this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults); diff --git a/src/plugins/vis_type_vislib/server/ui_settings.ts b/src/plugins/vis_type_vislib/server/ui_settings.ts index a48cbbae3d0ca..58564b4055daa 100644 --- a/src/plugins/vis_type_vislib/server/ui_settings.ts +++ b/src/plugins/vis_type_vislib/server/ui_settings.ts @@ -24,6 +24,8 @@ import { UiSettingsParams } from 'kibana/server'; import { DIMMING_OPACITY_SETTING, HEATMAP_MAX_BUCKETS_SETTING } from '../common'; export const uiSettings: Record = { + // TODO: move this to vis_type_xy when vislib is removed + // https://github.com/elastic/kibana/issues/56143 [DIMMING_OPACITY_SETTING]: { name: i18n.translate('visTypeVislib.advancedSettings.visualization.dimmingOpacityTitle', { defaultMessage: 'Dimming opacity', diff --git a/src/plugins/vis_type_xy/README.md b/src/plugins/vis_type_xy/README.md index 70ddb21c1e9db..549fc4e3ea189 100644 --- a/src/plugins/vis_type_xy/README.md +++ b/src/plugins/vis_type_xy/README.md @@ -1,2 +1,2 @@ Contains the new xy-axis chart using the elastic-charts library, which will eventually -replace the vislib xy-axis (bar, area, line) charts. \ No newline at end of file +replace the vislib xy-axis charts including bar, area, and line. diff --git a/src/plugins/vis_type_xy/common/index.ts b/src/plugins/vis_type_xy/common/index.ts new file mode 100644 index 0000000000000..edee1ea3219db --- /dev/null +++ b/src/plugins/vis_type_xy/common/index.ts @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { $Values } from '@kbn/utility-types'; + +/** + * Type of charts able to render + */ +export const ChartType = Object.freeze({ + Line: 'line' as const, + Area: 'area' as const, + Histogram: 'histogram' as const, +}); +export type ChartType = $Values; + +/** + * Type of xy visualizations + */ +export type XyVisType = ChartType | 'horizontal_bar'; + +export const LEGACY_CHARTS_LIBRARY = 'visualization:visualize:legacyChartsLibrary'; diff --git a/src/plugins/vis_type_xy/jest.config.js b/src/plugins/vis_type_xy/jest.config.js new file mode 100644 index 0000000000000..556e518d4f4e1 --- /dev/null +++ b/src/plugins/vis_type_xy/jest.config.js @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/src/plugins/vis_type_xy'], +}; diff --git a/src/plugins/vis_type_xy/kibana.json b/src/plugins/vis_type_xy/kibana.json index ca02da45e9112..619fa8e71c0dd 100644 --- a/src/plugins/vis_type_xy/kibana.json +++ b/src/plugins/vis_type_xy/kibana.json @@ -3,5 +3,6 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["charts", "expressions", "visualizations"] + "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection"], + "requiredBundles": ["kibanaUtils", "visDefaultEditor"] } diff --git a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap new file mode 100644 index 0000000000000..e6665c26a2815 --- /dev/null +++ b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`xy vis toExpressionAst function should match basic snapshot 1`] = ` +Object { + "addArgument": [Function], + "arguments": Object { + "type": Array [ + "area", + ], + "visConfig": Array [ + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + ], + }, + "getArgument": [Function], + "name": "xy_vis", + "removeArgument": [Function], + "replaceArgument": [Function], + "toAst": [Function], + "toString": [Function], + "type": "expression_function_builder", +} +`; diff --git a/src/plugins/vis_type_xy/public/_chart.scss b/src/plugins/vis_type_xy/public/_chart.scss new file mode 100644 index 0000000000000..ac9d4ed04aec4 --- /dev/null +++ b/src/plugins/vis_type_xy/public/_chart.scss @@ -0,0 +1,7 @@ +.xyChart__container { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} diff --git a/src/plugins/vis_type_xy/public/components/_detailed_tooltip.scss b/src/plugins/vis_type_xy/public/components/_detailed_tooltip.scss new file mode 100644 index 0000000000000..91b0a8d023290 --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/_detailed_tooltip.scss @@ -0,0 +1,34 @@ +.detailedTooltip { + @include euiToolTipStyle('s'); + pointer-events: none; + max-width: $euiSizeXL * 10; + overflow: hidden; + padding: $euiSizeS; + + table { + td, + th { + text-align: left; + padding: $euiSizeXS; + overflow-wrap: break-word; + word-wrap: break-word; + } + } +} + +.detailedTooltip__header { + > :last-child { + margin-bottom: $euiSizeS; + } +} + +.detailedTooltip__labelContainer, +.detailedTooltip__valueContainer { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.detailedTooltip__label { + font-weight: $euiFontWeightMedium; + color: shade($euiColorGhost, 20%); +} diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx new file mode 100644 index 0000000000000..3427baed41b8d --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx @@ -0,0 +1,142 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { isNil } from 'lodash'; + +import { + CustomTooltip, + TooltipValue, + TooltipValueFormatter, + XYChartSeriesIdentifier, +} from '@elastic/charts'; + +import { BUCKET_TYPES } from '../../../data/public'; + +import { Aspects } from '../types'; + +import './_detailed_tooltip.scss'; +import { fillEmptyValue } from '../utils/get_series_name_fn'; +import { COMPLEX_SPLIT_ACCESSOR } from '../utils/accessors'; + +interface TooltipData { + label: string; + value: string; +} + +const getTooltipData = ( + aspects: Aspects, + header: TooltipValue | null, + value: TooltipValue +): TooltipData[] => { + const data: TooltipData[] = []; + + if (header) { + const xFormatter = + aspects.x.aggType === BUCKET_TYPES.DATE_RANGE || aspects.x.aggType === BUCKET_TYPES.RANGE + ? null + : aspects.x.formatter; + data.push({ + label: aspects.x.title, + value: xFormatter ? xFormatter(header.value) : `${header.value}`, + }); + } + + const valueSeries = value.seriesIdentifier as XYChartSeriesIdentifier; + const yAccessor = aspects.y.find(({ accessor }) => accessor === valueSeries.yAccessor) ?? null; + + if (yAccessor) { + data.push({ + label: yAccessor.title, + value: yAccessor.formatter ? yAccessor.formatter(value.value) : `${value.value}`, + }); + } + + if (aspects.z && !isNil(value.markValue)) { + data.push({ + label: aspects.z.title, + value: aspects.z.formatter ? aspects.z.formatter(value.markValue) : `${value.markValue}`, + }); + } + + valueSeries.splitAccessors.forEach((splitValue, key) => { + const split = (aspects.series ?? []).find(({ accessor }, i) => { + return accessor === key || key === `${COMPLEX_SPLIT_ACCESSOR}::${i}`; + }); + + if (split) { + data.push({ + label: split?.title, + value: + split?.formatter && !key.toString().startsWith(COMPLEX_SPLIT_ACCESSOR) + ? split?.formatter(splitValue) + : `${splitValue}`, + }); + } + }); + + return data; +}; + +const renderData = ({ label, value: rawValue }: TooltipData, index: number) => { + const value = fillEmptyValue(rawValue); + return label && value ? ( + + +
{label}
+ + + +
{value}
+ + + ) : null; +}; + +export const getDetailedTooltip = (aspects: Aspects) => ( + headerFormatter?: TooltipValueFormatter +): CustomTooltip => { + return function DetailedTooltip({ header, values }) { + // Note: first value is not necessarily the closest value + // To be fixed with https://github.com/elastic/elastic-charts/issues/835 + // TODO: Allow multiple values to be displayed in tooltip + const highlightedValue = values.find(({ isHighlighted }) => isHighlighted); + + if (!highlightedValue) { + return null; + } + + const tooltipData = getTooltipData(aspects, header, highlightedValue); + + if (tooltipData.length === 0) { + return null; + } + + return ( +
+ {headerFormatter && header && ( +
{headerFormatter(header)}
+ )} + + {tooltipData.map(renderData)} +
+
+ ); + }; +}; diff --git a/src/plugins/vis_type_xy/public/components/index.ts b/src/plugins/vis_type_xy/public/components/index.ts new file mode 100644 index 0000000000000..d8d55c77b7a8a --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/index.ts @@ -0,0 +1,25 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { XYAxis } from './xy_axis'; +export { XYEndzones } from './xy_endzones'; +export { XYCurrentTime } from './xy_current_time'; +export { XYSettings } from './xy_settings'; +export { XYThresholdLine } from './xy_threshold_line'; +export { SplitChartWarning } from './split_chart_warning'; diff --git a/src/plugins/vis_type_xy/public/components/split_chart_warning.tsx b/src/plugins/vis_type_xy/public/components/split_chart_warning.tsx new file mode 100644 index 0000000000000..7265e70a791a3 --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/split_chart_warning.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FC } from 'react'; + +import { EuiLink, EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { getDocLinks } from '../services'; + +export const SplitChartWarning: FC = () => { + const advancedSettingsLink = getDocLinks().links.management.visualizationSettings; + + return ( + + + + + ), + }} + /> + + ); +}; diff --git a/src/plugins/inspector/common/adapters/data/types.ts b/src/plugins/vis_type_xy/public/components/xy_axis.tsx similarity index 53% rename from src/plugins/inspector/common/adapters/data/types.ts rename to src/plugins/vis_type_xy/public/components/xy_axis.tsx index 040724f4ae36e..b64f2bf1ec0ec 100644 --- a/src/plugins/inspector/common/adapters/data/types.ts +++ b/src/plugins/vis_type_xy/public/components/xy_axis.tsx @@ -17,32 +17,39 @@ * under the License. */ -export interface TabularDataValue { - formatted: string; - raw: unknown; -} +import React, { FC } from 'react'; -export interface TabularDataColumn { - name: string; - field: string; - filter?: (value: TabularDataValue) => void; - filterOut?: (value: TabularDataValue) => void; -} +import { Axis } from '@elastic/charts'; -export type TabularDataRow = Record; +import { AxisConfig } from '../types'; -export interface TabularData { - columns: TabularDataColumn[]; - rows: TabularDataRow[]; -} +type XYAxisPros = AxisConfig; -export type TabularCallback = () => TabularData | Promise; - -export interface TabularHolder { - data: TabularData | null; - options: TabularLoaderOptions; -} - -export interface TabularLoaderOptions { - returnsFormattedValues?: boolean; -} +export const XYAxis: FC = ({ + id, + title, + show, + position, + groupId, + grid, + ticks, + domain, + style, + integersOnly, +}) => ( + +); diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/__mocks__/@elastic/charts.js b/src/plugins/vis_type_xy/public/components/xy_current_time.tsx similarity index 61% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/__mocks__/@elastic/charts.js rename to src/plugins/vis_type_xy/public/components/xy_current_time.tsx index 19bfe685cac90..66ad4fda3bec7 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/__mocks__/@elastic/charts.js +++ b/src/plugins/vis_type_xy/public/components/xy_current_time.tsx @@ -17,28 +17,21 @@ * under the License. */ -export const CurveType = { - CURVE_CARDINAL: 0, - CURVE_NATURAL: 1, - CURVE_MONOTONE_X: 2, - CURVE_MONOTONE_Y: 3, - CURVE_BASIS: 4, - CURVE_CATMULL_ROM: 5, - CURVE_STEP: 6, - CURVE_STEP_AFTER: 7, - CURVE_STEP_BEFORE: 8, - LINEAR: 9, -}; +import React, { FC } from 'react'; +import { DomainRange } from '@elastic/charts'; +import { CurrentTime } from '../../../charts/public'; -export const ScaleType = { - Linear: 'linear', - Ordinal: 'ordinal', - Log: 'log', - Sqrt: 'sqrt', - Time: 'time', -}; +interface XYCurrentTime { + enabled: boolean; + isDarkMode: boolean; + domain?: DomainRange; +} -export const BarSeries = () => null; -export const AreaSeries = () => null; +export const XYCurrentTime: FC = ({ enabled, isDarkMode, domain }) => { + if (!enabled) { + return null; + } -export { LIGHT_THEME, DARK_THEME } from '@elastic/charts'; + const domainEnd = domain && 'max' in domain ? domain.max : undefined; + return ; +}; diff --git a/src/plugins/vis_type_xy/public/components/xy_endzones.tsx b/src/plugins/vis_type_xy/public/components/xy_endzones.tsx new file mode 100644 index 0000000000000..33e1d1e18bb1d --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/xy_endzones.tsx @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FC } from 'react'; + +import { DomainRange } from '@elastic/charts'; + +import { Endzones } from '../../../charts/public'; + +interface XYEndzones { + enabled: boolean; + isDarkMode: boolean; + isFullBin: boolean; + hideTooltips?: boolean; + domain?: DomainRange; + adjustedDomain?: DomainRange; +} + +export const XYEndzones: FC = ({ + enabled, + isDarkMode, + isFullBin, + hideTooltips, + domain, + adjustedDomain, +}) => { + if ( + enabled && + domain && + adjustedDomain && + 'min' in domain && + 'max' in domain && + domain.minInterval !== undefined && + 'min' in adjustedDomain && + 'max' in adjustedDomain + ) { + return ( + + ); + } + + return null; +}; diff --git a/src/plugins/vis_type_xy/public/components/xy_settings.tsx b/src/plugins/vis_type_xy/public/components/xy_settings.tsx new file mode 100644 index 0000000000000..3682fdf3350b0 --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/xy_settings.tsx @@ -0,0 +1,182 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FC } from 'react'; + +import { + Direction, + Settings, + DomainRange, + Position, + PartialTheme, + ElementClickListener, + BrushEndListener, + RenderChangeListener, + LegendAction, + LegendColorPicker, + TooltipProps, + TickFormatter, +} from '@elastic/charts'; + +import { renderEndzoneTooltip } from '../../../charts/public'; + +import { getThemeService, getUISettings } from '../services'; +import { VisConfig } from '../types'; +import { fillEmptyValue } from '../utils/get_series_name_fn'; + +declare global { + interface Window { + /** + * Flag used to enable debugState on elastic charts + */ + _echDebugStateFlag?: boolean; + } +} + +type XYSettingsProps = Pick< + VisConfig, + | 'markSizeRatio' + | 'rotation' + | 'enableHistogramMode' + | 'tooltip' + | 'isTimeChart' + | 'xAxis' + | 'orderBucketsBySum' +> & { + xDomain?: DomainRange; + adjustedXDomain?: DomainRange; + showLegend: boolean; + onElementClick: ElementClickListener; + onBrushEnd?: BrushEndListener; + onRenderChange: RenderChangeListener; + legendAction?: LegendAction; + legendColorPicker: LegendColorPicker; + legendPosition: Position; +}; + +export const XYSettings: FC = ({ + markSizeRatio, + rotation, + enableHistogramMode, + tooltip, + isTimeChart, + xAxis, + orderBucketsBySum, + xDomain, + adjustedXDomain, + showLegend, + onElementClick, + onBrushEnd, + onRenderChange, + legendAction, + legendColorPicker, + legendPosition, +}) => { + const themeService = getThemeService(); + const theme = themeService.useChartsTheme(); + const baseTheme = themeService.useChartsBaseTheme(); + const dimmingOpacity = getUISettings().get('visualization:dimmingOpacity'); + const fontSize = + typeof theme.barSeriesStyle?.displayValue?.fontSize === 'number' + ? { min: theme.barSeriesStyle?.displayValue?.fontSize } + : theme.barSeriesStyle?.displayValue?.fontSize ?? { min: 8 }; + + const themeOverrides: PartialTheme = { + markSizeRatio, + sharedStyle: { + unhighlighted: { + opacity: dimmingOpacity, + }, + }, + barSeriesStyle: { + displayValue: { + fontSize, + alignment: { + horizontal: 'center', + vertical: 'middle', + }, + }, + }, + axes: { + axisTitle: { + padding: { + outer: 10, + }, + }, + }, + chartMargins: + legendPosition === Position.Top || legendPosition === Position.Right + ? { + bottom: (theme.chartMargins?.bottom ?? 0) + 10, + } + : { + right: (theme.chartMargins?.right ?? 0) + 10, + }, + }; + + const headerValueFormatter: TickFormatter | undefined = xAxis.ticks?.formatter + ? (value) => fillEmptyValue(xAxis.ticks?.formatter?.(value)) ?? '' + : undefined; + const headerFormatter = + isTimeChart && xDomain && adjustedXDomain + ? renderEndzoneTooltip( + xDomain.minInterval, + 'min' in xDomain ? xDomain.min : undefined, + 'max' in xDomain ? xDomain.max : undefined, + headerValueFormatter, + !tooltip.detailedTooltip + ) + : headerValueFormatter && + (tooltip.detailedTooltip ? undefined : ({ value }: any) => headerValueFormatter(value)); + + const tooltipProps: TooltipProps = tooltip.detailedTooltip + ? { + ...tooltip, + customTooltip: tooltip.detailedTooltip(headerFormatter), + headerFormatter: undefined, + } + : { ...tooltip, headerFormatter }; + + return ( + + ); +}; diff --git a/src/plugins/vis_type_xy/public/components/xy_threshold_line.tsx b/src/plugins/vis_type_xy/public/components/xy_threshold_line.tsx new file mode 100644 index 0000000000000..46b0a009807a2 --- /dev/null +++ b/src/plugins/vis_type_xy/public/components/xy_threshold_line.tsx @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FC } from 'react'; + +import { AnnotationDomainTypes, LineAnnotation } from '@elastic/charts'; + +import { ThresholdLineConfig } from '../types'; + +type XYThresholdLineProps = ThresholdLineConfig & { + groupId?: string; +}; + +export const XYThresholdLine: FC = ({ + show, + value: dataValue, + color, + width, + groupId, + dash, +}) => { + if (!show) { + return null; + } + + return ( + + ); +}; diff --git a/src/plugins/vis_type_xy/public/config/get_agg_id.ts b/src/plugins/vis_type_xy/public/config/get_agg_id.ts new file mode 100644 index 0000000000000..7923145d83013 --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_agg_id.ts @@ -0,0 +1,25 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Get agg id from accessor + * + * For now this is determined by the esaggs column name. Could be cleaned up in the future. + */ +export const getAggId = (accessor: string) => (accessor ?? '').split('-').pop() ?? ''; diff --git a/src/plugins/vis_type_xy/public/config/get_aspects.ts b/src/plugins/vis_type_xy/public/config/get_aspects.ts new file mode 100644 index 0000000000000..73096de0a5d51 --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_aspects.ts @@ -0,0 +1,95 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { compact } from 'lodash'; + +import { i18n } from '@kbn/i18n'; + +import { DatatableColumn } from '../../../expressions/public'; + +import { Aspect, Dimension, Aspects, Dimensions } from '../types'; +import { getFormatService } from '../services'; +import { getAggId } from './get_agg_id'; + +export function getEmptyAspect(): Aspect { + return { + accessor: null, + aggId: null, + aggType: null, + title: i18n.translate('visTypeXy.aggResponse.allDocsTitle', { + defaultMessage: 'All docs', + }), + params: { + defaultValue: '_all', + }, + }; +} +export function getAspects(columns: DatatableColumn[], { x, y, z, series }: Dimensions): Aspects { + const seriesDimensions = Array.isArray(series) || series === undefined ? series : [series]; + + return { + x: getAspectsFromDimension(columns, x) ?? getEmptyAspect(), + y: getAspectsFromDimension(columns, y) ?? [], + z: z && z?.length > 0 ? getAspectsFromDimension(columns, z[0]) : undefined, + series: getAspectsFromDimension(columns, seriesDimensions), + }; +} + +function getAspectsFromDimension( + columns: DatatableColumn[], + dimension?: Dimension | null +): Aspect | undefined; +function getAspectsFromDimension( + columns: DatatableColumn[], + dimensions?: Dimension[] | null +): Aspect[] | undefined; +function getAspectsFromDimension( + columns: DatatableColumn[], + dimensions?: Dimension | Dimension[] | null +): Aspect[] | Aspect | undefined { + if (!dimensions) { + return; + } + + if (Array.isArray(dimensions)) { + return compact( + dimensions.map((d) => { + const column = d && columns[d.accessor]; + return column && getAspect(column, d); + }) + ); + } + + const column = columns[dimensions.accessor]; + return column && getAspect(column, dimensions); +} + +const getAspect = ( + { id: accessor, name: title }: DatatableColumn, + { accessor: column, format, params, aggType }: Dimension +): Aspect => ({ + accessor, + column, + title, + format, + aggType, + aggId: getAggId(accessor), + formatter: (value: any) => getFormatService().deserialize(format).convert(value), + params, +}); diff --git a/src/plugins/vis_type_xy/public/config/get_axis.ts b/src/plugins/vis_type_xy/public/config/get_axis.ts new file mode 100644 index 0000000000000..43a9e25e0e287 --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_axis.ts @@ -0,0 +1,198 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { identity, isNil } from 'lodash'; + +import { AxisSpec, TickFormatter, YDomainRange, ScaleType as ECScaleType } from '@elastic/charts'; + +import { LabelRotation } from '../../../charts/public'; +import { BUCKET_TYPES } from '../../../data/public'; + +import { + Aspect, + CategoryAxis, + Grid, + AxisConfig, + TickOptions, + ScaleConfig, + Scale, + ScaleType, + AxisType, + XScaleType, + YScaleType, + SeriesParam, +} from '../types'; +import { fillEmptyValue } from '../utils/get_series_name_fn'; + +export function getAxis( + { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, + { categoryLines, valueAxis }: Grid, + { params, format, formatter, title: fallbackTitle = '', aggType }: Aspect, + seriesParams: SeriesParam[], + isDateHistogram = false +): AxisConfig { + const isCategoryAxis = type === AxisType.Category; + // Hide unassigned axis, not supported in elastic charts + // TODO: refactor when disallowing unassigned axes + // https://github.com/elastic/kibana/issues/82752 + const show = + (isCategoryAxis || seriesParams.some(({ valueAxis: id }) => id === axis.id)) && axis.show; + const groupId = axis.id; + + const grid = isCategoryAxis + ? { + show: categoryLines, + } + : { + show: valueAxis === axis.id, + }; + // Date range formatter applied on xAccessor + const tickFormatter = + aggType === BUCKET_TYPES.DATE_RANGE || aggType === BUCKET_TYPES.RANGE ? identity : formatter; + const ticks: TickOptions = { + formatter: tickFormatter, + labelFormatter: getLabelFormatter(labels.truncate, tickFormatter), + show: labels.show, + rotation: labels.rotate, + showOverlappingLabels: !labels.filter, + showDuplicates: !labels.filter, + }; + const scale = getScale(axisScale, params, format, isCategoryAxis); + const title = axisTitle.text || fallbackTitle; + const fallbackRotation = + isCategoryAxis && isDateHistogram ? LabelRotation.Horizontal : LabelRotation.Vertical; + + return { + ...axis, + show, + groupId, + title, + ticks, + grid, + scale, + style: getAxisStyle(ticks, title, fallbackRotation), + domain: getAxisDomain(scale, isCategoryAxis), + integersOnly: aggType === 'count', + }; +} + +function getLabelFormatter( + truncate?: number | null, + formatter?: TickFormatter +): TickFormatter | undefined { + if (truncate === null || truncate === undefined) { + return formatter; + } + + return (value: any) => { + const formattedStringValue = `${formatter ? formatter(value) : value}`; + const finalValue = fillEmptyValue(formattedStringValue); + + if (finalValue.length > truncate) { + return `${finalValue.slice(0, truncate)}...`; + } + + return finalValue; + }; +} + +function getScaleType( + scale?: Scale, + isNumber?: boolean, + isTime = false, + isHistogram = false +): ECScaleType | undefined { + if (isTime) return ECScaleType.Time; + if (isHistogram) return ECScaleType.Linear; + + if (!isNumber) { + return ECScaleType.Ordinal; + } + + const type = scale?.type; + if (type === ScaleType.SquareRoot) { + return ECScaleType.Sqrt; + } + + return type; +} + +function getScale( + scale: Scale, + params: Aspect['params'], + format: Aspect['format'], + isCategoryAxis: boolean +): ScaleConfig { + const type = (isCategoryAxis + ? getScaleType( + scale, + format?.id === 'number' || (format?.params?.id === 'number' && format?.id !== 'range'), + 'date' in params, + 'interval' in params + ) + : getScaleType(scale, true)) as S; + + return { + ...scale, + type, + }; +} + +function getAxisStyle( + ticks?: TickOptions, + title?: string, + rotationFallback: LabelRotation = LabelRotation.Vertical +): AxisSpec['style'] { + return { + axisTitle: { + visible: (title ?? '').trim().length > 0, + }, + tickLabel: { + visible: ticks?.show, + rotation: -(ticks?.rotation ?? rotationFallback), + }, + }; +} + +function getAxisDomain( + scale: ScaleConfig, + isCategoryAxis: boolean +): YDomainRange | undefined { + if (isCategoryAxis || !scale) { + return; + } + + const { min, max, defaultYExtents, boundsMargin } = scale; + const fit = defaultYExtents; + const padding = boundsMargin; + + if (!isNil(min) && !isNil(max)) { + return { fit, padding, min, max }; + } + + if (!isNil(min)) { + return { fit, padding, min }; + } + + if (!isNil(max)) { + return { fit, padding, max }; + } + + return { fit, padding }; +} diff --git a/src/plugins/vis_type_xy/public/config/get_config.ts b/src/plugins/vis_type_xy/public/config/get_config.ts new file mode 100644 index 0000000000000..f0c5740b1307b --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_config.ts @@ -0,0 +1,134 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ScaleContinuousType } from '@elastic/charts/dist/scales'; + +import { Datatable } from '../../../expressions/public'; +import { BUCKET_TYPES } from '../../../data/public'; + +import { + Aspect, + AxisConfig, + DateHistogramParams, + SeriesParam, + VisConfig, + VisParams, + XScaleType, + YScaleType, +} from '../types'; +import { getThresholdLine } from './get_threshold_line'; +import { getRotation } from './get_rotation'; +import { getTooltip } from './get_tooltip'; +import { getLegend } from './get_legend'; +import { getAxis } from './get_axis'; +import { getAspects } from './get_aspects'; +import { ChartType } from '../index'; + +export function getConfig(table: Datatable, params: VisParams): VisConfig { + const { + thresholdLine, + orderBucketsBySum, + addTimeMarker, + radiusRatio, + labels, + fittingFunction, + detailedTooltip, + isVislibVis, + } = params; + const aspects = getAspects(table.columns, params.dimensions); + const xAxis = getAxis( + params.categoryAxes[0], + params.grid, + aspects.x, + params.seriesParams, + params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM + ); + const tooltip = getTooltip(aspects, params); + const yAxes = params.valueAxes.map((a) => + // uses first y aspect in array for formatting axis + getAxis(a, params.grid, aspects.y[0], params.seriesParams) + ); + const enableHistogramMode = + (params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM || + params.dimensions.x?.aggType === BUCKET_TYPES.HISTOGRAM) && + shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); + const isTimeChart = (aspects.x.params as DateHistogramParams).date ?? false; + + return { + // NOTE: downscale ratio to match current vislib implementation + markSizeRatio: radiusRatio * 0.6, + fittingFunction, + detailedTooltip, + orderBucketsBySum, + isTimeChart, + isVislibVis, + showCurrentTime: addTimeMarker && isTimeChart, + showValueLabel: labels.show ?? false, + enableHistogramMode, + tooltip, + aspects, + xAxis, + yAxes, + legend: getLegend(params), + rotation: getRotation(params.categoryAxes[0]), + thresholdLine: getThresholdLine(thresholdLine, yAxes, params.seriesParams), + }; +} + +/** + * disables histogram mode for any config that has non-stacked clustered bars + * + * @param seriesParams + * @param yAspects + * @param yAxes + */ +const shouldEnableHistogramMode = ( + seriesParams: SeriesParam[], + yAspects: Aspect[], + yAxes: Array> +): boolean => { + const bars = seriesParams.filter(({ type, data: { id: paramId } }) => { + return ( + type === ChartType.Histogram && yAspects.find(({ aggId }) => aggId === paramId) !== undefined + ); + }); + + if (bars.length === 1) { + return true; + } + + const groupIds = [ + ...bars.reduce>((acc, { valueAxis: groupId, mode }) => { + acc.add(groupId); + return acc; + }, new Set()), + ]; + + if (groupIds.length > 1) { + return false; + } + + const test = bars.every(({ valueAxis: groupId, mode }) => { + const yAxisScale = yAxes.find(({ groupId: axisGroupId }) => axisGroupId === groupId)?.scale; + + return mode === 'stacked' || yAxisScale?.mode === 'percentage'; + }); + + return test; +}; diff --git a/src/plugins/vis_type_xy/public/config/get_legend.ts b/src/plugins/vis_type_xy/public/config/get_legend.ts new file mode 100644 index 0000000000000..a376ec3c4fb96 --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_legend.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { LegendOptions, VisParams } from '../types'; + +export function getLegend({ addLegend, legendPosition }: VisParams): LegendOptions { + return { + show: addLegend, + position: legendPosition, + }; +} diff --git a/src/plugins/vis_type_xy/public/config/get_rotation.ts b/src/plugins/vis_type_xy/public/config/get_rotation.ts new file mode 100644 index 0000000000000..3c1e9a8f9130a --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_rotation.ts @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Rotation } from '@elastic/charts'; + +import { CategoryAxis } from '../types'; + +export function getRotation({ position }: CategoryAxis): Rotation { + if (position === 'left' || position === 'right') { + return 90; + } + + return 0; +} diff --git a/src/plugins/inspector/common/adapters/data/data_adapter.ts b/src/plugins/vis_type_xy/public/config/get_threshold_line.ts similarity index 51% rename from src/plugins/inspector/common/adapters/data/data_adapter.ts rename to src/plugins/vis_type_xy/public/config/get_threshold_line.ts index a21aa7db39145..861769f829074 100644 --- a/src/plugins/inspector/common/adapters/data/data_adapter.ts +++ b/src/plugins/vis_type_xy/public/config/get_threshold_line.ts @@ -17,24 +17,38 @@ * under the License. */ -import { EventEmitter } from 'events'; -import { TabularCallback, TabularHolder, TabularLoaderOptions } from './types'; +import { + ThresholdLineConfig, + ThresholdLine, + ThresholdLineStyle, + AxisConfig, + SeriesParam, + YScaleType, +} from '../types'; -export class DataAdapter extends EventEmitter { - private tabular?: TabularCallback; - private tabularOptions?: TabularLoaderOptions; +export function getThresholdLine( + { style, ...rest }: ThresholdLine, + yAxes: Array>, + seriesParams: SeriesParam[] +): ThresholdLineConfig { + const groupId = yAxes.find(({ id }) => seriesParams.some(({ valueAxis }) => id === valueAxis)) + ?.groupId; - public setTabularLoader(callback: TabularCallback, options: TabularLoaderOptions = {}): void { - this.tabular = callback; - this.tabularOptions = options; - this.emit('change', 'tabular'); - } + return { + ...rest, + dash: getDash(style), + groupId, + }; +} - public getTabular(): Promise { - if (!this.tabular || !this.tabularOptions) { - return Promise.resolve({ data: null, options: {} }); - } - const options = this.tabularOptions; - return Promise.resolve(this.tabular()).then((data) => ({ data, options })); +function getDash(style: ThresholdLineStyle): number[] | undefined { + switch (style) { + case ThresholdLineStyle.Dashed: + return [10, 5]; + case ThresholdLineStyle.DotDashed: + return [20, 5, 5, 5]; + case ThresholdLineStyle.Full: + default: + return; } } diff --git a/src/plugins/vis_type_xy/public/config/get_tooltip.ts b/src/plugins/vis_type_xy/public/config/get_tooltip.ts new file mode 100644 index 0000000000000..87146eeca9155 --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/get_tooltip.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { TooltipType } from '@elastic/charts'; + +import { Aspects, VisParams, TooltipConfig } from '../types'; +import { getDetailedTooltip } from '../components/detailed_tooltip'; + +export function getTooltip( + aspects: Aspects, + { addTooltip, detailedTooltip }: VisParams +): TooltipConfig { + return { + type: addTooltip ? TooltipType.VerticalCursor : TooltipType.None, + detailedTooltip: detailedTooltip ? getDetailedTooltip(aspects) : undefined, + }; +} diff --git a/src/plugins/vis_type_xy/public/config/index.ts b/src/plugins/vis_type_xy/public/config/index.ts new file mode 100644 index 0000000000000..2b0e32f726a6c --- /dev/null +++ b/src/plugins/vis_type_xy/public/config/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { getConfig } from './get_config'; +export { getAggId } from './get_agg_id'; diff --git a/src/plugins/vis_type_xy/public/editor/collections.ts b/src/plugins/vis_type_xy/public/editor/collections.ts new file mode 100644 index 0000000000000..0149bc476f5c5 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/collections.ts @@ -0,0 +1,201 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Fit } from '@elastic/charts'; + +import { AxisMode, ChartMode, InterpolationMode, ThresholdLineStyle } from '../types'; +import { ChartType } from '../../common'; +import { LabelRotation } from '../../../charts/public'; +import { getScaleTypes } from './scale_types'; +import { getPositions } from './positions'; + +export { getScaleTypes, getPositions }; + +export const getChartTypes = () => [ + { + text: i18n.translate('visTypeXy.chartTypes.lineText', { + defaultMessage: 'Line', + }), + value: ChartType.Line, + }, + { + text: i18n.translate('visTypeXy.chartTypes.areaText', { + defaultMessage: 'Area', + }), + value: ChartType.Area, + }, + { + text: i18n.translate('visTypeXy.chartTypes.barText', { + defaultMessage: 'Bar', + }), + value: ChartType.Histogram, + }, +]; + +export const getChartModes = () => [ + { + text: i18n.translate('visTypeXy.chartModes.normalText', { + defaultMessage: 'Normal', + }), + value: ChartMode.Normal, + }, + { + text: i18n.translate('visTypeXy.chartModes.stackedText', { + defaultMessage: 'Stacked', + }), + value: ChartMode.Stacked, + }, +]; + +export const getInterpolationModes = () => [ + { + text: i18n.translate('visTypeXy.interpolationModes.straightText', { + defaultMessage: 'Straight', + }), + value: InterpolationMode.Linear, + }, + { + text: i18n.translate('visTypeXy.interpolationModes.smoothedText', { + defaultMessage: 'Smoothed', + }), + value: InterpolationMode.Cardinal, + }, + { + text: i18n.translate('visTypeXy.interpolationModes.steppedText', { + defaultMessage: 'Stepped', + }), + value: InterpolationMode.StepAfter, + }, +]; + +export const getAxisModes = () => [ + { + text: i18n.translate('visTypeXy.axisModes.normalText', { + defaultMessage: 'Normal', + }), + value: AxisMode.Normal, + }, + { + text: i18n.translate('visTypeXy.axisModes.percentageText', { + defaultMessage: 'Percentage', + }), + value: AxisMode.Percentage, + }, + { + text: i18n.translate('visTypeXy.axisModes.wiggleText', { + defaultMessage: 'Wiggle', + }), + value: AxisMode.Wiggle, + }, + { + text: i18n.translate('visTypeXy.axisModes.silhouetteText', { + defaultMessage: 'Silhouette', + }), + value: AxisMode.Silhouette, + }, +]; + +export const getThresholdLineStyles = () => [ + { + value: ThresholdLineStyle.Full, + text: i18n.translate('visTypeXy.thresholdLine.style.fullText', { + defaultMessage: 'Full', + }), + }, + { + value: ThresholdLineStyle.Dashed, + text: i18n.translate('visTypeXy.thresholdLine.style.dashedText', { + defaultMessage: 'Dashed', + }), + }, + { + value: ThresholdLineStyle.DotDashed, + text: i18n.translate('visTypeXy.thresholdLine.style.dotdashedText', { + defaultMessage: 'Dot-dashed', + }), + }, +]; + +export const getRotateOptions = () => [ + { + text: i18n.translate('visTypeXy.categoryAxis.rotate.horizontalText', { + defaultMessage: 'Horizontal', + }), + value: LabelRotation.Horizontal, + }, + { + text: i18n.translate('visTypeXy.categoryAxis.rotate.verticalText', { + defaultMessage: 'Vertical', + }), + value: LabelRotation.Vertical, + }, + { + text: i18n.translate('visTypeXy.categoryAxis.rotate.angledText', { + defaultMessage: 'Angled', + }), + value: LabelRotation.Angled, + }, +]; + +export const getFittingFunctions = () => + [ + { + value: Fit.None, + text: i18n.translate('visTypeXy.fittingFunctionsTitle.none', { + defaultMessage: 'Hide (Do not fill gaps)', + }), + }, + { + value: Fit.Zero, + text: i18n.translate('visTypeXy.fittingFunctionsTitle.zero', { + defaultMessage: 'Zero (Fill gaps with zeros)', + }), + }, + { + value: Fit.Linear, + text: i18n.translate('visTypeXy.fittingFunctionsTitle.linear', { + defaultMessage: 'Linear (Fill gaps with a line)', + }), + }, + { + value: Fit.Carry, + text: i18n.translate('visTypeXy.fittingFunctionsTitle.carry', { + defaultMessage: 'Last (Fill gaps with the last value)', + }), + }, + { + value: Fit.Lookahead, + text: i18n.translate('visTypeXy.fittingFunctionsTitle.lookahead', { + defaultMessage: 'Next (Fill gaps with the next value)', + }), + }, + ] as const; + +export const getConfigCollections = () => ({ + legendPositions: getPositions(), + positions: getPositions(), + chartTypes: getChartTypes(), + axisModes: getAxisModes(), + scaleTypes: getScaleTypes(), + chartModes: getChartModes(), + interpolationModes: getInterpolationModes(), + thresholdLineStyles: getThresholdLineStyles(), + fittingFunctions: getFittingFunctions(), +}); diff --git a/src/plugins/vis_type_vislib/public/utils/common_config.tsx b/src/plugins/vis_type_xy/public/editor/common_config.tsx similarity index 59% rename from src/plugins/vis_type_vislib/public/utils/common_config.tsx rename to src/plugins/vis_type_xy/public/editor/common_config.tsx index de867dc72bba7..31d1a9d539621 100644 --- a/src/plugins/vis_type_vislib/public/utils/common_config.tsx +++ b/src/plugins/vis_type_xy/public/editor/common_config.tsx @@ -20,36 +20,37 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { PointSeriesOptions, MetricsAxisOptions } from '../components/options'; -import { ValidationWrapper } from '../components/common'; -import { BasicVislibParams } from '../types'; +import { VisOptionsProps } from '../../../vis_default_editor/public'; -function getAreaOptionTabs() { +import { VisParams } from '../types'; +import { MetricsAxisOptions, PointSeriesOptions } from './components/options'; +import { ValidationWrapper } from './components/common'; + +export function getOptionTabs(showElasticChartsOptions = false) { return [ { name: 'advanced', - title: i18n.translate('visTypeVislib.area.tabs.metricsAxesTitle', { + title: i18n.translate('visTypeXy.area.tabs.metricsAxesTitle', { defaultMessage: 'Metrics & axes', }), - editor: (props: VisOptionsProps) => ( + editor: (props: VisOptionsProps) => ( ), }, { name: 'options', - title: i18n.translate('visTypeVislib.area.tabs.panelSettingsTitle', { + title: i18n.translate('visTypeXy.area.tabs.panelSettingsTitle', { defaultMessage: 'Panel settings', }), - editor: (props: VisOptionsProps) => ( - + editor: (props: VisOptionsProps) => ( + ), }, ]; } - -const countLabel = i18n.translate('visTypeVislib.area.countText', { - defaultMessage: 'Count', -}); - -export { getAreaOptionTabs, countLabel }; diff --git a/src/plugins/vis_type_vislib/public/components/common/index.ts b/src/plugins/vis_type_xy/public/editor/components/common/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/components/common/index.ts rename to src/plugins/vis_type_xy/public/editor/components/common/index.ts diff --git a/src/plugins/vis_type_vislib/public/components/common/truncate_labels.tsx b/src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/components/common/truncate_labels.tsx rename to src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.tsx index 6f55f6f070d00..ae1f34376bbf8 100644 --- a/src/plugins/vis_type_vislib/public/components/common/truncate_labels.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.tsx @@ -33,7 +33,7 @@ function TruncateLabelsOption({ disabled, value = null, setValue }: TruncateLabe return ( extends VisOptionsProps { +export interface ValidationVisOptionsProps extends VisOptionsProps { setMultipleValidity(paramName: string, isValid: boolean): void; + extraProps?: E; } -interface ValidationWrapperProps extends VisOptionsProps { - component: React.ComponentType>; +interface ValidationWrapperProps extends VisOptionsProps { + component: React.ComponentType>; + extraProps?: E; } interface Item { isValid: boolean; } -function ValidationWrapper({ +function ValidationWrapper({ component: Component, ...rest -}: ValidationWrapperProps) { +}: ValidationWrapperProps) { const [panelState, setPanelState] = useState({} as { [key: string]: Item }); const isPanelValid = Object.values(panelState).every((item) => item.isValid); const { setValidity } = rest; diff --git a/src/plugins/vis_type_vislib/public/components/index.ts b/src/plugins/vis_type_xy/public/editor/components/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/components/index.ts rename to src/plugins/vis_type_xy/public/editor/components/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/options/index.tsx b/src/plugins/vis_type_xy/public/editor/components/options/index.tsx new file mode 100644 index 0000000000000..3eba7fa3ad818 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/index.tsx @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { lazy } from 'react'; + +import { VisParams } from '../../../types'; +import { ValidationVisOptionsProps } from '../common'; + +const PointSeriesOptionsLazy = lazy(() => import('./point_series')); +const MetricsAxisOptionsLazy = lazy(() => import('./metrics_axes')); + +export const PointSeriesOptions = ( + props: ValidationVisOptionsProps< + VisParams, + { + showElasticChartsOptions: boolean; + } + > +) => ; + +export const MetricsAxisOptions = (props: ValidationVisOptionsProps) => ( + +); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap similarity index 94% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap index 2b7c03084ec65..bc66c1940ac72 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap @@ -10,7 +10,7 @@ exports[`CategoryAxisPanel component should init with the default set of props 1

diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/index.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap similarity index 99% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/index.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap index 09e0753d592e5..c5ce09d4d78af 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/index.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap @@ -74,7 +74,6 @@ exports[`MetricsAxisOptions component should init with the default set of props /> diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap similarity index 98% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap index ed7ae45eed3a5..594511010b745 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap @@ -18,7 +18,7 @@ exports[`ValueAxesPanel component should init with the default set of props 1`]

@@ -120,7 +120,6 @@ exports[`ValueAxesPanel component should init with the default set of props 1`] } } index={0} - isCategoryAxisHorizontal={false} onValueAxisPositionChanged={[MockFunction]} setMultipleValidity={[MockFunction]} setParamByIndex={[MockFunction]} @@ -303,7 +302,6 @@ exports[`ValueAxesPanel component should init with the default set of props 1`] } } index={1} - isCategoryAxisHorizontal={false} onValueAxisPositionChanged={[MockFunction]} setMultipleValidity={[MockFunction]} setParamByIndex={[MockFunction]} diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap similarity index 96% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap index c4142fb487b6a..3f3ee66a85924 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap @@ -7,22 +7,18 @@ exports[`ValueAxisOptions component should init with the default set of props 1` options={ Array [ Object { - "disabled": false, "text": "Top", "value": "top", }, Object { - "disabled": true, "text": "Left", "value": "left", }, Object { - "disabled": true, "text": "Right", "value": "right", }, Object { - "disabled": false, "text": "Bottom", "value": "bottom", }, diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx similarity index 93% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.test.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx index 44ed0d5aeddab..3bf844618720b 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx @@ -20,16 +20,16 @@ import React from 'react'; import { shallow } from 'enzyme'; import { CategoryAxisPanel, CategoryAxisPanelProps } from './category_axis_panel'; -import { Axis } from '../../../types'; -import { Positions } from '../../../utils/collections'; +import { CategoryAxis } from '../../../../types'; import { LabelOptions } from './label_options'; import { categoryAxis, vis } from './mocks'; +import { Position } from '@elastic/charts'; describe('CategoryAxisPanel component', () => { let setCategoryAxis: jest.Mock; let onPositionChanged: jest.Mock; let defaultProps: CategoryAxisPanelProps; - let axis: Axis; + let axis: CategoryAxis; beforeEach(() => { setCategoryAxis = jest.fn(); @@ -60,7 +60,7 @@ describe('CategoryAxisPanel component', () => { }); it('should call onPositionChanged when position is changed', () => { - const value = Positions.RIGHT; + const value = Position.Right; const comp = shallow(); comp.find({ paramName: 'position' }).prop('setValue')('position', value); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx similarity index 78% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx index 468fb1f8c315a..d4647ae41a637 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/category_axis_panel.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx @@ -19,20 +19,24 @@ import React, { useCallback } from 'react'; -import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; +import { Position } from '@elastic/charts'; + +import { + SelectOption, + SwitchOption, + VisOptionsProps, +} from '../../../../../../vis_default_editor/public'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { Axis } from '../../../types'; -import { SelectOption, SwitchOption } from '../../../../../charts/public'; import { LabelOptions, SetAxisLabel } from './label_options'; -import { Positions } from '../../../utils/collections'; +import { CategoryAxis } from '../../../../types'; export interface CategoryAxisPanelProps { - axis: Axis; - onPositionChanged: (position: Positions) => void; - setCategoryAxis: (value: Axis) => void; + axis: CategoryAxis; + onPositionChanged: (position: Position) => void; + setCategoryAxis: (value: CategoryAxis) => void; vis: VisOptionsProps['vis']; } @@ -43,7 +47,7 @@ function CategoryAxisPanel({ setCategoryAxis, }: CategoryAxisPanelProps) { const setAxis = useCallback( - (paramName: T, value: Axis[T]) => { + (paramName: T, value: CategoryAxis[T]) => { const updatedAxis = { ...axis, [paramName]: value, @@ -54,7 +58,7 @@ function CategoryAxisPanel({ ); const setPosition = useCallback( - (paramName: 'position', value: Axis['position']) => { + (paramName: 'position', value: CategoryAxis['position']) => { setAxis(paramName, value); onPositionChanged(value); }, @@ -77,7 +81,7 @@ function CategoryAxisPanel({

@@ -85,7 +89,7 @@ function CategoryAxisPanel({ { let setParamByIndex: jest.Mock; @@ -53,14 +54,14 @@ describe('ChartOptions component', () => { }); it('should show LineOptions when type is line', () => { - chart.type = ChartTypes.LINE; + chart.type = ChartType.Line; const comp = shallow(); expect(comp.find(LineOptions).exists()).toBeTruthy(); }); it('should show line mode when type is area', () => { - chart.type = ChartTypes.AREA; + chart.type = ChartType.Area; const comp = shallow(); expect(comp.find({ paramName: 'interpolate' }).exists()).toBeTruthy(); @@ -78,8 +79,8 @@ describe('ChartOptions component', () => { it('should call setParamByIndex when mode is changed', () => { const comp = shallow(); const paramName = 'mode'; - comp.find({ paramName }).prop('setValue')(paramName, ChartModes.NORMAL); + comp.find({ paramName }).prop('setValue')(paramName, ChartMode.Normal); - expect(setParamByIndex).toBeCalledWith('seriesParams', 0, paramName, ChartModes.NORMAL); + expect(setParamByIndex).toBeCalledWith('seriesParams', 0, paramName, ChartMode.Normal); }); }); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx similarity index 80% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx index 623a8d1f348e9..070d5fe018150 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/chart_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx @@ -22,12 +22,13 @@ import React, { useMemo, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { Vis } from '../../../../../visualizations/public'; -import { SeriesParam, ValueAxis } from '../../../types'; -import { ChartTypes } from '../../../utils/collections'; -import { SelectOption } from '../../../../../charts/public'; +import { Vis } from '../../../../../../visualizations/public'; +import { SelectOption } from '../../../../../../vis_default_editor/public'; + +import { SeriesParam, ValueAxis } from '../../../../types'; import { LineOptions } from './line_options'; import { SetParamByIndex, ChangeValueAxis } from '.'; +import { ChartType } from '../../../../../common'; export type SetChart = (paramName: T, value: SeriesParam[T]) => void; @@ -69,7 +70,7 @@ function ChartOptions({ value: id, })), { - text: i18n.translate('visTypeVislib.controls.pointSeries.series.newAxisLabel', { + text: i18n.translate('visTypeXy.controls.pointSeries.series.newAxisLabel', { defaultMessage: 'New axis…', }), value: 'new', @@ -82,7 +83,7 @@ function ChartOptions({ <>
- {chart.type === ChartTypes.AREA && ( + {chart.type === ChartType.Area && ( <> )} - {chart.type === ChartTypes.LINE && ( - - )} + {chart.type === ChartType.Line && } ); } diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx similarity index 99% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.test.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx index 4798c67928f7f..82097271f8814 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx @@ -19,6 +19,7 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; + import { CustomExtentsOptions, CustomExtentsOptionsProps } from './custom_extents_options'; import { YExtents } from './y_extents'; import { valueAxis } from './mocks'; diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx similarity index 87% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx index 634d6b3f0641c..f64bdba542b99 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/custom_extents_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx @@ -18,10 +18,12 @@ */ import React, { useCallback, useEffect } from 'react'; + import { i18n } from '@kbn/i18n'; -import { ValueAxis } from '../../../types'; -import { NumberInputOption, SwitchOption } from '../../../../../charts/public'; +import { NumberInputOption, SwitchOption } from '../../../../../../vis_default_editor/public'; + +import { ValueAxis } from '../../../../types'; import { YExtents } from './y_extents'; import { SetScale } from './value_axis_options'; @@ -39,7 +41,7 @@ function CustomExtentsOptions({ setValueAxisScale, }: CustomExtentsOptionsProps) { const invalidBoundsMarginMessage = i18n.translate( - 'visTypeVislib.controls.pointSeries.valueAxes.scaleToDataBounds.minNeededBoundsMargin', + 'visTypeXy.controls.pointSeries.valueAxes.scaleToDataBounds.minNeededBoundsMargin', { defaultMessage: 'Bounds margin must be greater than or equal to 0.' } ); @@ -84,12 +86,9 @@ function CustomExtentsOptions({ return ( <> ({ + SeriesPanel: () => 'SeriesPanel', +})); +jest.mock('./category_axis_panel', () => ({ + CategoryAxisPanel: () => 'CategoryAxisPanel', +})); +jest.mock('./value_axes_panel', () => ({ + ValueAxesPanel: () => 'ValueAxesPanel', +})); + +const SERIES_PARAMS = 'seriesParams'; +const VALUE_AXES = 'valueAxes'; + +const aggCount: IAggConfig = { + id: '1', + type: { name: 'count' }, + makeLabel: () => 'Count', +} as IAggConfig; + +const aggAverage: IAggConfig = { + id: '2', + type: { name: 'average' } as IAggType, + makeLabel: () => 'Average', +} as IAggConfig; + +const createAggs = (aggs: any[]) => ({ + aggs, + bySchemaName: () => aggs, +}); + +describe('MetricsAxisOptions component', () => { + let setValue: jest.Mock; + let defaultProps: ValidationVisOptionsProps; + let axis: ValueAxis; + let axisRight: ValueAxis; + let chart: SeriesParam; + + beforeEach(() => { + setValue = jest.fn(); + + axis = { + ...valueAxis, + name: 'LeftAxis-1', + position: Position.Left, + }; + axisRight = { + ...valueAxis, + id: 'ValueAxis-2', + name: 'RightAxis-1', + position: Position.Right, + }; + chart = { + ...seriesParam, + type: ChartType.Area, + }; + + defaultProps = { + aggs: createAggs([aggCount]), + isTabSelected: true, + vis: { + type: { + type: ChartType.Area, + schemas: { metrics: [{ name: 'metric' }] }, + }, + setState: jest.fn(), + serialize: jest.fn(), + }, + stateParams: { + valueAxes: [axis], + seriesParams: [chart], + categoryAxes: [categoryAxis], + grid: { + valueAxis: defaultValueAxisId, + }, + }, + setValue, + } as any; + }); + + it('should init with the default set of props', () => { + const component = shallow(); + + expect(component).toMatchSnapshot(); + }); + + describe('useEffect', () => { + it('should update series when new agg is added', () => { + const component = mount(); + component.setProps({ + aggs: createAggs([aggCount, aggAverage]), + }); + + const updatedSeries = [chart, { ...chart, data: { id: '2', label: aggAverage.makeLabel() } }]; + expect(setValue).toHaveBeenLastCalledWith(SERIES_PARAMS, updatedSeries); + }); + + it('should update series when new agg label is changed', () => { + const component = mount(); + const agg = { id: aggCount.id, makeLabel: () => 'New label' }; + component.setProps({ + aggs: createAggs([agg]), + }); + + const updatedSeries = [{ ...chart, data: { id: agg.id, label: agg.makeLabel() } }]; + expect(setValue).toHaveBeenCalledWith(SERIES_PARAMS, updatedSeries); + }); + }); + + describe('updateAxisTitle', () => { + it('should not update the value axis title if custom title was set', () => { + defaultProps.stateParams.valueAxes[0].title.text = 'Custom title'; + const component = mount(); + const newAgg = { + ...aggCount, + makeLabel: () => 'Custom label', + }; + component.setProps({ + aggs: createAggs([newAgg]), + }); + const updatedValues = [{ ...axis, title: { text: newAgg.makeLabel() } }]; + expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES, updatedValues); + }); + + it('should set the custom title to match the value axis label when only one agg exists for that axis', () => { + const component = mount(); + const agg = { + id: aggCount.id, + params: { customLabel: 'Custom label' }, + makeLabel: () => 'Custom label', + }; + component.setProps({ + aggs: createAggs([agg]), + }); + + const updatedSeriesParams = [{ ...chart, data: { ...chart.data, label: agg.makeLabel() } }]; + const updatedValues = [{ ...axis, title: { text: agg.makeLabel() } }]; + + expect(setValue).toHaveBeenCalledTimes(5); + expect(setValue).toHaveBeenNthCalledWith(3, SERIES_PARAMS, updatedSeriesParams); + expect(setValue).toHaveBeenNthCalledWith(5, SERIES_PARAMS, updatedSeriesParams); + expect(setValue).toHaveBeenNthCalledWith(4, VALUE_AXES, updatedValues); + }); + + it('should not set the custom title to match the value axis label when more than one agg exists for that axis', () => { + const component = mount(); + const agg = { id: aggCount.id, makeLabel: () => 'Custom label' }; + component.setProps({ + aggs: createAggs([agg, aggAverage]), + stateParams: { + ...defaultProps.stateParams, + seriesParams: [chart, chart], + }, + }); + + expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES); + }); + + it('should not overwrite the custom title with the value axis label if the custom title has been changed', () => { + defaultProps.stateParams.valueAxes[0].title.text = 'Custom title'; + const component = mount(); + const agg = { + id: aggCount.id, + params: { customLabel: 'Custom label' }, + makeLabel: () => 'Custom label', + }; + component.setProps({ + aggs: createAggs([agg]), + }); + + expect(setValue).not.toHaveBeenCalledWith(VALUE_AXES); + }); + }); + + it('should add value axis', () => { + const component = shallow(); + component.find(ValueAxesPanel).prop('addValueAxis')(); + + expect(setValue).toHaveBeenCalledWith(VALUE_AXES, [axis, axisRight]); + }); + + describe('removeValueAxis', () => { + beforeEach(() => { + defaultProps.stateParams.valueAxes = [axis, axisRight]; + }); + + it('should remove value axis', () => { + const component = shallow(); + component.find(ValueAxesPanel).prop('removeValueAxis')(axis); + + expect(setValue).toHaveBeenCalledWith(VALUE_AXES, [axisRight]); + }); + + it('should update seriesParams "valueAxis" prop', () => { + const updatedSeriesParam = { ...chart, valueAxis: 'ValueAxis-2' }; + const component = shallow(); + component.find(ValueAxesPanel).prop('removeValueAxis')(axis); + + expect(setValue).toHaveBeenCalledWith(SERIES_PARAMS, [updatedSeriesParam]); + }); + + it('should reset grid "valueAxis" prop', () => { + const updatedGrid = { valueAxis: undefined }; + defaultProps.stateParams.seriesParams[0].valueAxis = 'ValueAxis-2'; + const component = shallow(); + component.find(ValueAxesPanel).prop('removeValueAxis')(axis); + + expect(setValue).toHaveBeenCalledWith('grid', updatedGrid); + }); + }); + + describe('onValueAxisPositionChanged', () => { + const getProps = ( + valuePosition1: Position = Position.Right, + valuePosition2: Position = Position.Left + ): ValidationVisOptionsProps => ({ + ...defaultProps, + stateParams: { + ...defaultProps.stateParams, + valueAxes: [ + { + ...valueAxis, + id: 'ValueAxis-1', + position: valuePosition1, + }, + { + ...valueAxis, + id: 'ValueAxis-2', + position: valuePosition2, + }, + { + ...valueAxis, + id: 'ValueAxis-3', + position: valuePosition2, + }, + ], + categoryAxes: [ + { + ...categoryAxis, + position: mapPosition(valuePosition1), + }, + ], + }, + }); + + it('should update all value axes if another value axis changes from horizontal to vertical', () => { + const component = mount(); + setValue.mockClear(); + const onValueAxisPositionChanged = component + .find(ValueAxesPanel) + .prop('onValueAxisPositionChanged'); + onValueAxisPositionChanged(0, Position.Bottom); + expect(setValue).nthCalledWith(1, 'categoryAxes', [ + expect.objectContaining({ + id: 'CategoryAxis-1', + position: Position.Right, + }), + ]); + expect(setValue).nthCalledWith(2, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Bottom, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Top, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Top, + }), + ]); + }); + + it('should update all value axes if another value axis changes from vertical to horizontal', () => { + const component = mount(); + setValue.mockClear(); + const onValueAxisPositionChanged = component + .find(ValueAxesPanel) + .prop('onValueAxisPositionChanged'); + onValueAxisPositionChanged(1, Position.Left); + expect(setValue).nthCalledWith(1, 'categoryAxes', [ + expect.objectContaining({ + id: 'CategoryAxis-1', + position: Position.Top, + }), + ]); + expect(setValue).nthCalledWith(2, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Right, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Left, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Left, + }), + ]); + }); + + it('should update only changed value axis if value axis stays horizontal', () => { + const component = mount(); + setValue.mockClear(); + const onValueAxisPositionChanged = component + .find(ValueAxesPanel) + .prop('onValueAxisPositionChanged'); + onValueAxisPositionChanged(0, Position.Left); + expect(setValue).nthCalledWith(1, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Left, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Left, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Left, + }), + ]); + }); + + it('should update only changed value axis if value axis stays vertical', () => { + const component = mount(); + setValue.mockClear(); + const onValueAxisPositionChanged = component + .find(ValueAxesPanel) + .prop('onValueAxisPositionChanged'); + onValueAxisPositionChanged(1, Position.Top); + expect(setValue).nthCalledWith(1, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Top, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Top, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Bottom, + }), + ]); + }); + }); + + describe('onCategoryAxisPositionChanged', () => { + const getProps = ( + position: Position = Position.Bottom + ): ValidationVisOptionsProps => ({ + ...defaultProps, + stateParams: { + ...defaultProps.stateParams, + valueAxes: [ + { + ...valueAxis, + id: 'ValueAxis-1', + position: mapPosition(position), + }, + { + ...valueAxis, + id: 'ValueAxis-2', + position: mapPositionOpposite(mapPosition(position)), + }, + { + ...valueAxis, + id: 'ValueAxis-3', + position: mapPosition(position), + }, + ], + categoryAxes: [ + { + ...categoryAxis, + position, + }, + ], + }, + }); + + it('should update all value axes if category axis changes from horizontal to vertical', () => { + const component = mount(); + setValue.mockClear(); + const onPositionChanged = component.find(CategoryAxisPanel).prop('onPositionChanged'); + onPositionChanged(Position.Left); + expect(setValue).nthCalledWith(1, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Bottom, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Top, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Bottom, + }), + ]); + }); + + it('should update all value axes if category axis changes from vertical to horizontal', () => { + const component = mount(); + setValue.mockClear(); + const onPositionChanged = component.find(CategoryAxisPanel).prop('onPositionChanged'); + onPositionChanged(Position.Top); + expect(setValue).nthCalledWith(1, 'valueAxes', [ + expect.objectContaining({ + id: 'ValueAxis-1', + position: Position.Left, + }), + expect.objectContaining({ + id: 'ValueAxis-2', + position: Position.Right, + }), + expect.objectContaining({ + id: 'ValueAxis-3', + position: Position.Left, + }), + ]); + }); + + it('should not update value axes if category axis stays horizontal', () => { + const component = mount(); + setValue.mockClear(); + const onPositionChanged = component.find(CategoryAxisPanel).prop('onPositionChanged'); + onPositionChanged(Position.Top); + expect(setValue).not.toBeCalled(); + }); + + it('should not update value axes if category axis stays vertical', () => { + const component = mount(); + setValue.mockClear(); + const onPositionChanged = component.find(CategoryAxisPanel).prop('onPositionChanged'); + onPositionChanged(Position.Right); + expect(setValue).not.toBeCalled(); + }); + }); +}); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx similarity index 83% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx index 0862c47c35cff..9b4bf3127d45e 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx @@ -19,10 +19,12 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { cloneDeep, get } from 'lodash'; + import { EuiSpacer } from '@elastic/eui'; -import { IAggConfig } from 'src/plugins/data/public'; -import { BasicVislibParams, ValueAxis, SeriesParam, Axis } from '../../../types'; +import { IAggConfig } from '../../../../../../data/public'; + +import { VisParams, ValueAxis, SeriesParam, CategoryAxis } from '../../../../types'; import { ValidationVisOptionsProps } from '../../common'; import { SeriesPanel } from './series_panel'; import { CategoryAxisPanel } from './category_axis_panel'; @@ -34,6 +36,7 @@ import { getUpdatedAxisName, mapPositionOpposite, mapPosition, + mapPositionOpposingOpposite, } from './utils'; export type SetParamByIndex =

( @@ -51,11 +54,9 @@ export type ChangeValueAxis = ( const VALUE_AXIS_PREFIX = 'ValueAxis-'; -function MetricsAxisOptions(props: ValidationVisOptionsProps) { +function MetricsAxisOptions(props: ValidationVisOptionsProps) { const { stateParams, setValue, aggs, vis, isTabSelected } = props; - const [isCategoryAxisHorizontal, setIsCategoryAxisHorizontal] = useState(true); - const setParamByIndex: SetParamByIndex = useCallback( (axesName, index, paramName, value) => { const items = stateParams[axesName]; @@ -72,7 +73,7 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) ); const setCategoryAxis = useCallback( - (value: Axis) => { + (value: CategoryAxis) => { const categoryAxes = [...stateParams.categoryAxes]; categoryAxes[0] = value; setValue('categoryAxes', categoryAxes); @@ -170,33 +171,58 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) ); const onValueAxisPositionChanged = useCallback( - (index: number, value: ValueAxis['position']) => { + (index: number, axisPosition: ValueAxis['position']) => { + const isHorizontalAxis = isAxisHorizontal(axisPosition); const valueAxes = [...stateParams.valueAxes]; - const name = getUpdatedAxisName(value, valueAxes); + const name = getUpdatedAxisName(axisPosition, valueAxes); + const [categoryAxes] = stateParams.categoryAxes; - valueAxes[index] = { - ...valueAxes[index], - name, - position: value, - }; - setValue('valueAxes', valueAxes); + if (isAxisHorizontal(categoryAxes.position) === isHorizontalAxis) { + const updatedCategoryAxes = { + ...categoryAxes, + position: mapPosition(categoryAxes.position), + }; + + setValue('categoryAxes', [updatedCategoryAxes]); + + const oldPosition = valueAxes[index].position; + const newValueAxes = valueAxes.map(({ position, ...axis }, i) => ({ + ...axis, + position: + i === index + ? axisPosition + : mapPositionOpposingOpposite(position, oldPosition, axisPosition), + })); + setValue('valueAxes', newValueAxes); + } else { + valueAxes[index] = { + ...valueAxes[index], + name, + position: axisPosition, + }; + setValue('valueAxes', valueAxes); + } }, - [stateParams.valueAxes, setValue] + [stateParams.valueAxes, stateParams.categoryAxes, setValue] ); const onCategoryAxisPositionChanged = useCallback( - (chartPosition: Axis['position']) => { - const isChartHorizontal = isAxisHorizontal(chartPosition); - setIsCategoryAxisHorizontal(isAxisHorizontal(chartPosition)); - - stateParams.valueAxes.forEach((axis, index) => { - if (isAxisHorizontal(axis.position) === isChartHorizontal) { - const position = mapPosition(axis.position); - onValueAxisPositionChanged(index, position); - } - }); + (axisPosition: CategoryAxis['position']) => { + const isHorizontalAxis = isAxisHorizontal(axisPosition); + + if ( + stateParams.valueAxes.some( + ({ position }) => isAxisHorizontal(position) === isHorizontalAxis + ) + ) { + const newValueAxes = stateParams.valueAxes.map(({ position, ...axis }) => ({ + ...axis, + position: mapPosition(position), + })); + setValue('valueAxes', newValueAxes); + } }, - [stateParams.valueAxes, onValueAxisPositionChanged] + [setValue, stateParams.valueAxes] ); const addValueAxis = useCallback(() => { @@ -305,7 +331,6 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) ( - paramName: T, - value: Axis['labels'][T] -) => void; +export type SetAxisLabel = (paramName: T, value: Labels[T]) => void; export interface LabelOptionsProps { - axisLabels: Axis['labels']; + axisLabels: Labels; axisFilterCheckboxName: string; setAxisLabel: SetAxisLabel; } function LabelOptions({ axisLabels, axisFilterCheckboxName, setAxisLabel }: LabelOptionsProps) { const setAxisLabelRotate = useCallback( - (paramName: 'rotate', value: Axis['labels']['rotate']) => { + (paramName: 'rotate', value: Labels['rotate']) => { setAxisLabel(paramName, Number(value)); }, [setAxisLabel] @@ -54,7 +52,7 @@ function LabelOptions({ axisLabels, axisFilterCheckboxName, setAxisLabel }: Labe

@@ -62,7 +60,7 @@ function LabelOptions({ axisLabels, axisFilterCheckboxName, setAxisLabel }: Labe

@@ -57,13 +58,10 @@ function SeriesPanel({ seriesParams, ...chartProps }: SeriesPanelProps) { initialIsOpen={index === 0} buttonContent={chart.data.label} buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate" - aria-label={i18n.translate( - 'visTypeVislib.controls.pointSeries.seriesAccordionAriaLabel', - { - defaultMessage: 'Toggle {agg} options', - values: { agg: chart.data.label }, - } - )} + aria-label={i18n.translate('visTypeXy.controls.pointSeries.seriesAccordionAriaLabel', { + defaultMessage: 'Toggle {agg} options', + values: { agg: chart.data.label }, + })} > <> diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/utils.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts similarity index 53% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/utils.ts rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts index 708e8cf15f029..58216ee8953cd 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/utils.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ - import { upperFirst } from 'lodash'; -import { BasicVislibParams, ValueAxis, SeriesParam } from '../../../types'; -import { ChartModes, ChartTypes, InterpolationModes, Positions } from '../../../utils/collections'; +import { Position } from '@elastic/charts'; + +import { VisParams, ValueAxis, SeriesParam, ChartMode, InterpolationMode } from '../../../../types'; +import { ChartType } from '../../../../../common'; -const makeSerie = ( +export const makeSerie = ( id: string, label: string, defaultValueAxis: ValueAxis['id'], @@ -31,11 +32,11 @@ const makeSerie = ( const data = { id, label }; const defaultSerie = { show: true, - mode: ChartModes.NORMAL, - type: ChartTypes.LINE, + mode: ChartMode.Normal, + type: ChartType.Line, drawLinesBetweenPoints: true, showCircles: true, - interpolate: InterpolationModes.LINEAR, + interpolate: InterpolationMode.Linear, lineWidth: 2, valueAxis: defaultValueAxis, data, @@ -43,12 +44,12 @@ const makeSerie = ( return lastSerie ? { ...lastSerie, data } : defaultSerie; }; -const isAxisHorizontal = (position: Positions) => - [Positions.TOP, Positions.BOTTOM].includes(position as any); +export const isAxisHorizontal = (position: Position) => + [Position.Top, Position.Bottom].includes(position as any); const RADIX = 10; -function countNextAxisNumber(axisName: string, axisProp: 'id' | 'name' = 'id') { +export function countNextAxisNumber(axisName: string, axisProp: 'id' | 'name' = 'id') { return (value: number, axis: ValueAxis) => { const nameLength = axisName.length; if (axis[axisProp].substr(0, nameLength) === axisName) { @@ -63,9 +64,9 @@ function countNextAxisNumber(axisName: string, axisProp: 'id' | 'name' = 'id') { const AXIS_PREFIX = 'Axis-'; -const getUpdatedAxisName = ( +export const getUpdatedAxisName = ( axisPosition: ValueAxis['position'], - valueAxes: BasicVislibParams['valueAxes'] + valueAxes: VisParams['valueAxes'] ) => { const axisName = upperFirst(axisPosition) + AXIS_PREFIX; const nextAxisNameNumber = valueAxes.reduce(countNextAxisNumber(axisName, 'name'), 1); @@ -73,39 +74,56 @@ const getUpdatedAxisName = ( return `${axisName}${nextAxisNameNumber}`; }; -function mapPositionOpposite(position: Positions) { +/** + * Maps axis position to opposite position + * @param position + */ +export function mapPositionOpposite(position: Position) { switch (position) { - case Positions.BOTTOM: - return Positions.TOP; - case Positions.TOP: - return Positions.BOTTOM; - case Positions.LEFT: - return Positions.RIGHT; - case Positions.RIGHT: - return Positions.LEFT; + case Position.Bottom: + return Position.Top; + case Position.Top: + return Position.Bottom; + case Position.Left: + return Position.Right; + case Position.Right: + return Position.Left; default: throw new Error('Invalid legend position.'); } } -function mapPosition(position: Positions) { - switch (position) { - case Positions.BOTTOM: - return Positions.LEFT; - case Positions.TOP: - return Positions.RIGHT; - case Positions.LEFT: - return Positions.BOTTOM; - case Positions.RIGHT: - return Positions.TOP; +/** + * Maps axis position to new position or opposite of new position based on old position + * @param position + * @param oldPosition + * @param newPosition + */ +export function mapPositionOpposingOpposite( + position: Position, + oldPosition: Position, + newPosition: Position +) { + if (position === oldPosition) { + return newPosition; } + + return mapPositionOpposite(newPosition); } -export { - makeSerie, - isAxisHorizontal, - countNextAxisNumber, - getUpdatedAxisName, - mapPositionOpposite, - mapPosition, -}; +/** + * Maps axis position to opposite rotation position + * @param position + */ +export function mapPosition(position: Position) { + switch (position) { + case Position.Bottom: + return Position.Left; + case Position.Top: + return Position.Right; + case Position.Left: + return Position.Bottom; + case Position.Right: + return Position.Top; + } +} diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.test.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx index 070433ca03f6d..f3286029db32f 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx @@ -19,10 +19,12 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { ValueAxesPanel, ValueAxesPanelProps } from './value_axes_panel'; -import { ValueAxis, SeriesParam } from '../../../types'; -import { Positions } from '../../../utils/collections'; + import { mountWithIntl } from '@kbn/test/jest'; +import { Position } from '@elastic/charts'; + +import { ValueAxis, SeriesParam } from '../../../../types'; +import { ValueAxesPanel, ValueAxesPanelProps } from './value_axes_panel'; import { valueAxis, seriesParam, vis } from './mocks'; describe('ValueAxesPanel component', () => { @@ -47,7 +49,7 @@ describe('ValueAxesPanel component', () => { axisRight = { ...valueAxis, id: 'ValueAxis-2', - position: Positions.RIGHT, + position: Position.Right, }; seriesParamCount = { ...seriesParam }; seriesParamAverage = { @@ -63,7 +65,6 @@ describe('ValueAxesPanel component', () => { seriesParams: [seriesParamCount, seriesParamAverage], valueAxes: [axisLeft, axisRight], vis, - isCategoryAxisHorizontal: false, setParamByIndex, onValueAxisPositionChanged, addValueAxis, diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx similarity index 90% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx index 5f7d33b7f1f47..397704663ff1f 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axes_panel.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx @@ -31,13 +31,13 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Vis } from '../../../../../visualizations/public'; -import { SeriesParam, ValueAxis } from '../../../types'; +import { Vis } from '../../../../../../visualizations/public'; + +import { SeriesParam, ValueAxis } from '../../../../types'; import { ValueAxisOptions } from './value_axis_options'; import { SetParamByIndex } from '.'; export interface ValueAxesPanelProps { - isCategoryAxisHorizontal: boolean; addValueAxis: () => ValueAxis; removeValueAxis: (axis: ValueAxis) => void; onValueAxisPositionChanged: (index: number, value: ValueAxis['position']) => void; @@ -64,7 +64,7 @@ function ValueAxesPanel(props: ValueAxesPanelProps) { const removeButtonTooltip = useMemo( () => - i18n.translate('visTypeVislib.controls.pointSeries.valueAxes.removeButtonTooltip', { + i18n.translate('visTypeXy.controls.pointSeries.valueAxes.removeButtonTooltip', { defaultMessage: 'Remove Y-axis', }), [] @@ -87,7 +87,7 @@ function ValueAxesPanel(props: ValueAxesPanelProps) { const addButtonTooltip = useMemo( () => - i18n.translate('visTypeVislib.controls.pointSeries.valueAxes.addButtonTooltip', { + i18n.translate('visTypeXy.controls.pointSeries.valueAxes.addButtonTooltip', { defaultMessage: 'Add Y-axis', }), [] @@ -115,7 +115,7 @@ function ValueAxesPanel(props: ValueAxesPanelProps) {

@@ -146,7 +146,7 @@ function ValueAxesPanel(props: ValueAxesPanelProps) { buttonClassName="eui-textTruncate" buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate" aria-label={i18n.translate( - 'visTypeVislib.controls.pointSeries.valueAxes.toggleOptionsAriaLabel', + 'visTypeXy.controls.pointSeries.valueAxes.toggleOptionsAriaLabel', { defaultMessage: 'Toggle {axisName} options', values: { axisName: axis.name }, @@ -160,7 +160,6 @@ function ValueAxesPanel(props: ValueAxesPanelProps) { axis={axis} index={index} valueAxis={valueAxes[index]} - isCategoryAxisHorizontal={props.isCategoryAxisHorizontal} onValueAxisPositionChanged={props.onValueAxisPositionChanged} setParamByIndex={props.setParamByIndex} setMultipleValidity={props.setMultipleValidity} diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx similarity index 64% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx index 1977bdba6eadf..62757d14a0196 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx @@ -19,21 +19,18 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { ValueAxisOptions, ValueAxisOptionsParams } from './value_axis_options'; -import { ValueAxis } from '../../../types'; -import { TextInputOption } from '../../../../../charts/public'; + +import { Position } from '@elastic/charts'; + +import { TextInputOption } from '../../../../../../vis_default_editor/public'; + +import { ValueAxis, ScaleType } from '../../../../types'; import { LabelOptions } from './label_options'; -import { ScaleTypes, Positions } from '../../../utils/collections'; +import { ValueAxisOptions, ValueAxisOptionsParams } from './value_axis_options'; import { valueAxis, vis } from './mocks'; const POSITION = 'position'; -interface PositionOption { - text: string; - value: Positions; - disabled: boolean; -} - describe('ValueAxisOptions component', () => { let setParamByIndex: jest.Mock; let onValueAxisPositionChanged: jest.Mock; @@ -52,7 +49,6 @@ describe('ValueAxisOptions component', () => { index: 0, valueAxis, vis, - isCategoryAxisHorizontal: false, setParamByIndex, onValueAxisPositionChanged, setMultipleValidity, @@ -73,50 +69,8 @@ describe('ValueAxisOptions component', () => { expect(comp.find(LabelOptions).exists()).toBeFalsy(); }); - it('should only allow left and right value axis position when category axis is horizontal', () => { - defaultProps.isCategoryAxisHorizontal = true; - const comp = shallow(); - - const options: PositionOption[] = comp.find({ paramName: POSITION }).prop('options'); - - expect(options.length).toBe(4); - options.forEach(({ value, disabled }) => { - switch (value) { - case Positions.LEFT: - case Positions.RIGHT: - expect(disabled).toBeFalsy(); - break; - case Positions.TOP: - case Positions.BOTTOM: - expect(disabled).toBeTruthy(); - break; - } - }); - }); - - it('should only allow top and bottom value axis position when category axis is vertical', () => { - defaultProps.isCategoryAxisHorizontal = false; - const comp = shallow(); - - const options: PositionOption[] = comp.find({ paramName: POSITION }).prop('options'); - - expect(options.length).toBe(4); - options.forEach(({ value, disabled }) => { - switch (value) { - case Positions.LEFT: - case Positions.RIGHT: - expect(disabled).toBeTruthy(); - break; - case Positions.TOP: - case Positions.BOTTOM: - expect(disabled).toBeFalsy(); - break; - } - }); - }); - it('should call onValueAxisPositionChanged when position is changed', () => { - const value = Positions.RIGHT; + const value = Position.Right; const comp = shallow(); comp.find({ paramName: POSITION }).prop('setValue')(POSITION, value); @@ -135,7 +89,7 @@ describe('ValueAxisOptions component', () => { }); it('should call setValueAxis when scale value is changed', () => { - const scaleValue = ScaleTypes.SQUARE_ROOT; + const scaleValue = ScaleType.SquareRoot; const comp = shallow(); comp.find({ paramName: 'type' }).prop('setValue')('type', scaleValue); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx similarity index 75% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx index b42d038267d77..d81ddcb95ce62 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/value_axis_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx @@ -17,17 +17,20 @@ * under the License. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSpacer, EuiAccordion, EuiHorizontalRule } from '@elastic/eui'; -import { Vis } from '../../../../../visualizations/public'; -import { ValueAxis } from '../../../types'; -import { Positions } from '../../../utils/collections'; -import { SelectOption, SwitchOption, TextInputOption } from '../../../../../charts/public'; +import { Vis } from '../../../../../../visualizations/public'; +import { + SelectOption, + SwitchOption, + TextInputOption, +} from '../../../../../../vis_default_editor/public'; + +import { ValueAxis } from '../../../../types'; import { LabelOptions, SetAxisLabel } from './label_options'; import { CustomExtentsOptions } from './custom_extents_options'; -import { isAxisHorizontal } from './utils'; import { SetParamByIndex } from '.'; export type SetScale = ( @@ -38,7 +41,6 @@ export type SetScale = ( export interface ValueAxisOptionsParams { axis: ValueAxis; index: number; - isCategoryAxisHorizontal: boolean; onValueAxisPositionChanged: (index: number, value: ValueAxis['position']) => void; setParamByIndex: SetParamByIndex; valueAxis: ValueAxis; @@ -46,10 +48,9 @@ export interface ValueAxisOptionsParams { setMultipleValidity: (paramName: string, isValid: boolean) => void; } -function ValueAxisOptions({ +export function ValueAxisOptions({ axis, index, - isCategoryAxisHorizontal, valueAxis, vis, onValueAxisPositionChanged, @@ -105,34 +106,13 @@ function ValueAxisOptions({ [index, onValueAxisPositionChanged] ); - const isPositionDisabled = useCallback( - (position: Positions) => { - if (isCategoryAxisHorizontal) { - return isAxisHorizontal(position); - } - return [Positions.LEFT, Positions.RIGHT].includes(position as any); - }, - [isCategoryAxisHorizontal] - ); - - const positions = useMemo( - () => - vis.type.editorConfig.collections.positions.map( - (position: { text: string; value: Positions }) => ({ - ...position, - disabled: isPositionDisabled(position.value), - }) - ), - [vis.type.editorConfig.collections.positions, isPositionDisabled] - ); - return ( <> ); } - -export { ValueAxisOptions }; diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx similarity index 94% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx index 7bd5c9efdf29d..27a28d96d0608 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx @@ -19,9 +19,10 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; + +import { ScaleType } from '../../../../types'; import { YExtents, YExtentsProps } from './y_extents'; -import { ScaleTypes } from '../../../utils/collections'; -import { NumberInputOption } from '../../../../../charts/public'; +import { NumberInputOption } from '../../../../../../vis_default_editor/public'; describe('YExtents component', () => { let setMultipleValidity: jest.Mock; @@ -35,7 +36,7 @@ describe('YExtents component', () => { defaultProps = { scale: { - type: ScaleTypes.LINEAR, + type: ScaleType.Linear, }, setMultipleValidity, setScale, @@ -81,7 +82,7 @@ describe('YExtents component', () => { it('should call setMultipleValidity with false when min equals 0 and scale is log', () => { defaultProps.scale.min = 0; defaultProps.scale.max = 1; - defaultProps.scale.type = ScaleTypes.LOG; + defaultProps.scale.type = ScaleType.Log; mount(); expect(setMultipleValidity).toBeCalledWith(Y_EXTENTS, false); diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx similarity index 83% rename from src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx index 4e23ee5a41554..ba7049e984573 100644 --- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/y_extents.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx @@ -21,15 +21,15 @@ import React, { useEffect, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Scale } from '../../../types'; -import { ScaleTypes } from '../../../utils/collections'; -import { NumberInputOption } from '../../../../../charts/public'; +import { NumberInputOption } from '../../../../../../vis_default_editor/public'; + +import { Scale, ScaleType } from '../../../../types'; import { SetScale } from './value_axis_options'; -const rangeError = i18n.translate('visTypeVislib.controls.pointSeries.valueAxes.minErrorMessage', { +const rangeError = i18n.translate('visTypeXy.controls.pointSeries.valueAxes.minErrorMessage', { defaultMessage: 'Min should be less than Max.', }); -const minError = i18n.translate('visTypeVislib.controls.pointSeries.valueAxes.minNeededScaleText', { +const minError = i18n.translate('visTypeXy.controls.pointSeries.valueAxes.minNeededScaleText', { defaultMessage: 'Min must exceed 0 when a log scale is selected.', }); @@ -59,7 +59,7 @@ function YExtents({ scale, setScale, setMultipleValidity }: YExtentsProps) { errors.push(rangeError); } - if (type === ScaleTypes.LOG && (isNullOrUndefined(min) || min <= 0)) { + if (type === ScaleType.Log && (isNullOrUndefined(min) || min <= 0)) { errors.push(minError); } @@ -86,7 +86,7 @@ function YExtents({ scale, setScale, setMultipleValidity }: YExtentsProps) { ) { + const trackUiMetric = getTrackUiMetric(); + const { stateParams, setValue, vis, aggs } = props; + + const hasLineChart = stateParams.seriesParams.some( + ({ type, data: { id: paramId } }) => + (type === ChartType.Line || type === ChartType.Area) && + aggs.aggs.find(({ id }) => id === paramId)?.enabled + ); + + return ( + <> + { + if (trackUiMetric) { + trackUiMetric(METRIC_TYPE.CLICK, 'detailed_tooltip_switched'); + } + setValue(paramName, value); + }} + /> + + {hasLineChart && ( + { + if (trackUiMetric) { + trackUiMetric(METRIC_TYPE.CLICK, 'fitting_function_selected'); + } + setValue(paramName, value); + }} + /> + )} + + ); +} diff --git a/src/plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx similarity index 59% rename from src/plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx index 0126dce37c9f2..9efc9b65b19ee 100644 --- a/src/plugins/vis_type_vislib/public/components/options/point_series/grid_panel.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx @@ -16,25 +16,36 @@ * specific language governing permissions and limitations * under the License. */ + import React, { useMemo, useEffect, useCallback } from 'react'; -import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; -import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { SelectOption, SwitchOption } from '../../../../../charts/public'; -import { BasicVislibParams, ValueAxis } from '../../../types'; +import { SelectOption, SwitchOption } from '../../../../../../vis_default_editor/public'; +import { VisParams, ValueAxis } from '../../../../types'; +import { ValidationVisOptionsProps } from '../../common'; -function GridPanel({ stateParams, setValue, hasHistogramAgg }: VisOptionsProps) { +type GridPanelOptions = ValidationVisOptionsProps< + VisParams, + { + showElasticChartsOptions: boolean; + } +>; + +function GridPanel({ stateParams, setValue, hasHistogramAgg, extraProps }: GridPanelOptions) { const setGrid = useCallback( - ( - paramName: T, - value: BasicVislibParams['grid'][T] - ) => setValue('grid', { ...stateParams.grid, [paramName]: value }), + (paramName: T, value: VisParams['grid'][T]) => + setValue('grid', { ...stateParams.grid, [paramName]: value }), [stateParams.grid, setValue] ); + const disableCategoryGridLines = useMemo( + () => !extraProps?.showElasticChartsOptions && hasHistogramAgg, + [extraProps?.showElasticChartsOptions, hasHistogramAgg] + ); + const options = useMemo( () => [ ...stateParams.valueAxes.map(({ id, name }: ValueAxis) => ({ @@ -42,7 +53,7 @@ function GridPanel({ stateParams, setValue, hasHistogramAgg }: VisOptionsProps { - if (hasHistogramAgg) { + if (disableCategoryGridLines) { setGrid('categoryLines', false); } - }, [hasHistogramAgg, setGrid]); + }, [disableCategoryGridLines, setGrid]); return (

@@ -71,19 +82,16 @@ function GridPanel({ stateParams, setValue, hasHistogramAgg }: VisOptionsProps
diff --git a/src/plugins/vis_type_vislib/public/components/options/point_series/index.ts b/src/plugins/vis_type_xy/public/editor/components/options/point_series/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/components/options/point_series/index.ts rename to src/plugins/vis_type_xy/public/editor/components/options/point_series/index.ts diff --git a/src/plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx similarity index 63% rename from src/plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx index 18073d2218877..1d00f80e0b0d7 100644 --- a/src/plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx @@ -16,25 +16,41 @@ * specific language governing permissions and limitations * under the License. */ + import React, { useMemo } from 'react'; import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { uniq } from 'lodash'; -import { ValidationVisOptionsProps } from '../../common'; -import { BasicOptions, SwitchOption } from '../../../../../charts/public'; +import { BasicOptions, SwitchOption } from '../../../../../../vis_default_editor/public'; +import { BUCKET_TYPES } from '../../../../../../data/public'; + +import { VisParams } from '../../../../types'; import { GridPanel } from './grid_panel'; import { ThresholdPanel } from './threshold_panel'; -import { BasicVislibParams } from '../../../types'; -import { ChartTypes } from '../../../utils/collections'; - -function PointSeriesOptions(props: ValidationVisOptionsProps) { - const { stateParams, setValue, vis } = props; +import { ChartType } from '../../../../../common'; +import { ValidationVisOptionsProps } from '../../common'; +import { ElasticChartsOptions } from './elastic_charts_options'; - const currentChartTypes = useMemo(() => uniq(stateParams.seriesParams.map(({ type }) => type)), [ - stateParams.seriesParams, - ]); +export function PointSeriesOptions( + props: ValidationVisOptionsProps< + VisParams, + { + // TODO: Remove when vis_type_vislib is removed + // https://github.com/elastic/kibana/issues/56143 + showElasticChartsOptions: boolean; + } + > +) { + const { stateParams, setValue, vis, aggs } = props; + const hasBarChart = useMemo( + () => + stateParams.seriesParams.some( + ({ type, data: { id: paramId } }) => + type === ChartType.Histogram && aggs.aggs.find(({ id }) => id === paramId)?.enabled + ), + [stateParams.seriesParams, aggs.aggs] + ); return ( <> @@ -42,7 +58,7 @@ function PointSeriesOptions(props: ValidationVisOptionsProps)

@@ -52,10 +68,11 @@ function PointSeriesOptions(props: ValidationVisOptionsProps) {vis.data.aggs!.aggs.some( - (agg) => agg.schema === 'segment' && agg.type.name === 'date_histogram' + (agg) => agg.schema === 'segment' && agg.type.name === BUCKET_TYPES.DATE_HISTOGRAM ) ? ( ) /> ) : ( ) /> )} - {currentChartTypes.includes(ChartTypes.HISTOGRAM) && ( + {hasBarChart && ( ) } /> )} + + {props.extraProps?.showElasticChartsOptions && } @@ -98,5 +118,3 @@ function PointSeriesOptions(props: ValidationVisOptionsProps) ); } - -export { PointSeriesOptions }; diff --git a/src/plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx similarity index 77% rename from src/plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx rename to src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx index 964bb7d569b08..8eab0c478e67b 100644 --- a/src/plugins/vis_type_vislib/public/components/options/point_series/threshold_panel.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx @@ -17,39 +17,40 @@ * under the License. */ import React, { useCallback } from 'react'; -import { EuiPanel, EuiTitle, EuiColorPicker, EuiFormRow, EuiSpacer } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPanel, EuiTitle, EuiColorPicker, EuiFormRow, EuiSpacer } from '@elastic/eui'; -import { ValidationVisOptionsProps } from '../../common'; import { SelectOption, SwitchOption, RequiredNumberInputOption, -} from '../../../../../charts/public'; -import { BasicVislibParams } from '../../../types'; +} from '../../../../../../vis_default_editor/public'; +import { ValidationVisOptionsProps } from '../../common'; +import { VisParams } from '../../../../types'; function ThresholdPanel({ stateParams, setValue, setMultipleValidity, vis, -}: ValidationVisOptionsProps) { +}: ValidationVisOptionsProps) { const setThresholdLine = useCallback( - ( + ( paramName: T, - value: BasicVislibParams['thresholdLine'][T] + value: VisParams['thresholdLine'][T] ) => setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value }), [stateParams.thresholdLine, setValue] ); const setThresholdLineColor = useCallback( - (value: BasicVislibParams['thresholdLine']['color']) => setThresholdLine('color', value), + (value: VisParams['thresholdLine']['color']) => setThresholdLine('color', value), [setThresholdLine] ); const setThresholdLineValidity = useCallback( - (paramName: keyof BasicVislibParams['thresholdLine'], isValid: boolean) => + (paramName: keyof VisParams['thresholdLine'], isValid: boolean) => setMultipleValidity(`thresholdLine__${paramName}`, isValid), [setMultipleValidity] ); @@ -59,7 +60,7 @@ function ThresholdPanel({

@@ -67,7 +68,7 @@ function ThresholdPanel({ import('./components/data_view')); +import { i18n } from '@kbn/i18n'; +import { Position } from '@elastic/charts'; -export const getDataViewDescription = (): InspectorViewDescription => ({ - title: i18n.translate('inspector.data.dataTitle', { - defaultMessage: 'Data', - }), - order: 10, - help: i18n.translate('inspector.data.dataDescriptionTooltip', { - defaultMessage: 'View the data behind the visualization', - }), - shouldShow(adapters: Adapters) { - return Boolean(adapters.data); +export const getPositions = () => [ + { + text: i18n.translate('visTypeXy.legendPositions.topText', { + defaultMessage: 'Top', + }), + value: Position.Top, + }, + { + text: i18n.translate('visTypeXy.legendPositions.leftText', { + defaultMessage: 'Left', + }), + value: Position.Left, + }, + { + text: i18n.translate('visTypeXy.legendPositions.rightText', { + defaultMessage: 'Right', + }), + value: Position.Right, + }, + { + text: i18n.translate('visTypeXy.legendPositions.bottomText', { + defaultMessage: 'Bottom', + }), + value: Position.Bottom, }, - component: DataViewComponent, -}); +]; diff --git a/src/plugins/ui_actions/public/triggers/select_range_trigger.ts b/src/plugins/vis_type_xy/public/editor/scale_types.ts similarity index 62% rename from src/plugins/ui_actions/public/triggers/select_range_trigger.ts rename to src/plugins/vis_type_xy/public/editor/scale_types.ts index 312e75314bd92..c115b04ead5fd 100644 --- a/src/plugins/ui_actions/public/triggers/select_range_trigger.ts +++ b/src/plugins/vis_type_xy/public/editor/scale_types.ts @@ -18,15 +18,26 @@ */ import { i18n } from '@kbn/i18n'; -import { Trigger } from '.'; -export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; -export const selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'> = { - id: SELECT_RANGE_TRIGGER, - title: i18n.translate('uiActions.triggers.selectRangeTitle', { - defaultMessage: 'Range selection', - }), - description: i18n.translate('uiActions.triggers.selectRangeDescription', { - defaultMessage: 'A range of values on the visualization', - }), -}; +import { ScaleType } from '../types'; + +export const getScaleTypes = () => [ + { + text: i18n.translate('visTypeXy.scaleTypes.linearText', { + defaultMessage: 'Linear', + }), + value: ScaleType.Linear, + }, + { + text: i18n.translate('visTypeXy.scaleTypes.logText', { + defaultMessage: 'Log', + }), + value: ScaleType.Log, + }, + { + text: i18n.translate('visTypeXy.scaleTypes.squareRootText', { + defaultMessage: 'Square root', + }), + value: ScaleType.SquareRoot, + }, +]; diff --git a/src/plugins/vis_type_xy/public/index.ts b/src/plugins/vis_type_xy/public/index.ts index 9af75ce9059e9..0739ad77a245b 100644 --- a/src/plugins/vis_type_xy/public/index.ts +++ b/src/plugins/vis_type_xy/public/index.ts @@ -17,11 +17,35 @@ * under the License. */ -import { PluginInitializerContext } from '../../../core/public'; import { VisTypeXyPlugin as Plugin } from './plugin'; export { VisTypeXyPluginSetup } from './plugin'; -export function plugin(initializerContext: PluginInitializerContext) { - return new Plugin(initializerContext); +// TODO: Remove when vis_type_vislib is removed +// https://github.com/elastic/kibana/issues/56143 +export { + CategoryAxis, + ThresholdLine, + ValueAxis, + Grid, + SeriesParam, + Dimension, + Dimensions, + ScaleType, + AxisType, + HistogramParams, + DateHistogramParams, +} from './types'; +export type { ValidationVisOptionsProps } from './editor/components/common/validation_wrapper'; +export { TruncateLabelsOption } from './editor/components/common/truncate_labels'; +export { getPositions } from './editor/positions'; +export { getScaleTypes } from './editor/scale_types'; +export { xyVisTypes } from './vis_types'; +export { getAggId } from './config/get_agg_id'; + +// Export common types +export * from '../common'; + +export function plugin() { + return new Plugin(); } diff --git a/src/plugins/vis_type_xy/public/plugin.ts b/src/plugins/vis_type_xy/public/plugin.ts index 667018c1e6e30..ab22ae57ebbdf 100644 --- a/src/plugins/vis_type_xy/public/plugin.ts +++ b/src/plugins/vis_type_xy/public/plugin.ts @@ -17,71 +17,84 @@ * under the License. */ -import { - CoreSetup, - CoreStart, - Plugin, - IUiSettingsClient, - PluginInitializerContext, -} from 'kibana/public'; - +import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; import { VisualizationsSetup, VisualizationsStart } from '../../visualizations/public'; import { ChartsPluginSetup } from '../../charts/public'; +import { DataPublicPluginStart } from '../../data/public'; +import { UsageCollectionSetup } from '../../usage_collection/public'; -export interface VisTypeXyDependencies { - uiSettings: IUiSettingsClient; - charts: ChartsPluginSetup; -} +import { createVisTypeXyVisFn } from './xy_vis_fn'; +import { + setDataActions, + setFormatService, + setThemeService, + setColorsService, + setTimefilter, + setUISettings, + setDocLinks, + setTrackUiMetric, +} from './services'; +import { visTypesDefinitions } from './vis_types'; +import { LEGACY_CHARTS_LIBRARY } from '../common'; +import { xyVisRenderer } from './vis_renderer'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface VisTypeXyPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisTypeXyPluginStart {} /** @internal */ export interface VisTypeXyPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; charts: ChartsPluginSetup; + usageCollection: UsageCollectionSetup; } /** @internal */ export interface VisTypeXyPluginStartDependencies { expressions: ReturnType; visualizations: VisualizationsStart; + data: DataPublicPluginStart; } -type VisTypeXyCoreSetup = CoreSetup; +type VisTypeXyCoreSetup = CoreSetup; /** @internal */ -export class VisTypeXyPlugin implements Plugin { - constructor(public initializerContext: PluginInitializerContext) {} - +export class VisTypeXyPlugin + implements + Plugin< + VisTypeXyPluginSetup, + VisTypeXyPluginStart, + VisTypeXyPluginSetupDependencies, + VisTypeXyPluginStartDependencies + > { public async setup( core: VisTypeXyCoreSetup, - { expressions, visualizations, charts }: VisTypeXyPluginSetupDependencies + { expressions, visualizations, charts, usageCollection }: VisTypeXyPluginSetupDependencies ) { - // eslint-disable-next-line no-console - console.warn( - 'The visTypeXy plugin is enabled\n\n', - 'This may negatively alter existing vislib visualization configurations if saved.' - ); - const visualizationDependencies: Readonly = { - uiSettings: core.uiSettings, - charts, - }; + if (!core.uiSettings.get(LEGACY_CHARTS_LIBRARY, false)) { + setUISettings(core.uiSettings); + setThemeService(charts.theme); + setColorsService(charts.legacyColors); - const visTypeDefinitions: any[] = []; - const visFunctions: any = []; + [createVisTypeXyVisFn].forEach(expressions.registerFunction); + expressions.registerRenderer(xyVisRenderer); + visTypesDefinitions.forEach(visualizations.createBaseVisualization); + } - visFunctions.forEach((fn: any) => expressions.registerFunction(fn)); - visTypeDefinitions.forEach((vis: any) => - visualizations.createBaseVisualization(vis(visualizationDependencies)) - ); + setTrackUiMetric(usageCollection?.reportUiCounter.bind(usageCollection, 'vis_type_xy')); return {}; } - public start(core: CoreStart, deps: VisTypeXyPluginStartDependencies) { - // nothing to do here + public start(core: CoreStart, { data }: VisTypeXyPluginStartDependencies) { + setFormatService(data.fieldFormats); + setDataActions(data.actions); + setTimefilter(data.query.timefilter.timefilter); + setDocLinks(core.docLinks); + + return {}; } } diff --git a/src/plugins/vis_type_xy/public/services.ts b/src/plugins/vis_type_xy/public/services.ts new file mode 100644 index 0000000000000..086cab8fb217a --- /dev/null +++ b/src/plugins/vis_type_xy/public/services.ts @@ -0,0 +1,54 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { UiCounterMetricType } from '@kbn/analytics'; +import { CoreSetup, DocLinksStart } from '../../../core/public'; +import { createGetterSetter } from '../../kibana_utils/public'; +import { DataPublicPluginStart } from '../../data/public'; +import { ChartsPluginSetup } from '../../charts/public'; + +export const [getUISettings, setUISettings] = createGetterSetter( + 'xy core.uiSettings' +); + +export const [getDataActions, setDataActions] = createGetterSetter< + DataPublicPluginStart['actions'] +>('xy data.actions'); + +export const [getFormatService, setFormatService] = createGetterSetter< + DataPublicPluginStart['fieldFormats'] +>('xy data.fieldFormats'); + +export const [getTimefilter, setTimefilter] = createGetterSetter< + DataPublicPluginStart['query']['timefilter']['timefilter'] +>('xy data.query.timefilter.timefilter'); + +export const [getThemeService, setThemeService] = createGetterSetter( + 'xy charts.theme' +); + +export const [getColorsService, setColorsService] = createGetterSetter< + ChartsPluginSetup['legacyColors'] +>('xy charts.color'); + +export const [getDocLinks, setDocLinks] = createGetterSetter('DocLinks'); + +export const [getTrackUiMetric, setTrackUiMetric] = createGetterSetter< + (metricType: UiCounterMetricType, eventName: string | string[]) => void +>('trackUiMetric'); diff --git a/src/plugins/vis_type_xy/public/to_ast.test.ts b/src/plugins/vis_type_xy/public/to_ast.test.ts new file mode 100644 index 0000000000000..678a9faaec585 --- /dev/null +++ b/src/plugins/vis_type_xy/public/to_ast.test.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Vis } from '../../visualizations/public'; +import { buildExpression } from '../../expressions/public'; +import { sampleAreaVis } from '../../vis_type_vislib/public/sample_vis.test.mocks'; + +import { toExpressionAst } from './to_ast'; +import { VisParams } from './types'; + +jest.mock('../../expressions/public', () => ({ + ...(jest.requireActual('../../expressions/public') as any), + buildExpression: jest.fn().mockImplementation(() => ({ + toAst: () => ({ + type: 'expression', + chain: [], + }), + })), +})); + +jest.mock('./to_ast_esaggs', () => ({ + getEsaggsFn: jest.fn(), +})); + +describe('xy vis toExpressionAst function', () => { + let vis: Vis; + + const params = { + timefilter: {}, + timeRange: {}, + abortSignal: {}, + } as any; + + beforeEach(() => { + vis = sampleAreaVis as any; + }); + + it('should match basic snapshot', () => { + toExpressionAst(vis, params); + const [, builtExpression] = (buildExpression as jest.Mock).mock.calls[0][0]; + + expect(builtExpression).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts new file mode 100644 index 0000000000000..c93dbe46dca0e --- /dev/null +++ b/src/plugins/vis_type_xy/public/to_ast.ts @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; + +import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { BUCKET_TYPES } from '../../data/public'; + +import { DateHistogramParams, Dimensions, HistogramParams, VisParams } from './types'; +import { visName, VisTypeXyExpressionFunctionDefinition } from './xy_vis_fn'; +import { XyVisType } from '../common'; +import { getEsaggsFn } from './to_ast_esaggs'; + +export const toExpressionAst: VisToExpressionAst = async (vis, params) => { + const schemas = getVisSchemas(vis, params); + const dimensions: Dimensions = { + x: schemas.segment ? schemas.segment[0] : null, + y: schemas.metric, + z: schemas.radius, + width: schemas.width, + series: schemas.group, + splitRow: schemas.split_row, + splitColumn: schemas.split_column, + }; + + const responseAggs = vis.data.aggs?.getResponseAggs().filter(({ enabled }) => enabled) ?? []; + + if (dimensions.x) { + const xAgg = responseAggs[dimensions.x.accessor] as any; + if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { + (dimensions.x.params as DateHistogramParams).date = true; + const { esUnit, esValue } = xAgg.buckets.getInterval(); + (dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit; + (dimensions.x.params as DateHistogramParams).intervalESValue = esValue; + (dimensions.x.params as DateHistogramParams).interval = moment + .duration(esValue, esUnit) + .asMilliseconds(); + (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat(); + } else if (xAgg.type.name === BUCKET_TYPES.HISTOGRAM) { + const intervalParam = xAgg.type.paramByName('interval'); + const output = { params: {} as any }; + await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { + abortSignal: params.abortSignal, + }); + intervalParam.write(xAgg, output); + (dimensions.x.params as HistogramParams).interval = output.params.interval; + } + } + + const visConfig = { ...vis.params }; + + (dimensions.y || []).forEach((yDimension) => { + const yAgg = responseAggs[yDimension.accessor]; + const seriesParam = (visConfig.seriesParams || []).find( + (param: any) => param.data.id === yAgg.id + ); + if (seriesParam) { + const usedValueAxis = (visConfig.valueAxes || []).find( + (valueAxis: any) => valueAxis.id === seriesParam.valueAxis + ); + if (usedValueAxis?.scale.mode === 'percentage') { + yDimension.format = { id: 'percent' }; + } + } + }); + + visConfig.dimensions = dimensions; + + const visTypeXy = buildExpressionFunction(visName, { + type: vis.type.name as XyVisType, + visConfig: JSON.stringify(visConfig), + }); + + const ast = buildExpression([getEsaggsFn(vis), visTypeXy]); + + return ast.toAst(); +}; diff --git a/src/plugins/vis_type_xy/public/to_ast_esaggs.ts b/src/plugins/vis_type_xy/public/to_ast_esaggs.ts new file mode 100644 index 0000000000000..da8d11ac8340c --- /dev/null +++ b/src/plugins/vis_type_xy/public/to_ast_esaggs.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Vis } from '../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { + EsaggsExpressionFunctionDefinition, + IndexPatternLoadExpressionFunctionDefinition, +} from '../../data/public'; + +import { VisParams } from './types'; + +/** + * Get esaggs expressions function + * TODO: replace this with vis.data.aggs!.toExpressionAst(); + * https://github.com/elastic/kibana/issues/61768 + * @param vis + */ +export function getEsaggsFn(vis: Vis) { + return buildExpressionFunction('esaggs', { + index: buildExpression([ + buildExpressionFunction('indexPatternLoad', { + id: vis.data.indexPattern!.id!, + }), + ]), + metricsAtAllLevels: vis.isHierarchical(), + partialRows: false, + aggs: vis.data.aggs!.aggs.map((agg) => buildExpression(agg.toExpressionAst())), + }); +} diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_type_xy/public/types/config.ts new file mode 100644 index 0000000000000..ec73c0f6e3fc0 --- /dev/null +++ b/src/plugins/vis_type_xy/public/types/config.ts @@ -0,0 +1,130 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + AxisSpec, + CustomTooltip, + Fit, + GridLineStyle, + Position, + Rotation, + SeriesScales, + TickFormatter, + TooltipProps, + TooltipValueFormatter, + YDomainRange, +} from '@elastic/charts'; + +import { Dimension, Scale, ThresholdLine } from './param'; + +export interface Column { + id: string | null; + name: string; +} + +export interface Aspect { + accessor: Column['id']; + aggType: string | null; + aggId: string | null; + column?: Dimension['accessor']; + title: Column['name']; + format?: Dimension['format']; + formatter?: TickFormatter; + params: Dimension['params']; +} + +export interface Aspects { + x: Aspect; + y: Aspect[]; + z?: Aspect; + series?: Aspect[]; +} + +export interface AxisGrid { + show?: boolean; + styles?: GridLineStyle; +} + +export interface TickOptions { + show?: boolean; + size?: number; + count?: number; + padding?: number; + formatter?: TickFormatter; + labelFormatter?: TickFormatter; + rotation?: number; + showDuplicates?: boolean; + integersOnly?: boolean; + showOverlappingTicks?: boolean; + showOverlappingLabels?: boolean; +} + +export type YScaleType = SeriesScales['yScaleType']; +export type XScaleType = SeriesScales['xScaleType']; + +export type ScaleConfig = Omit & { + type?: S; +}; + +export interface AxisConfig { + id: string; + groupId?: string; + position: Position; + ticks?: TickOptions; + show: boolean; + style: AxisSpec['style']; + scale: ScaleConfig; + domain?: YDomainRange; + title?: string; + grid?: AxisGrid; + integersOnly: boolean; +} + +export interface LegendOptions { + show: boolean; + position?: Position; +} + +export type ThresholdLineConfig = Omit & { + dash?: number[]; + groupId?: string; +}; + +export type TooltipConfig = Omit & { + detailedTooltip?: (headerFormatter?: TooltipValueFormatter) => CustomTooltip; +}; + +export interface VisConfig { + legend: LegendOptions; + tooltip: TooltipConfig; + xAxis: AxisConfig; + yAxes: Array>; + aspects: Aspects; + rotation: Rotation; + thresholdLine: ThresholdLineConfig; + orderBucketsBySum?: boolean; + showCurrentTime: boolean; + isTimeChart: boolean; + markSizeRatio: number; + showValueLabel: boolean; + enableHistogramMode: boolean; + fittingFunction?: Exclude; + detailedTooltip?: boolean; + isVislibVis?: boolean; +} diff --git a/src/plugins/vis_type_xy/public/types/constants.ts b/src/plugins/vis_type_xy/public/types/constants.ts new file mode 100644 index 0000000000000..f92c56e43413e --- /dev/null +++ b/src/plugins/vis_type_xy/public/types/constants.ts @@ -0,0 +1,67 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { $Values } from '@kbn/utility-types'; + +export const ChartMode = Object.freeze({ + Normal: 'normal' as const, + Stacked: 'stacked' as const, +}); +export type ChartMode = $Values; + +export const InterpolationMode = Object.freeze({ + Linear: 'linear' as const, + Cardinal: 'cardinal' as const, + StepAfter: 'step-after' as const, +}); +export type InterpolationMode = $Values; + +export const AxisType = Object.freeze({ + Category: 'category' as const, + Value: 'value' as const, +}); +export type AxisType = $Values; + +export const ScaleType = Object.freeze({ + Linear: 'linear' as const, + Log: 'log' as const, + SquareRoot: 'square root' as const, +}); +export type ScaleType = $Values; + +export const AxisMode = Object.freeze({ + Normal: 'normal' as const, + Percentage: 'percentage' as const, + Wiggle: 'wiggle' as const, + Silhouette: 'silhouette' as const, +}); +export type AxisMode = $Values; + +export const ThresholdLineStyle = Object.freeze({ + Full: 'full' as const, + Dashed: 'dashed' as const, + DotDashed: 'dot-dashed' as const, +}); +export type ThresholdLineStyle = $Values; + +export const ColorMode = Object.freeze({ + Background: 'Background' as const, + Labels: 'Labels' as const, + None: 'None' as const, +}); +export type ColorMode = $Values; diff --git a/src/plugins/vis_type_xy/public/types/index.ts b/src/plugins/vis_type_xy/public/types/index.ts new file mode 100644 index 0000000000000..791373def2018 --- /dev/null +++ b/src/plugins/vis_type_xy/public/types/index.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './constants'; +export * from './config'; +export * from './param'; +export * from './vis_type'; diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts new file mode 100644 index 0000000000000..c8cd020dec03c --- /dev/null +++ b/src/plugins/vis_type_xy/public/types/param.ts @@ -0,0 +1,160 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Fit, Position } from '@elastic/charts'; + +import { Style, Labels } from '../../../charts/public'; +import { SchemaConfig } from '../../../visualizations/public'; + +import { ChartType } from '../../common'; +import { + ChartMode, + AxisMode, + AxisType, + InterpolationMode, + ScaleType, + ThresholdLineStyle, +} from './constants'; + +export interface Scale { + boundsMargin?: number | ''; + defaultYExtents?: boolean; + max?: number | null; + min?: number | null; + mode?: AxisMode; + setYExtents?: boolean; + type: ScaleType; +} + +export interface CategoryAxis { + id: string; + labels: Labels; + position: Position; + scale: Scale; + show: boolean; + title: { + text?: string; + }; + type: AxisType; + /** + * Used only for heatmap, here for consistent types when used in vis_type_vislib + * + * remove with vis_type_vislib + * https://github.com/elastic/kibana/issues/56143 + */ + style: Partial