diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index 5d7ba22841aa..217645b90381 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -70,6 +70,7 @@ yarn kbn watch-bazel - @kbn/apm-utils - @kbn/babel-code-parser - @kbn/babel-preset +- @kbn/cli-dev-mode - @kbn/config - @kbn/config-schema - @kbn/crypto @@ -87,6 +88,7 @@ yarn kbn watch-bazel - @kbn/mapbox-gl - @kbn/monaco - @kbn/optimizer +- @kbn/plugin-helpers - @kbn/rule-data-utils - @kbn/securitysolution-es-utils - @kbn/securitysolution-hook-utils diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 853180ec816e..66a23ee189ae 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -482,6 +482,9 @@ of buckets to try to represent. [[visualization-visualize-chartslibrary]]`visualization:visualize:legacyChartsLibrary`:: Enables the legacy charts library for aggregation-based area, line, and bar charts in *Visualize*. +[[visualization-visualize-pieChartslibrary]]`visualization:visualize:legacyPieChartsLibrary`:: +Enables the legacy charts library for aggregation-based pie charts in *Visualize*. + [[visualization-colormapping]]`visualization:colorMapping`:: **This setting is deprecated and will not be supported as of 8.0.** Maps values to specific colors in charts using the *Compatibility* palette. diff --git a/package.json b/package.json index f99eb86a43ce..ecedb64c343e 100644 --- a/package.json +++ b/package.json @@ -109,10 +109,10 @@ "@elastic/maki": "6.3.0", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", - "@elastic/react-search-ui": "^1.5.1", + "@elastic/react-search-ui": "^1.6.0", "@elastic/request-crypto": "1.1.4", "@elastic/safer-lodash-set": "link:bazel-bin/packages/elastic-safer-lodash-set", - "@elastic/search-ui-app-search-connector": "^1.5.0", + "@elastic/search-ui-app-search-connector": "^1.6.0", "@elastic/ui-ace": "0.2.3", "@hapi/accept": "^5.0.2", "@hapi/boom": "^9.1.1", @@ -457,7 +457,7 @@ "@jest/reporters": "^26.6.2", "@kbn/babel-code-parser": "link:bazel-bin/packages/kbn-babel-code-parser", "@kbn/babel-preset": "link:bazel-bin/packages/kbn-babel-preset", - "@kbn/cli-dev-mode": "link:packages/kbn-cli-dev-mode", + "@kbn/cli-dev-mode": "link:bazel-bin/packages/kbn-cli-dev-mode", "@kbn/dev-utils": "link:bazel-bin/packages/kbn-dev-utils", "@kbn/docs-utils": "link:bazel-bin/packages/kbn-docs-utils", "@kbn/es": "link:bazel-bin/packages/kbn-es", @@ -467,7 +467,7 @@ "@kbn/expect": "link:bazel-bin/packages/kbn-expect", "@kbn/optimizer": "link:bazel-bin/packages/kbn-optimizer", "@kbn/plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator", - "@kbn/plugin-helpers": "link:packages/kbn-plugin-helpers", + "@kbn/plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers", "@kbn/pm": "link:packages/kbn-pm", "@kbn/storybook": "link:bazel-bin/packages/kbn-storybook", "@kbn/telemetry-tools": "link:bazel-bin/packages/kbn-telemetry-tools", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index d9e2f0e1f998..1094a2def3e7 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -12,6 +12,7 @@ filegroup( "//packages/kbn-apm-utils:build", "//packages/kbn-babel-code-parser:build", "//packages/kbn-babel-preset:build", + "//packages/kbn-cli-dev-mode:build", "//packages/kbn-common-utils:build", "//packages/kbn-config:build", "//packages/kbn-config-schema:build", @@ -31,6 +32,7 @@ filegroup( "//packages/kbn-monaco:build", "//packages/kbn-optimizer:build", "//packages/kbn-plugin-generator:build", + "//packages/kbn-plugin-helpers:build", "//packages/kbn-rule-data-utils:build", "//packages/kbn-securitysolution-list-constants:build", "//packages/kbn-securitysolution-io-ts-types:build", diff --git a/packages/kbn-cli-dev-mode/BUILD.bazel b/packages/kbn-cli-dev-mode/BUILD.bazel new file mode 100644 index 000000000000..ab1b6601f429 --- /dev/null +++ b/packages/kbn-cli-dev-mode/BUILD.bazel @@ -0,0 +1,103 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") + +PKG_BASE_NAME = "kbn-cli-dev-mode" +PKG_REQUIRE_NAME = "@kbn/cli-dev-mode" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = ["**/*.test.*"], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md" +] + +SRC_DEPS = [ + "//packages/kbn-config", + "//packages/kbn-config-schema", + "//packages/kbn-dev-utils", + "//packages/kbn-logging", + "//packages/kbn-optimizer", + "//packages/kbn-server-http-tools", + "//packages/kbn-std", + "//packages/kbn-utils", + "@npm//@hapi/h2o2", + "@npm//@hapi/hapi", + "@npm//argsplit", + "@npm//chokidar", + "@npm//elastic-apm-node", + "@npm//execa", + "@npm//getopts", + "@npm//lodash", + "@npm//moment", + "@npm//rxjs", + "@npm//supertest", +] + +TYPES_DEPS = [ + "@npm//@types/hapi__h2o2", + "@npm//@types/hapi__hapi", + "@npm//@types/getopts", + "@npm//@types/jest", + "@npm//@types/lodash", + "@npm//@types/node", + "@npm//@types/supertest", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_map = True, + incremental = True, + out_dir = "target", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json index cf6fcfd88a26..ac86ee2ef369 100644 --- a/packages/kbn-cli-dev-mode/package.json +++ b/packages/kbn-cli-dev-mode/package.json @@ -5,11 +5,6 @@ "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", "private": true, - "scripts": { - "build": "../../node_modules/.bin/tsc", - "kbn:bootstrap": "yarn build", - "kbn:watch": "yarn build --watch" - }, "kibana": { "devOnly": true } diff --git a/packages/kbn-cli-dev-mode/tsconfig.json b/packages/kbn-cli-dev-mode/tsconfig.json index 4436d27dbff8..0c71ad8e245d 100644 --- a/packages/kbn-cli-dev-mode/tsconfig.json +++ b/packages/kbn-cli-dev-mode/tsconfig.json @@ -1,10 +1,11 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "incremental": false, + "incremental": true, "outDir": "./target", "declaration": true, "declarationMap": true, + "rootDir": "./src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-cli-dev-mode/src", "types": [ diff --git a/packages/kbn-interpreter/BUILD.bazel b/packages/kbn-interpreter/BUILD.bazel index 4492faabfdf8..c29faf65638c 100644 --- a/packages/kbn-interpreter/BUILD.bazel +++ b/packages/kbn-interpreter/BUILD.bazel @@ -1,5 +1,5 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@npm//pegjs:index.bzl", "pegjs") +load("@npm//peggy:index.bzl", "peggy") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") PKG_BASE_NAME = "kbn-interpreter" @@ -37,10 +37,10 @@ TYPES_DEPS = [ DEPS = SRC_DEPS + TYPES_DEPS -pegjs( +peggy( name = "grammar", data = [ - ":grammar/grammar.pegjs" + ":grammar/grammar.peggy" ], output_dir = True, args = [ @@ -48,7 +48,7 @@ pegjs( "expression,argument", "-o", "$(@D)/index.js", - "./%s/grammar/grammar.pegjs" % package_name() + "./%s/grammar/grammar.peggy" % package_name() ], ) diff --git a/packages/kbn-interpreter/grammar/grammar.pegjs b/packages/kbn-interpreter/grammar/grammar.peggy similarity index 100% rename from packages/kbn-interpreter/grammar/grammar.pegjs rename to packages/kbn-interpreter/grammar/grammar.peggy diff --git a/packages/kbn-plugin-helpers/BUILD.bazel b/packages/kbn-plugin-helpers/BUILD.bazel new file mode 100644 index 000000000000..1a1f3453f768 --- /dev/null +++ b/packages/kbn-plugin-helpers/BUILD.bazel @@ -0,0 +1,97 @@ + +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") + +PKG_BASE_NAME = "kbn-plugin-helpers" +PKG_REQUIRE_NAME = "@kbn/plugin-helpers" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md" +] + +SRC_DEPS = [ + "//packages/kbn-dev-utils", + "//packages/kbn-optimizer", + "//packages/kbn-utils", + "@npm//del", + "@npm//execa", + "@npm//extract-zip", + "@npm//globby", + "@npm//gulp-zip", + "@npm//inquirer", + "@npm//load-json-file", + "@npm//vinyl-fs", +] + +TYPES_DEPS = [ + "@npm//@types/extract-zip", + "@npm//@types/gulp-zip", + "@npm//@types/inquirer", + "@npm//@types/jest", + "@npm//@types/node", + "@npm//@types/vinyl-fs", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_map = True, + incremental = True, + out_dir = "target", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 36a37075191a..1f4df52a0330 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -11,9 +11,5 @@ "types": "target/index.d.ts", "bin": { "plugin-helpers": "bin/plugin-helpers.js" - }, - "scripts": { - "kbn:bootstrap": "rm -rf target && ../../node_modules/.bin/tsc", - "kbn:watch": "../../node_modules/.bin/tsc --watch" } } \ No newline at end of file diff --git a/packages/kbn-plugin-helpers/tsconfig.json b/packages/kbn-plugin-helpers/tsconfig.json index 87d11843f398..4348f1e1a751 100644 --- a/packages/kbn-plugin-helpers/tsconfig.json +++ b/packages/kbn-plugin-helpers/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "incremental": false, + "incremental": true, "outDir": "target", "target": "ES2018", "declaration": true, diff --git a/src/plugins/data/common/field_formats/converters/string.ts b/src/plugins/data/common/field_formats/converters/string.ts index ec92d7591052..64367df5d90d 100644 --- a/src/plugins/data/common/field_formats/converters/string.ts +++ b/src/plugins/data/common/field_formats/converters/string.ts @@ -13,6 +13,10 @@ import { FieldFormat } from '../field_format'; import { TextContextTypeConvert, FIELD_FORMAT_IDS } from '../types'; import { shortenDottedString } from '../../utils'; +export const emptyLabel = i18n.translate('data.fieldFormats.string.emptyLabel', { + defaultMessage: '(empty)', +}); + const TRANSFORM_OPTIONS = [ { kind: false, @@ -103,6 +107,9 @@ export class StringFormat extends FieldFormat { } textConvert: TextContextTypeConvert = (val) => { + if (val === '') { + return emptyLabel; + } switch (this.param('transform')) { case 'lower': return String(val).toLowerCase(); diff --git a/src/plugins/data/config.ts b/src/plugins/data/config.ts index 9306b64019bb..1b7bfbc09ad1 100644 --- a/src/plugins/data/config.ts +++ b/src/plugins/data/config.ts @@ -44,10 +44,20 @@ export const searchSessionsConfigSchema = schema.object({ */ pageSize: schema.number({ defaultValue: 100 }), /** - * trackingInterval controls how often we track search session objects progress + * trackingInterval controls how often we track persisted search session objects progress */ trackingInterval: schema.duration({ defaultValue: '10s' }), + /** + * cleanupInterval controls how often we track non-persisted search session objects for cleanup + */ + cleanupInterval: schema.duration({ defaultValue: '60s' }), + + /** + * expireInterval controls how often we track persisted search session objects for expiration + */ + expireInterval: schema.duration({ defaultValue: '60m' }), + /** * monitoringTaskTimeout controls for how long task manager waits for search session monitoring task to complete before considering it timed out, * If tasks timeouts it receives cancel signal and next task starts in "trackingInterval" time diff --git a/src/plugins/data/public/search/session/session_service.test.ts b/src/plugins/data/public/search/session/session_service.test.ts index 39680c494836..7f388a29cd45 100644 --- a/src/plugins/data/public/search/session/session_service.test.ts +++ b/src/plugins/data/public/search/session/session_service.test.ts @@ -98,6 +98,14 @@ describe('Session service', () => { expect(nowProvider.reset).toHaveBeenCalled(); }); + it("Can clear other apps' session", async () => { + sessionService.start(); + expect(sessionService.getSessionId()).not.toBeUndefined(); + currentAppId$.next('change'); + sessionService.clear(); + expect(sessionService.getSessionId()).toBeUndefined(); + }); + it("Can start a new session in case there is other apps' stale session", async () => { const s1 = sessionService.start(); expect(sessionService.getSessionId()).not.toBeUndefined(); diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index a6b79a9e2c00..ff637b668661 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -396,6 +396,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'visualization:visualize:legacyPieChartsLibrary': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'doc_table:legacy': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 8448b359ce60..b59abc3aa715 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -26,6 +26,7 @@ export interface UsageStats { 'autocomplete:useTimeRange': boolean; 'search:timeout': number; 'visualization:visualize:legacyChartsLibrary': boolean; + 'visualization:visualize:legacyPieChartsLibrary': boolean; 'doc_table:legacy': boolean; 'discover:modifyColumnsOnSwitch': boolean; 'discover:searchFieldsFromSource': boolean; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 99c6dcb40e57..496335a3b0dc 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -8594,6 +8594,12 @@ "description": "Non-default value of setting." } }, + "visualization:visualize:legacyPieChartsLibrary": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "doc_table:legacy": { "type": "boolean", "_meta": { diff --git a/src/plugins/vis_type_pie/common/index.ts b/src/plugins/vis_type_pie/common/index.ts index 1aa1680530b3..a02a2b2ba10f 100644 --- a/src/plugins/vis_type_pie/common/index.ts +++ b/src/plugins/vis_type_pie/common/index.ts @@ -7,3 +7,4 @@ */ export const DEFAULT_PERCENT_DECIMALS = 2; +export const LEGACY_PIE_CHARTS_LIBRARY = 'visualization:visualize:legacyPieChartsLibrary'; diff --git a/src/plugins/vis_type_pie/kibana.json b/src/plugins/vis_type_pie/kibana.json index ee312fd19e8d..eebefc42681b 100644 --- a/src/plugins/vis_type_pie/kibana.json +++ b/src/plugins/vis_type_pie/kibana.json @@ -2,8 +2,10 @@ "id": "visTypePie", "version": "kibana", "ui": true, + "server": true, "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection"], "requiredBundles": ["visDefaultEditor"], + "extraPublicDirs": ["common/index"], "owner": { "name": "Kibana App", "githubTeam": "kibana-app" diff --git a/src/plugins/vis_type_pie/public/plugin.ts b/src/plugins/vis_type_pie/public/plugin.ts index 440a3a75a2eb..787f49c19aca 100644 --- a/src/plugins/vis_type_pie/public/plugin.ts +++ b/src/plugins/vis_type_pie/public/plugin.ts @@ -12,7 +12,7 @@ import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; import { ChartsPluginSetup } from '../../charts/public'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { DataPublicPluginStart } from '../../data/public'; -import { LEGACY_CHARTS_LIBRARY } from '../../visualizations/common/constants'; +import { LEGACY_PIE_CHARTS_LIBRARY } from '../common'; import { pieLabels as pieLabelsExpressionFunction } from './expression_functions/pie_labels'; import { createPieVisFn } from './pie_fn'; import { getPieVisRenderer } from './pie_renderer'; @@ -43,7 +43,7 @@ export class VisTypePiePlugin { core: CoreSetup, { expressions, visualizations, charts, usageCollection }: VisTypePieSetupDependencies ) { - if (!core.uiSettings.get(LEGACY_CHARTS_LIBRARY, false)) { + if (!core.uiSettings.get(LEGACY_PIE_CHARTS_LIBRARY, false)) { const getStartDeps = async () => { const [coreStart, deps] = await core.getStartServices(); return { diff --git a/src/plugins/vis_type_pie/public/utils/get_layers.ts b/src/plugins/vis_type_pie/public/utils/get_layers.ts index 27dcf2d37981..5a82871bf368 100644 --- a/src/plugins/vis_type_pie/public/utils/get_layers.ts +++ b/src/plugins/vis_type_pie/public/utils/get_layers.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { i18n } from '@kbn/i18n'; import { Datum, PartitionFillLabel, @@ -125,11 +124,6 @@ export const getLayers = ( }, showAccessor: (d: Datum) => d !== EMPTY_SLICE, nodeLabel: (d: unknown) => { - if (d === '') { - return i18n.translate('visTypePie.emptyLabelValue', { - defaultMessage: '(empty)', - }); - } if (col.format) { const formattedLabel = formatter.deserialize(col.format).convert(d) ?? ''; if (visParams.labels.truncate && formattedLabel.length <= visParams.labels.truncate) { diff --git a/src/plugins/vis_type_pie/server/index.ts b/src/plugins/vis_type_pie/server/index.ts new file mode 100644 index 000000000000..201071fbb5fc --- /dev/null +++ b/src/plugins/vis_type_pie/server/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { VisTypePieServerPlugin } from './plugin'; + +export const plugin = () => new VisTypePieServerPlugin(); diff --git a/src/plugins/vis_type_pie/server/plugin.ts b/src/plugins/vis_type_pie/server/plugin.ts new file mode 100644 index 000000000000..48576bdff5d3 --- /dev/null +++ b/src/plugins/vis_type_pie/server/plugin.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; + +import { CoreSetup, Plugin, UiSettingsParams } from 'kibana/server'; + +import { LEGACY_PIE_CHARTS_LIBRARY } from '../common'; + +export const getUiSettingsConfig: () => Record> = () => ({ + // TODO: Remove this when vis_type_vislib is removed + // https://github.com/elastic/kibana/issues/56143 + [LEGACY_PIE_CHARTS_LIBRARY]: { + name: i18n.translate('visTypePie.advancedSettings.visualization.legacyPieChartsLibrary.name', { + defaultMessage: 'Pie legacy charts library', + }), + requiresPageReload: true, + value: false, + description: i18n.translate( + 'visTypePie.advancedSettings.visualization.legacyPieChartsLibrary.description', + { + defaultMessage: 'Enables legacy charts library for pie charts in visualize.', + } + ), + deprecation: { + message: i18n.translate( + 'visTypePie.advancedSettings.visualization.legacyPieChartsLibrary.deprecation', + { + defaultMessage: + 'The legacy charts library for pie in visualize is deprecated and will not be supported as of 8.0.', + } + ), + docLinksKey: 'visualizationSettings', + }, + category: ['visualization'], + schema: schema.boolean(), + }, +}); + +export class VisTypePieServerPlugin implements Plugin { + public setup(core: CoreSetup) { + core.uiSettings.register(getUiSettingsConfig()); + + return {}; + } + + public start() { + return {}; + } +} diff --git a/src/plugins/vis_type_vislib/public/plugin.ts b/src/plugins/vis_type_vislib/public/plugin.ts index 52faf8a74778..cdc02aacafa3 100644 --- a/src/plugins/vis_type_vislib/public/plugin.ts +++ b/src/plugins/vis_type_vislib/public/plugin.ts @@ -13,7 +13,8 @@ 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 '../../visualizations/common/constants'; +import { LEGACY_CHARTS_LIBRARY } from '../../vis_type_xy/common/index'; +import { LEGACY_PIE_CHARTS_LIBRARY } from '../../vis_type_pie/common/index'; import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn'; import { createPieVisFn } from './pie_fn'; @@ -50,17 +51,18 @@ export class VisTypeVislibPlugin core: VisTypeVislibCoreSetup, { expressions, visualizations, charts }: VisTypeVislibPluginSetupDependencies ) { - if (!core.uiSettings.get(LEGACY_CHARTS_LIBRARY, false)) { - // Register only non-replaced vis types - convertedTypeDefinitions.forEach(visualizations.createBaseVisualization); - expressions.registerRenderer(getVislibVisRenderer(core, charts)); - expressions.registerFunction(createVisTypeVislibVisFn()); - } else { - // Register all vis types - visLibVisTypeDefinitions.forEach(visualizations.createBaseVisualization); + const typeDefinitions = !core.uiSettings.get(LEGACY_CHARTS_LIBRARY, false) + ? convertedTypeDefinitions + : visLibVisTypeDefinitions; + // register vislib XY axis charts + typeDefinitions.forEach(visualizations.createBaseVisualization); + expressions.registerRenderer(getVislibVisRenderer(core, charts)); + expressions.registerFunction(createVisTypeVislibVisFn()); + + if (core.uiSettings.get(LEGACY_PIE_CHARTS_LIBRARY, false)) { + // register vislib pie chart visualizations.createBaseVisualization(pieVisTypeDefinition); - expressions.registerRenderer(getVislibVisRenderer(core, charts)); - [createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction); + expressions.registerFunction(createPieVisFn()); } } diff --git a/src/plugins/vis_type_xy/common/index.ts b/src/plugins/vis_type_xy/common/index.ts index f17bc8476d9a..a80946f7c62f 100644 --- a/src/plugins/vis_type_xy/common/index.ts +++ b/src/plugins/vis_type_xy/common/index.ts @@ -19,3 +19,5 @@ export enum ChartType { * 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/kibana.json b/src/plugins/vis_type_xy/kibana.json index 1d7fd6a0813b..c25f035fb6d4 100644 --- a/src/plugins/vis_type_xy/kibana.json +++ b/src/plugins/vis_type_xy/kibana.json @@ -2,8 +2,10 @@ "id": "visTypeXy", "version": "kibana", "ui": true, + "server": true, "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection"], "requiredBundles": ["kibanaUtils", "visDefaultEditor"], + "extraPublicDirs": ["common/index"], "owner": { "name": "Kibana App", "githubTeam": "kibana-app" diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx index c9ed82fcf58e..fb6b4bb41d9b 100644 --- a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx @@ -19,7 +19,6 @@ import { import { Aspects } from '../types'; import './_detailed_tooltip.scss'; -import { fillEmptyValue } from '../utils/get_series_name_fn'; import { COMPLEX_SPLIT_ACCESSOR, isRangeAggType } from '../utils/accessors'; interface TooltipData { @@ -100,8 +99,7 @@ export const getTooltipData = ( return data; }; -const renderData = ({ label, value: rawValue }: TooltipData, index: number) => { - const value = fillEmptyValue(rawValue); +const renderData = ({ label, value }: TooltipData, index: number) => { return label && value ? ( diff --git a/src/plugins/vis_type_xy/public/components/xy_settings.tsx b/src/plugins/vis_type_xy/public/components/xy_settings.tsx index 8922f512522a..8d6a7eecdfe5 100644 --- a/src/plugins/vis_type_xy/public/components/xy_settings.tsx +++ b/src/plugins/vis_type_xy/public/components/xy_settings.tsx @@ -29,7 +29,6 @@ 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 { @@ -134,7 +133,7 @@ export const XYSettings: FC = ({ }; const headerValueFormatter: TickFormatter | undefined = xAxis.ticks?.formatter - ? (value) => fillEmptyValue(xAxis.ticks?.formatter?.(value)) ?? '' + ? (value) => xAxis.ticks?.formatter?.(value) ?? '' : undefined; const headerFormatter = isTimeChart && xDomain && adjustedXDomain diff --git a/src/plugins/vis_type_xy/public/config/get_axis.ts b/src/plugins/vis_type_xy/public/config/get_axis.ts index 08b17c882eea..71d33cc20d05 100644 --- a/src/plugins/vis_type_xy/public/config/get_axis.ts +++ b/src/plugins/vis_type_xy/public/config/get_axis.ts @@ -27,7 +27,6 @@ import { YScaleType, SeriesParam, } from '../types'; -import { fillEmptyValue } from '../utils/get_series_name_fn'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, @@ -90,8 +89,7 @@ function getLabelFormatter( } return (value: any) => { - const formattedStringValue = `${formatter ? formatter(value) : value}`; - const finalValue = fillEmptyValue(formattedStringValue); + const finalValue = `${formatter ? formatter(value) : value}`; if (finalValue.length > truncate) { return `${finalValue.slice(0, truncate)}...`; diff --git a/src/plugins/vis_type_xy/public/plugin.ts b/src/plugins/vis_type_xy/public/plugin.ts index e8d53127765b..b595d3172f14 100644 --- a/src/plugins/vis_type_xy/public/plugin.ts +++ b/src/plugins/vis_type_xy/public/plugin.ts @@ -23,7 +23,7 @@ import { } from './services'; import { visTypesDefinitions } from './vis_types'; -import { LEGACY_CHARTS_LIBRARY } from '../../visualizations/common/constants'; +import { LEGACY_CHARTS_LIBRARY } from '../common/'; import { xyVisRenderer } from './vis_renderer'; import * as expressionFunctions from './expression_functions'; diff --git a/src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts b/src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts index 0e54650e22f7..137f8a555801 100644 --- a/src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts +++ b/src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts @@ -8,21 +8,10 @@ import { memoize } from 'lodash'; -import { i18n } from '@kbn/i18n'; import { XYChartSeriesIdentifier, SeriesName } from '@elastic/charts'; import { VisConfig } from '../types'; -const emptyTextLabel = i18n.translate('visTypeXy.emptyTextColumnValue', { - defaultMessage: '(empty)', -}); - -/** - * Returns empty values - */ -export const fillEmptyValue = (value: T) => - value === '' ? emptyTextLabel : value; - function getSplitValues( splitAccessors: XYChartSeriesIdentifier['splitAccessors'], seriesAspects?: VisConfig['aspects']['series'] @@ -36,7 +25,7 @@ function getSplitValues( const split = (seriesAspects ?? []).find(({ accessor }) => accessor === key); splitValues.push(split?.formatter ? split?.formatter(value) : value); }); - return splitValues.map(fillEmptyValue); + return splitValues; } export const getSeriesNameFn = (aspects: VisConfig['aspects'], multipleY = false) => diff --git a/src/plugins/vis_type_xy/server/index.ts b/src/plugins/vis_type_xy/server/index.ts new file mode 100644 index 000000000000..a27ac49c0ea4 --- /dev/null +++ b/src/plugins/vis_type_xy/server/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { VisTypeXyServerPlugin } from './plugin'; + +export const plugin = () => new VisTypeXyServerPlugin(); diff --git a/src/plugins/vis_type_xy/server/plugin.ts b/src/plugins/vis_type_xy/server/plugin.ts new file mode 100644 index 000000000000..46d6531204c2 --- /dev/null +++ b/src/plugins/vis_type_xy/server/plugin.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; + +import { CoreSetup, Plugin, UiSettingsParams } from 'kibana/server'; + +import { LEGACY_CHARTS_LIBRARY } from '../common'; + +export const getUiSettingsConfig: () => Record> = () => ({ + // TODO: Remove this when vis_type_vislib is removed + // https://github.com/elastic/kibana/issues/56143 + [LEGACY_CHARTS_LIBRARY]: { + name: i18n.translate('visTypeXy.advancedSettings.visualization.legacyChartsLibrary.name', { + defaultMessage: 'XY axis legacy charts library', + }), + requiresPageReload: true, + value: false, + description: i18n.translate( + 'visTypeXy.advancedSettings.visualization.legacyChartsLibrary.description', + { + defaultMessage: 'Enables legacy charts library for area, line and bar charts in visualize.', + } + ), + deprecation: { + message: i18n.translate( + 'visTypeXy.advancedSettings.visualization.legacyChartsLibrary.deprecation', + { + defaultMessage: + 'The legacy charts library for area, line and bar charts in visualize is deprecated and will not be supported as of 7.16.', + } + ), + docLinksKey: 'visualizationSettings', + }, + category: ['visualization'], + schema: schema.boolean(), + }, +}); + +export class VisTypeXyServerPlugin implements Plugin { + public setup(core: CoreSetup) { + core.uiSettings.register(getUiSettingsConfig()); + + return {}; + } + + public start() { + return {}; + } +} diff --git a/src/plugins/visualizations/common/constants.ts b/src/plugins/visualizations/common/constants.ts index a33e74b498a2..a8a0963ac894 100644 --- a/src/plugins/visualizations/common/constants.ts +++ b/src/plugins/visualizations/common/constants.ts @@ -7,4 +7,3 @@ */ export const VISUALIZE_ENABLE_LABS_SETTING = 'visualize:enableLabs'; -export const LEGACY_CHARTS_LIBRARY = 'visualization:visualize:legacyChartsLibrary'; diff --git a/src/plugins/visualizations/server/plugin.ts b/src/plugins/visualizations/server/plugin.ts index 1fec63f2bb45..5a5a80b2689d 100644 --- a/src/plugins/visualizations/server/plugin.ts +++ b/src/plugins/visualizations/server/plugin.ts @@ -18,7 +18,7 @@ import { Logger, } from '../../../core/server'; -import { VISUALIZE_ENABLE_LABS_SETTING, LEGACY_CHARTS_LIBRARY } from '../common/constants'; +import { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants'; import { visualizationSavedObjectType } from './saved_objects'; @@ -58,27 +58,6 @@ export class VisualizationsPlugin category: ['visualization'], schema: schema.boolean(), }, - // TODO: Remove this when vis_type_vislib is removed - // https://github.com/elastic/kibana/issues/56143 - [LEGACY_CHARTS_LIBRARY]: { - name: i18n.translate( - 'visualizations.advancedSettings.visualization.legacyChartsLibrary.name', - { - defaultMessage: 'Legacy charts library', - } - ), - requiresPageReload: true, - value: false, - description: i18n.translate( - 'visualizations.advancedSettings.visualization.legacyChartsLibrary.description', - { - defaultMessage: - 'Enables legacy charts library for area, line, bar, pie charts in visualize.', - } - ), - category: ['visualization'], - schema: schema.boolean(), - }, }); if (plugins.usageCollection) { diff --git a/test/functional/apps/context/index.js b/test/functional/apps/context/index.js index 7612dae338d9..031171a58718 100644 --- a/test/functional/apps/context/index.js +++ b/test/functional/apps/context/index.js @@ -15,16 +15,18 @@ export default function ({ getService, getPageObjects, loadTestFile }) { describe('context app', function () { this.tags('ciGroup1'); - before(async function () { + before(async () => { await browser.setWindowSize(1200, 800); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await esArchiver.load('test/functional/fixtures/es_archiver/visualize'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); await PageObjects.common.navigateToApp('discover'); }); - after(function unloadMakelogs() { - return esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + after(async () => { + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); }); loadTestFile(require.resolve('./_context_navigation')); diff --git a/test/functional/apps/dashboard/dashboard_state.ts b/test/functional/apps/dashboard/dashboard_state.ts index 047681e1a8ac..6c259f5a71ef 100644 --- a/test/functional/apps/dashboard/dashboard_state.ts +++ b/test/functional/apps/dashboard/dashboard_state.ts @@ -53,6 +53,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { if (isNewChartsLibraryEnabled) { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': false, + 'visualization:visualize:legacyPieChartsLibrary': false, }); await browser.refresh(); } diff --git a/test/functional/apps/dashboard/index.ts b/test/functional/apps/dashboard/index.ts index 4b83b2ac92de..e4dc04282e4a 100644 --- a/test/functional/apps/dashboard/index.ts +++ b/test/functional/apps/dashboard/index.ts @@ -123,6 +123,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await loadLogstash(); await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': false, + 'visualization:visualize:legacyPieChartsLibrary': false, }); await browser.refresh(); }); @@ -131,6 +132,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await unloadLogstash(); await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': true, + 'visualization:visualize:legacyPieChartsLibrary': true, }); await browser.refresh(); }); diff --git a/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts b/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts index e986429a15d2..264885490cdf 100644 --- a/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts +++ b/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts @@ -12,26 +12,31 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); - const log = getService('log'); + const security = getService('security'); const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'timePicker', 'discover']); describe('index pattern with unmapped fields', () => { before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/unmapped_fields'); + await security.testUser.setRoles(['kibana_admin', 'test-index-unmapped-fields']); + const fromTime = 'Jan 20, 2021 @ 00:00:00.000'; + const toTime = 'Jan 25, 2021 @ 00:00:00.000'; + await kibanaServer.uiSettings.replace({ defaultIndex: 'test-index-unmapped-fields', 'discover:searchFieldsFromSource': false, + 'timepicker:timeDefaults': `{ "from": "${fromTime}", "to": "${toTime}"}`, }); - log.debug('discover'); - const fromTime = 'Jan 20, 2021 @ 00:00:00.000'; - const toTime = 'Jan 25, 2021 @ 00:00:00.000'; + await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); }); after(async () => { await esArchiver.unload('test/functional/fixtures/es_archiver/unmapped_fields'); + await kibanaServer.uiSettings.unset('defaultIndex'); + await kibanaServer.uiSettings.unset('discover:searchFieldsFromSource'); + await kibanaServer.uiSettings.unset('timepicker:timeDefaults'); }); it('unmapped fields exist on a new saved search', async () => { diff --git a/test/functional/apps/discover/_sidebar.ts b/test/functional/apps/discover/_sidebar.ts index 8179f4e44e8b..d8701261126c 100644 --- a/test/functional/apps/discover/_sidebar.ts +++ b/test/functional/apps/discover/_sidebar.ts @@ -14,8 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'discover', 'timePicker']); const testSubjects = getService('testSubjects'); - // Failing: See https://github.com/elastic/kibana/issues/101449 - describe.skip('discover sidebar', function describeIndexTests() { + describe('discover sidebar', function describeIndexTests() { before(async function () { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/discover'); diff --git a/test/functional/apps/discover/_source_filters.ts b/test/functional/apps/discover/_source_filters.ts index f3793dc3e028..6c6979b39702 100644 --- a/test/functional/apps/discover/_source_filters.ts +++ b/test/functional/apps/discover/_source_filters.ts @@ -23,8 +23,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }); - log.debug('load kibana index with default index pattern'); - await esArchiver.load('test/functional/fixtures/es_archiver/visualize_source-filters'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); // and load a set of makelogs data await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); @@ -43,6 +42,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.sleep(1000); }); + after(async () => { + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); + }); + it('should not get the field referer', async function () { const fieldNames = await PageObjects.discover.getAllFieldNames(); expect(fieldNames).to.not.contain('referer'); diff --git a/test/functional/apps/getting_started/_shakespeare.ts b/test/functional/apps/getting_started/_shakespeare.ts index 945c1fdcbdcf..ae6841b85c98 100644 --- a/test/functional/apps/getting_started/_shakespeare.ts +++ b/test/functional/apps/getting_started/_shakespeare.ts @@ -57,6 +57,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { if (isNewChartsLibraryEnabled) { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': false, + 'visualization:visualize:legacyPieChartsLibrary': false, }); await browser.refresh(); } diff --git a/test/functional/apps/getting_started/index.ts b/test/functional/apps/getting_started/index.ts index b75a30037d06..4c1c052ef15a 100644 --- a/test/functional/apps/getting_started/index.ts +++ b/test/functional/apps/getting_started/index.ts @@ -24,6 +24,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { before(async () => { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': false, + 'visualization:visualize:legacyPieChartsLibrary': false, }); await browser.refresh(); }); @@ -31,6 +32,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { after(async () => { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': true, + 'visualization:visualize:legacyPieChartsLibrary': true, }); await browser.refresh(); }); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index cecd206abd1d..bc6160eba384 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -31,6 +31,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { before(async () => { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': false, + 'visualization:visualize:legacyPieChartsLibrary': false, }); await browser.refresh(); }); @@ -38,6 +39,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { after(async () => { await kibanaServer.uiSettings.update({ 'visualization:visualize:legacyChartsLibrary': true, + 'visualization:visualize:legacyPieChartsLibrary': true, }); await browser.refresh(); }); diff --git a/test/functional/config.js b/test/functional/config.js index bab1148cf372..670488003e56 100644 --- a/test/functional/config.js +++ b/test/functional/config.js @@ -58,6 +58,7 @@ export default async function ({ readConfigFile }) { 'accessibility:disableAnimations': true, 'dateFormat:tz': 'UTC', 'visualization:visualize:legacyChartsLibrary': true, + 'visualization:visualize:legacyPieChartsLibrary': true, }, }, @@ -292,6 +293,21 @@ export default async function ({ readConfigFile }) { kibana: [], }, + 'test-index-unmapped-fields': { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['test-index-unmapped-fields'], + privileges: ['read', 'view_index_metadata'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + animals: { elasticsearch: { cluster: [], diff --git a/test/functional/fixtures/es_archiver/visualize/data.json b/test/functional/fixtures/es_archiver/visualize/data.json deleted file mode 100644 index d48aa3e98d18..000000000000 --- a/test/functional/fixtures/es_archiver/visualize/data.json +++ /dev/null @@ -1,388 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "index-pattern:logstash-*", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "index-pattern": { - "fieldAttrs": "{\"utc_time\":{\"customLabel\":\"UTC time\"}}", - "fieldFormatMap": "{\"bytes\":{\"id\":\"bytes\"}}", - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "timeFieldName": "@timestamp", - "title": "logstash-*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern" - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:logstash*", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "index-pattern": { - "fieldFormatMap": "{\"bytes\":{\"id\":\"bytes\"}}", - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "title": "logstash*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern" - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:long-window-logstash-*", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "index-pattern": { - "fieldFormatMap": "{\"bytes\":{\"id\":\"bytes\"}}", - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "timeFieldName": "@timestamp", - "title": "long-window-logstash-*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern" - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Shared-Item-Visualization-AreaChart", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "visualization": { - "description": "AreaChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "Shared-Item Visualization AreaChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization-AreaChart", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "visualization": { - "description": "AreaChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "Visualization AreaChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"Visualization AreaChart\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":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\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"labels\":{},\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"now-15m\",\"to\":\"now\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:68305470-87bc-11e9-a991-3b492a7c3e09", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "control_0_index_pattern", - "type": "index-pattern" - }, - { - "id": "logstash-*", - "name": "control_1_index_pattern", - "type": "index-pattern" - } - ], - "type": "visualization", - "updated_at": "2019-06-05T18:04:48.310Z", - "visualization": { - "description": "", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "title": "chained input control", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"chained input control\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559757816862\",\"fieldName\":\"geo.src\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1559757836347\",\"fieldName\":\"clientip\",\"parent\":\"1559757816862\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:64983230-87bf-11e9-a991-3b492a7c3e09", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "control_0_index_pattern", - "type": "index-pattern" - } - ], - "type": "visualization", - "updated_at": "2019-06-05T18:26:10.771Z", - "visualization": { - "description": "", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "title": "dynamic options input control", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"dynamic options input control\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559759127876\",\"fieldName\":\"geo.src\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:5d2de430-87c0-11e9-a991-3b492a7c3e09", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "control_0_index_pattern", - "type": "index-pattern" - }, - { - "id": "logstash-*", - "name": "control_1_index_pattern", - "type": "index-pattern" - } - ], - "type": "visualization", - "updated_at": "2019-06-05T18:33:07.827Z", - "visualization": { - "description": "", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "title": "chained input control with dynamic options", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"chained input control with dynamic options\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559759550755\",\"fieldName\":\"machine.os.raw\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1559759557302\",\"fieldName\":\"geo.src\",\"parent\":\"1559759550755\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:test_index*", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "index-pattern": { - "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"message.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"message\"}}},{\"name\":\"user\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"user.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"user\"}}}]", - "title": "test_index*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern" - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:AreaChart-no-date-field", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "test_index*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "visualization": { - "description": "AreaChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "AreaChart [no date field]", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"AreaChart [no date field]\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"addTooltip\":true,\"addLegend\":true,\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:log*", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "index-pattern": { - "fieldFormatMap": "{\"bytes\":{\"id\":\"bytes\"}}", - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "title": "log*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern" - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:AreaChart-no-time-filter", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - { - "id": "log*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "visualization": { - "description": "AreaChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "AreaChart [no time filter]", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"AreaChart [no time filter]\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"addTooltip\":true,\"addLegend\":true,\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}" - } - }, - "type": "_doc" - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:VegaMap", - "index": ".kibana", - "source": { - "coreMigrationVersion": "7.14.0", - "migrationVersion": { - "visualization": "7.14.0" - }, - "references": [ - ], - "type": "visualization", - "visualization": { - "description": "VegaMap", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "title": "VegaMap", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"aggs\":[],\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega/v5.json\\n config: {\\n kibana: {type: \\\"map\\\", latitude: 25, longitude: -70, zoom: 3}\\n }\\n data: [\\n {\\n name: table\\n url: {\\n index: kibana_sample_data_flights\\n %context%: true\\n // Uncomment to enable time filtering\\n // %timefield%: timestamp\\n body: {\\n size: 0\\n aggs: {\\n origins: {\\n terms: {field: \\\"OriginAirportID\\\", size: 10000}\\n aggs: {\\n originLocation: {\\n top_hits: {\\n size: 1\\n _source: {\\n includes: [\\\"OriginLocation\\\", \\\"Origin\\\"]\\n }\\n }\\n }\\n distinations: {\\n terms: {field: \\\"DestAirportID\\\", size: 10000}\\n aggs: {\\n destLocation: {\\n top_hits: {\\n size: 1\\n _source: {\\n includes: [\\\"DestLocation\\\"]\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n format: {property: \\\"aggregations.origins.buckets\\\"}\\n transform: [\\n {\\n type: geopoint\\n projection: projection\\n fields: [\\n originLocation.hits.hits[0]._source.OriginLocation.lon\\n originLocation.hits.hits[0]._source.OriginLocation.lat\\n ]\\n }\\n ]\\n }\\n {\\n name: selectedDatum\\n on: [\\n {trigger: \\\"!selected\\\", remove: true}\\n {trigger: \\\"selected\\\", insert: \\\"selected\\\"}\\n ]\\n }\\n ]\\n signals: [\\n {\\n name: selected\\n value: null\\n on: [\\n {events: \\\"@airport:mouseover\\\", update: \\\"datum\\\"}\\n {events: \\\"@airport:mouseout\\\", update: \\\"null\\\"}\\n ]\\n }\\n ]\\n scales: [\\n {\\n name: airportSize\\n type: linear\\n domain: {data: \\\"table\\\", field: \\\"doc_count\\\"}\\n range: [\\n {signal: \\\"zoom*zoom*0.2+1\\\"}\\n {signal: \\\"zoom*zoom*10+1\\\"}\\n ]\\n }\\n ]\\n marks: [\\n {\\n type: group\\n from: {\\n facet: {\\n name: facetedDatum\\n data: selectedDatum\\n field: distinations.buckets\\n }\\n }\\n data: [\\n {\\n name: facetDatumElems\\n source: facetedDatum\\n transform: [\\n {\\n type: geopoint\\n projection: projection\\n fields: [\\n destLocation.hits.hits[0]._source.DestLocation.lon\\n destLocation.hits.hits[0]._source.DestLocation.lat\\n ]\\n }\\n {type: \\\"formula\\\", expr: \\\"{x:parent.x, y:parent.y}\\\", as: \\\"source\\\"}\\n {type: \\\"formula\\\", expr: \\\"{x:datum.x, y:datum.y}\\\", as: \\\"target\\\"}\\n {type: \\\"linkpath\\\", shape: \\\"diagonal\\\"}\\n ]\\n }\\n ]\\n scales: [\\n {\\n name: lineThickness\\n type: log\\n clamp: true\\n range: [1, 8]\\n }\\n {\\n name: lineOpacity\\n type: log\\n clamp: true\\n range: [0.2, 0.8]\\n }\\n ]\\n marks: [\\n {\\n from: {data: \\\"facetDatumElems\\\"}\\n type: path\\n interactive: false\\n encode: {\\n update: {\\n path: {field: \\\"path\\\"}\\n stroke: {value: \\\"black\\\"}\\n strokeWidth: {scale: \\\"lineThickness\\\", field: \\\"doc_count\\\"}\\n strokeOpacity: {scale: \\\"lineOpacity\\\", field: \\\"doc_count\\\"}\\n }\\n }\\n }\\n ]\\n }\\n {\\n name: airport\\n type: symbol\\n from: {data: \\\"table\\\"}\\n encode: {\\n update: {\\n size: {scale: \\\"airportSize\\\", field: \\\"doc_count\\\"}\\n xc: {signal: \\\"datum.x\\\"}\\n yc: {signal: \\\"datum.y\\\"}\\n tooltip: {\\n signal: \\\"{title: datum.originLocation.hits.hits[0]._source.Origin + ' (' + datum.key + ')', connnections: length(datum.distinations.buckets), flights: datum.doc_count}\\\"\\n }\\n }\\n }\\n }\\n ]\\n}\"},\"title\":\"[Flights] Airport Connections (Hover Over Airport)\",\"type\":\"vega\"}" - } - }, - "type": "_doc" - } -} \ No newline at end of file diff --git a/test/functional/fixtures/es_archiver/visualize/mappings.json b/test/functional/fixtures/es_archiver/visualize/mappings.json deleted file mode 100644 index d032352d9a68..000000000000 --- a/test/functional/fixtures/es_archiver/visualize/mappings.json +++ /dev/null @@ -1,487 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana_$KIBANA_PACKAGE_VERSION": {}, - ".kibana": {} - }, - "index": ".kibana_$KIBANA_PACKAGE_VERSION_001", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", - "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", - "config": "c63748b75f39d0c54de12d12c1ccbc20", - "core-usage-stats": "3d1b76c39bfb2cc8296b024d73854724", - "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", - "dashboard": "40554caf09725935e2c02e02563a2d07", - "index-pattern": "45915a1ad866812242df474eb0479052", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "legacy-url-alias": "6155300fd11a00e23d5cbaa39f0fce0a", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "db2c00e39b36f40930a3b9fc71c823e1", - "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-counter": "0d409297dc5ebe1e3a1da691c6ee32e3", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "usage-counters": "8cc260bdceffec4ffc3ad165c97dc1b4", - "visualization": "f819cf6636b75c9e76ba733a0c6ef355" - } - }, - "dynamic": "strict", - "properties": { - "application_usage_daily": { - "dynamic": "false", - "properties": { - "timestamp": { - "type": "date" - } - } - }, - "application_usage_totals": { - "dynamic": "false", - "type": "object" - }, - "application_usage_transactional": { - "dynamic": "false", - "type": "object" - }, - "config": { - "dynamic": "false", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "core-usage-stats": { - "dynamic": "false", - "type": "object" - }, - "coreMigrationVersion": { - "type": "keyword" - }, - "dashboard": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "optionsJSON": { - "index": false, - "type": "text" - }, - "panelsJSON": { - "index": false, - "type": "text" - }, - "refreshInterval": { - "properties": { - "display": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "pause": { - "doc_values": false, - "index": false, - "type": "boolean" - }, - "section": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "value": { - "doc_values": false, - "index": false, - "type": "integer" - } - } - }, - "timeFrom": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "timeRestore": { - "doc_values": false, - "index": false, - "type": "boolean" - }, - "timeTo": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "index-pattern": { - "dynamic": "false", - "properties": { - "title": { - "type": "text" - }, - "type": { - "type": "keyword" - } - } - }, - "kql-telemetry": { - "properties": { - "optInCount": { - "type": "long" - }, - "optOutCount": { - "type": "long" - } - } - }, - "legacy-url-alias": { - "dynamic": "false", - "properties": { - "disabled": { - "type": "boolean" - }, - "sourceId": { - "type": "keyword" - }, - "targetType": { - "type": "keyword" - } - } - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "index-pattern": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "visualization": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "originId": { - "type": "keyword" - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "sample-data-telemetry": { - "properties": { - "installCount": { - "type": "long" - }, - "unInstallCount": { - "type": "long" - } - } - }, - "search": { - "properties": { - "columns": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "description": { - "type": "text" - }, - "grid": { - "enabled": false, - "type": "object" - }, - "hideChart": { - "doc_values": false, - "index": false, - "type": "boolean" - }, - "hits": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "sort": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "search-telemetry": { - "dynamic": "false", - "type": "object" - }, - "server": { - "dynamic": "false", - "type": "object" - }, - "telemetry": { - "properties": { - "allowChangingOptInStatus": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "lastReported": { - "type": "date" - }, - "lastVersionChecked": { - "type": "keyword" - }, - "reportFailureCount": { - "type": "integer" - }, - "reportFailureVersion": { - "type": "keyword" - }, - "sendUsageFrom": { - "type": "keyword" - }, - "userHasSeenNotice": { - "type": "boolean" - } - } - }, - "timelion-sheet": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "timelion_chart_height": { - "type": "integer" - }, - "timelion_columns": { - "type": "integer" - }, - "timelion_interval": { - "type": "keyword" - }, - "timelion_other_interval": { - "type": "keyword" - }, - "timelion_rows": { - "type": "integer" - }, - "timelion_sheet": { - "type": "text" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "type": { - "type": "keyword" - }, - "ui-counter": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "ui-metric": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "updated_at": { - "type": "date" - }, - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "usage-counters": { - "dynamic": "false", - "properties": { - "domainId": { - "type": "keyword" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "savedSearchRefName": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "index": false, - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "index": false, - "type": "text" - } - } - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "10", - "refresh_interval": "1s", - "routing_partition_size": "1" - } - } - } -} \ No newline at end of file diff --git a/test/functional/fixtures/kbn_archiver/visualize.json b/test/functional/fixtures/kbn_archiver/visualize.json index 758841e8d81e..660da856964b 100644 --- a/test/functional/fixtures/kbn_archiver/visualize.json +++ b/test/functional/fixtures/kbn_archiver/visualize.json @@ -6,14 +6,14 @@ "timeFieldName": "@timestamp", "title": "logstash-*" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "logstash-*", "migrationVersion": { "index-pattern": "7.11.0" }, "references": [], "type": "index-pattern", - "version": "WzI2LDJd" + "version": "WzEzLDFd" } { @@ -27,10 +27,10 @@ "version": 1, "visState": "{\"title\":\"chained input control with dynamic options\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559759550755\",\"fieldName\":\"machine.os.raw\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1559759557302\",\"fieldName\":\"geo.src\",\"parent\":\"1559759550755\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "5d2de430-87c0-11e9-a991-3b492a7c3e09", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -46,7 +46,7 @@ ], "type": "visualization", "updated_at": "2019-06-05T18:33:07.827Z", - "version": "WzMzLDJd" + "version": "WzIwLDFd" } { @@ -60,10 +60,10 @@ "version": 1, "visState": "{\"title\":\"dynamic options input control\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559759127876\",\"fieldName\":\"geo.src\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "64983230-87bf-11e9-a991-3b492a7c3e09", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -74,7 +74,7 @@ ], "type": "visualization", "updated_at": "2019-06-05T18:26:10.771Z", - "version": "WzMyLDJd" + "version": "WzE5LDFd" } { @@ -88,10 +88,10 @@ "version": 1, "visState": "{\"title\":\"chained input control\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1559757816862\",\"fieldName\":\"geo.src\",\"parent\":\"\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1559757836347\",\"fieldName\":\"clientip\",\"parent\":\"1559757816862\",\"label\":\"\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "68305470-87bc-11e9-a991-3b492a7c3e09", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -107,7 +107,7 @@ ], "type": "visualization", "updated_at": "2019-06-05T18:04:48.310Z", - "version": "WzMxLDJd" + "version": "WzE4LDFd" } { @@ -115,10 +115,14 @@ "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"message.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"message\"}}},{\"name\":\"user\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"user.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"user\"}}}]", "title": "test_index*" }, + "coreMigrationVersion": "7.14.0", "id": "test_index*", + "migrationVersion": { + "index-pattern": "7.11.0" + }, "references": [], "type": "index-pattern", - "version": "WzI1LDJd" + "version": "WzIxLDFd" } { @@ -132,10 +136,10 @@ "version": 1, "visState": "{\"title\":\"AreaChart [no date field]\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"addTooltip\":true,\"addLegend\":true,\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "AreaChart-no-date-field", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -145,7 +149,7 @@ } ], "type": "visualization", - "version": "WzM0LDJd" + "version": "WzIyLDFd" } { @@ -154,14 +158,14 @@ "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", "title": "log*" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "log*", "migrationVersion": { "index-pattern": "7.11.0" }, "references": [], "type": "index-pattern", - "version": "WzM1LDJd" + "version": "WzIzLDFd" } { @@ -175,10 +179,10 @@ "version": 1, "visState": "{\"title\":\"AreaChart [no time filter]\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"addTooltip\":true,\"addLegend\":true,\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "AreaChart-no-time-filter", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -188,7 +192,7 @@ } ], "type": "visualization", - "version": "WzM2LDJd" + "version": "WzI0LDFd" } { @@ -202,10 +206,10 @@ "version": 1, "visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "Shared-Item-Visualization-AreaChart", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -215,7 +219,7 @@ } ], "type": "visualization", - "version": "WzI5LDJd" + "version": "WzE2LDFd" } { @@ -229,14 +233,14 @@ "version": 1, "visState": "{\"aggs\":[],\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega/v5.json\\n config: {\\n kibana: {type: \\\"map\\\", latitude: 25, longitude: -70, zoom: 3}\\n }\\n data: [\\n {\\n name: table\\n url: {\\n index: kibana_sample_data_flights\\n %context%: true\\n // Uncomment to enable time filtering\\n // %timefield%: timestamp\\n body: {\\n size: 0\\n aggs: {\\n origins: {\\n terms: {field: \\\"OriginAirportID\\\", size: 10000}\\n aggs: {\\n originLocation: {\\n top_hits: {\\n size: 1\\n _source: {\\n includes: [\\\"OriginLocation\\\", \\\"Origin\\\"]\\n }\\n }\\n }\\n distinations: {\\n terms: {field: \\\"DestAirportID\\\", size: 10000}\\n aggs: {\\n destLocation: {\\n top_hits: {\\n size: 1\\n _source: {\\n includes: [\\\"DestLocation\\\"]\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n format: {property: \\\"aggregations.origins.buckets\\\"}\\n transform: [\\n {\\n type: geopoint\\n projection: projection\\n fields: [\\n originLocation.hits.hits[0]._source.OriginLocation.lon\\n originLocation.hits.hits[0]._source.OriginLocation.lat\\n ]\\n }\\n ]\\n }\\n {\\n name: selectedDatum\\n on: [\\n {trigger: \\\"!selected\\\", remove: true}\\n {trigger: \\\"selected\\\", insert: \\\"selected\\\"}\\n ]\\n }\\n ]\\n signals: [\\n {\\n name: selected\\n value: null\\n on: [\\n {events: \\\"@airport:mouseover\\\", update: \\\"datum\\\"}\\n {events: \\\"@airport:mouseout\\\", update: \\\"null\\\"}\\n ]\\n }\\n ]\\n scales: [\\n {\\n name: airportSize\\n type: linear\\n domain: {data: \\\"table\\\", field: \\\"doc_count\\\"}\\n range: [\\n {signal: \\\"zoom*zoom*0.2+1\\\"}\\n {signal: \\\"zoom*zoom*10+1\\\"}\\n ]\\n }\\n ]\\n marks: [\\n {\\n type: group\\n from: {\\n facet: {\\n name: facetedDatum\\n data: selectedDatum\\n field: distinations.buckets\\n }\\n }\\n data: [\\n {\\n name: facetDatumElems\\n source: facetedDatum\\n transform: [\\n {\\n type: geopoint\\n projection: projection\\n fields: [\\n destLocation.hits.hits[0]._source.DestLocation.lon\\n destLocation.hits.hits[0]._source.DestLocation.lat\\n ]\\n }\\n {type: \\\"formula\\\", expr: \\\"{x:parent.x, y:parent.y}\\\", as: \\\"source\\\"}\\n {type: \\\"formula\\\", expr: \\\"{x:datum.x, y:datum.y}\\\", as: \\\"target\\\"}\\n {type: \\\"linkpath\\\", shape: \\\"diagonal\\\"}\\n ]\\n }\\n ]\\n scales: [\\n {\\n name: lineThickness\\n type: log\\n clamp: true\\n range: [1, 8]\\n }\\n {\\n name: lineOpacity\\n type: log\\n clamp: true\\n range: [0.2, 0.8]\\n }\\n ]\\n marks: [\\n {\\n from: {data: \\\"facetDatumElems\\\"}\\n type: path\\n interactive: false\\n encode: {\\n update: {\\n path: {field: \\\"path\\\"}\\n stroke: {value: \\\"black\\\"}\\n strokeWidth: {scale: \\\"lineThickness\\\", field: \\\"doc_count\\\"}\\n strokeOpacity: {scale: \\\"lineOpacity\\\", field: \\\"doc_count\\\"}\\n }\\n }\\n }\\n ]\\n }\\n {\\n name: airport\\n type: symbol\\n from: {data: \\\"table\\\"}\\n encode: {\\n update: {\\n size: {scale: \\\"airportSize\\\", field: \\\"doc_count\\\"}\\n xc: {signal: \\\"datum.x\\\"}\\n yc: {signal: \\\"datum.y\\\"}\\n tooltip: {\\n signal: \\\"{title: datum.originLocation.hits.hits[0]._source.Origin + ' (' + datum.key + ')', connnections: length(datum.distinations.buckets), flights: datum.doc_count}\\\"\\n }\\n }\\n }\\n }\\n ]\\n}\"},\"title\":\"[Flights] Airport Connections (Hover Over Airport)\",\"type\":\"vega\"}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "VegaMap", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [], "type": "visualization", - "version": "WzM3LDJd" + "version": "WzI1LDFd" } { @@ -250,10 +254,10 @@ "version": 1, "visState": "{\"title\":\"Visualization AreaChart\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":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\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"labels\":{},\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"now-15m\",\"to\":\"now\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}]}" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "Visualization-AreaChart", "migrationVersion": { - "visualization": "7.13.0" + "visualization": "7.14.0" }, "references": [ { @@ -263,7 +267,7 @@ } ], "type": "visualization", - "version": "WzMwLDJd" + "version": "WzE3LDFd" } { @@ -272,14 +276,14 @@ "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", "title": "logstash*" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "logstash*", "migrationVersion": { "index-pattern": "7.11.0" }, "references": [], "type": "index-pattern", - "version": "WzI3LDJd" + "version": "WzE0LDFd" } { @@ -289,12 +293,12 @@ "timeFieldName": "@timestamp", "title": "long-window-logstash-*" }, - "coreMigrationVersion": "8.0.0", + "coreMigrationVersion": "7.14.0", "id": "long-window-logstash-*", "migrationVersion": { "index-pattern": "7.11.0" }, "references": [], "type": "index-pattern", - "version": "WzI4LDJd" + "version": "WzE1LDFd" } \ No newline at end of file diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 65b899d2e2fb..dc3a04568316 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -448,7 +448,10 @@ export class DiscoverPageObject extends FtrService { public async closeSidebarFieldFilter() { await this.testSubjects.click('toggleFieldFilterButton'); - await this.testSubjects.missingOrFail('filterSelectionPanel'); + + await this.retry.waitFor('sidebar filter closed', async () => { + return !(await this.testSubjects.exists('filterSelectionPanel')); + }); } public async waitForChartLoadingComplete(renderCount: number) { diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts index c8587f4ffd34..64b8c363fa6c 100644 --- a/test/functional/page_objects/visualize_chart_page.ts +++ b/test/functional/page_objects/visualize_chart_page.ts @@ -37,7 +37,8 @@ export class VisualizeChartPageObject extends FtrService { public async isNewChartsLibraryEnabled(): Promise { const legacyChartsLibrary = Boolean( - await this.kibanaServer.uiSettings.get('visualization:visualize:legacyChartsLibrary') + (await this.kibanaServer.uiSettings.get('visualization:visualize:legacyChartsLibrary')) && + (await this.kibanaServer.uiSettings.get('visualization:visualize:legacyPieChartsLibrary')) ) ?? true; const enabled = !legacyChartsLibrary; this.log.debug(`-- isNewChartsLibraryEnabled = ${enabled}`); diff --git a/test/functional/page_objects/visualize_page.ts b/test/functional/page_objects/visualize_page.ts index a11a254509e7..e930406cdcce 100644 --- a/test/functional/page_objects/visualize_page.ts +++ b/test/functional/page_objects/visualize_page.ts @@ -57,6 +57,7 @@ export class VisualizePageObject extends FtrService { defaultIndex: 'logstash-*', [UI_SETTINGS.FORMAT_BYTES_DEFAULT_PATTERN]: '0,0.[000]b', 'visualization:visualize:legacyChartsLibrary': !isNewLibrary, + 'visualization:visualize:legacyPieChartsLibrary': !isNewLibrary, }); } diff --git a/test/interpreter_functional/test_suites/run_pipeline/index.ts b/test/interpreter_functional/test_suites/run_pipeline/index.ts index 9cf7e0deba2f..f8c37bab02b8 100644 --- a/test/interpreter_functional/test_suites/run_pipeline/index.ts +++ b/test/interpreter_functional/test_suites/run_pipeline/index.ts @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await esArchiver.load('test/functional/fixtures/es_archiver/visualize_embedding'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'Australia/North', defaultIndex: 'logstash-*', @@ -32,6 +32,12 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid await testSubjects.find('pluginContent'); }); + after(async () => { + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); + }); + loadTestFile(require.resolve('./basic')); loadTestFile(require.resolve('./tag_cloud')); loadTestFile(require.resolve('./metric')); diff --git a/test/plugin_functional/test_suites/custom_visualizations/index.js b/test/plugin_functional/test_suites/custom_visualizations/index.js index 0998b97da67f..22b0f21fb983 100644 --- a/test/plugin_functional/test_suites/custom_visualizations/index.js +++ b/test/plugin_functional/test_suites/custom_visualizations/index.js @@ -14,7 +14,7 @@ export default function ({ getService, loadTestFile }) { describe('custom visualizations', function () { before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/visualize'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'Australia/North', defaultIndex: 'logstash-*', @@ -22,6 +22,12 @@ export default function ({ getService, loadTestFile }) { await browser.setWindowSize(1300, 900); }); + after(async () => { + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); + }); + loadTestFile(require.resolve('./self_changing_vis')); }); } diff --git a/test/visual_regression/tests/vega/vega_map_visualization.ts b/test/visual_regression/tests/vega/vega_map_visualization.ts index 96b08467e4a8..d891e7f2bab6 100644 --- a/test/visual_regression/tests/vega/vega_map_visualization.ts +++ b/test/visual_regression/tests/vega/vega_map_visualization.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['common', 'visualize', 'visChart', 'visEditor', 'vegaChart']); const visualTesting = getService('visualTesting'); @@ -18,12 +19,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'test/functional/fixtures/es_archiver/kibana_sample_data_flights' ); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/visualize'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); }); after(async () => { await esArchiver.unload('test/functional/fixtures/es_archiver/kibana_sample_data_flights'); - await esArchiver.unload('test/functional/fixtures/es_archiver/visualize'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); }); it('should show map with vega layer', async function () { diff --git a/x-pack/package.json b/x-pack/package.json index 1397a3da8107..1af3d569e41a 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -26,7 +26,6 @@ "yarn": "^1.21.1" }, "devDependencies": { - "@kbn/plugin-helpers": "link:../packages/kbn-plugin-helpers", "@kbn/test": "link:../packages/kbn-test" } } \ No newline at end of file diff --git a/x-pack/plugins/canvas/CONTRIBUTING.md b/x-pack/plugins/canvas/CONTRIBUTING.md index d3bff6777124..d8a657ea73c4 100644 --- a/x-pack/plugins/canvas/CONTRIBUTING.md +++ b/x-pack/plugins/canvas/CONTRIBUTING.md @@ -36,8 +36,8 @@ To keep the code terse, Canvas uses i18n "dictionaries": abstracted, static sing ```js -// i18n/components.ts -export const ComponentStrings = { +// asset_manager.tsx +const strings = { // ... AssetManager: { getCopyAssetMessage: (id: string) => @@ -52,10 +52,6 @@ export const ComponentStrings = { // ... }; -// asset_manager.tsx -import { ComponentStrings } from '../../../i18n'; -const { AssetManager: strings } = ComponentStrings; - const text = ( {strings.getSpaceUsedText(percentageUsed)} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/advanced_filter/component/advanced_filter.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/advanced_filter/component/advanced_filter.tsx index 4dfb4c3f0927..b5c009abc276 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/advanced_filter/component/advanced_filter.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/advanced_filter/component/advanced_filter.tsx @@ -5,12 +5,22 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import PropTypes from 'prop-types'; import React, { FunctionComponent } from 'react'; -import { ComponentStrings } from '../../../../../i18n'; +import PropTypes from 'prop-types'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -const { AdvancedFilter: strings } = ComponentStrings; +const strings = { + getApplyButtonLabel: () => + i18n.translate('xpack.canvas.renderer.advancedFilter.applyButtonLabel', { + defaultMessage: 'Apply', + description: 'This refers to applying the filter to the Canvas workpad', + }), + getInputPlaceholder: () => + i18n.translate('xpack.canvas.renderer.advancedFilter.inputPlaceholder', { + defaultMessage: 'Enter filter expression', + }), +}; export interface Props { /** Optional value for the component */ diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/dropdown_filter/component/dropdown_filter.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/dropdown_filter/component/dropdown_filter.tsx index 86517c897f02..43f2e1ecc84f 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/dropdown_filter/component/dropdown_filter.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/filters/dropdown_filter/component/dropdown_filter.tsx @@ -5,12 +5,18 @@ * 2.0. */ -import { EuiIcon } from '@elastic/eui'; -import PropTypes from 'prop-types'; import React, { ChangeEvent, FocusEvent, FunctionComponent } from 'react'; -import { ComponentStrings } from '../../../../../i18n'; +import PropTypes from 'prop-types'; +import { EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -const { DropdownFilter: strings } = ComponentStrings; +const strings = { + getMatchAllOptionLabel: () => + i18n.translate('xpack.canvas.renderer.dropdownFilter.matchAllOptionLabel', { + defaultMessage: 'ANY', + description: 'The dropdown filter option to match any value in the field.', + }), +}; export interface Props { /** diff --git a/x-pack/plugins/canvas/i18n/components.ts b/x-pack/plugins/canvas/i18n/components.ts deleted file mode 100644 index 6f011bb73e3b..000000000000 --- a/x-pack/plugins/canvas/i18n/components.ts +++ /dev/null @@ -1,1543 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { BOLD_MD_TOKEN, CANVAS, HTML, JSON, PDF, URL, ZIP } from './constants'; - -export const ComponentStrings = { - AddEmbeddableFlyout: { - getNoItemsText: () => - i18n.translate('xpack.canvas.embedObject.noMatchingObjectsMessage', { - defaultMessage: 'No matching objects found.', - }), - getTitleText: () => - i18n.translate('xpack.canvas.embedObject.titleText', { - defaultMessage: 'Add from Kibana', - }), - }, - AdvancedFilter: { - getApplyButtonLabel: () => - i18n.translate('xpack.canvas.renderer.advancedFilter.applyButtonLabel', { - defaultMessage: 'Apply', - description: 'This refers to applying the filter to the Canvas workpad', - }), - getInputPlaceholder: () => - i18n.translate('xpack.canvas.renderer.advancedFilter.inputPlaceholder', { - defaultMessage: 'Enter filter expression', - }), - }, - App: { - getLoadErrorMessage: (error: string) => - i18n.translate('xpack.canvas.app.loadErrorMessage', { - defaultMessage: 'Message: {error}', - values: { - error, - }, - }), - getLoadErrorTitle: () => - i18n.translate('xpack.canvas.app.loadErrorTitle', { - defaultMessage: 'Canvas failed to load', - }), - getLoadingMessage: () => - i18n.translate('xpack.canvas.app.loadingMessage', { - defaultMessage: 'Canvas is loading', - }), - }, - ArgAddPopover: { - getAddAriaLabel: () => - i18n.translate('xpack.canvas.argAddPopover.addAriaLabel', { - defaultMessage: 'Add argument', - }), - }, - ArgFormAdvancedFailure: { - getApplyButtonLabel: () => - i18n.translate('xpack.canvas.argFormAdvancedFailure.applyButtonLabel', { - defaultMessage: 'Apply', - }), - getResetButtonLabel: () => - i18n.translate('xpack.canvas.argFormAdvancedFailure.resetButtonLabel', { - defaultMessage: 'Reset', - }), - getRowErrorMessage: () => - i18n.translate('xpack.canvas.argFormAdvancedFailure.rowErrorMessage', { - defaultMessage: 'Invalid Expression', - }), - }, - ArgFormArgSimpleForm: { - getRemoveAriaLabel: () => - i18n.translate('xpack.canvas.argFormArgSimpleForm.removeAriaLabel', { - defaultMessage: 'Remove', - }), - getRequiredTooltip: () => - i18n.translate('xpack.canvas.argFormArgSimpleForm.requiredTooltip', { - defaultMessage: 'This argument is required, you should specify a value.', - }), - }, - ArgFormPendingArgValue: { - getLoadingMessage: () => - i18n.translate('xpack.canvas.argFormPendingArgValue.loadingMessage', { - defaultMessage: 'Loading', - }), - }, - ArgFormSimpleFailure: { - getFailureTooltip: () => - i18n.translate('xpack.canvas.argFormSimpleFailure.failureTooltip', { - defaultMessage: - 'The interface for this argument could not parse the value, so a fallback input is being used', - }), - }, - Asset: { - getCopyAssetTooltip: () => - i18n.translate('xpack.canvas.asset.copyAssetTooltip', { - defaultMessage: 'Copy id to clipboard', - }), - getCreateImageTooltip: () => - i18n.translate('xpack.canvas.asset.createImageTooltip', { - defaultMessage: 'Create image element', - }), - getDeleteAssetTooltip: () => - i18n.translate('xpack.canvas.asset.deleteAssetTooltip', { - defaultMessage: 'Delete', - }), - getDownloadAssetTooltip: () => - i18n.translate('xpack.canvas.asset.downloadAssetTooltip', { - defaultMessage: 'Download', - }), - getThumbnailAltText: () => - i18n.translate('xpack.canvas.asset.thumbnailAltText', { - defaultMessage: 'Asset thumbnail', - }), - getConfirmModalButtonLabel: () => - i18n.translate('xpack.canvas.asset.confirmModalButtonLabel', { - defaultMessage: 'Remove', - }), - getConfirmModalMessageText: () => - i18n.translate('xpack.canvas.asset.confirmModalDetail', { - defaultMessage: 'Are you sure you want to remove this asset?', - }), - getConfirmModalTitle: () => - i18n.translate('xpack.canvas.asset.confirmModalTitle', { - defaultMessage: 'Remove Asset', - }), - }, - AssetManager: { - getButtonLabel: () => - i18n.translate('xpack.canvas.assetManager.manageButtonLabel', { - defaultMessage: 'Manage assets', - }), - getDescription: () => - i18n.translate('xpack.canvas.assetModal.modalDescription', { - defaultMessage: - 'Below are the image assets in this workpad. Any assets that are currently in use cannot be determined at this time. To reclaim space, delete assets.', - }), - getEmptyAssetsDescription: () => - i18n.translate('xpack.canvas.assetModal.emptyAssetsDescription', { - defaultMessage: 'Import your assets to get started', - }), - getFilePickerPromptText: () => - i18n.translate('xpack.canvas.assetModal.filePickerPromptText', { - defaultMessage: 'Select or drag and drop images', - }), - getLoadingText: () => - i18n.translate('xpack.canvas.assetModal.loadingText', { - defaultMessage: 'Uploading images', - }), - getModalCloseButtonLabel: () => - i18n.translate('xpack.canvas.assetModal.modalCloseButtonLabel', { - defaultMessage: 'Close', - }), - getModalTitle: () => - i18n.translate('xpack.canvas.assetModal.modalTitle', { - defaultMessage: 'Manage workpad assets', - }), - getSpaceUsedText: (percentageUsed: number) => - i18n.translate('xpack.canvas.assetModal.spacedUsedText', { - defaultMessage: '{percentageUsed}% space used', - values: { - percentageUsed, - }, - }), - getCopyAssetMessage: (id: string) => - i18n.translate('xpack.canvas.assetModal.copyAssetMessage', { - defaultMessage: `Copied '{id}' to clipboard`, - values: { - id, - }, - }), - }, - AssetPicker: { - getAssetAltText: () => - i18n.translate('xpack.canvas.assetpicker.assetAltText', { - defaultMessage: 'Asset thumbnail', - }), - }, - CanvasLoading: { - getLoadingLabel: () => - i18n.translate('xpack.canvas.canvasLoading.loadingMessage', { - defaultMessage: 'Loading', - }), - }, - ColorManager: { - getAddAriaLabel: () => - i18n.translate('xpack.canvas.colorManager.addAriaLabel', { - defaultMessage: 'Add Color', - }), - getCodePlaceholder: () => - i18n.translate('xpack.canvas.colorManager.codePlaceholder', { - defaultMessage: 'Color code', - }), - getRemoveAriaLabel: () => - i18n.translate('xpack.canvas.colorManager.removeAriaLabel', { - defaultMessage: 'Remove Color', - }), - }, - CustomElementModal: { - getCancelButtonLabel: () => - i18n.translate('xpack.canvas.customElementModal.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - getCharactersRemainingDescription: (numberOfRemainingCharacter: number) => - i18n.translate('xpack.canvas.customElementModal.remainingCharactersDescription', { - defaultMessage: '{numberOfRemainingCharacter} characters remaining', - values: { - numberOfRemainingCharacter, - }, - }), - getDescriptionInputLabel: () => - i18n.translate('xpack.canvas.customElementModal.descriptionInputLabel', { - defaultMessage: 'Description', - }), - getElementPreviewTitle: () => - i18n.translate('xpack.canvas.customElementModal.elementPreviewTitle', { - defaultMessage: 'Element preview', - }), - getImageFilePickerPlaceholder: () => - i18n.translate('xpack.canvas.customElementModal.imageFilePickerPlaceholder', { - defaultMessage: 'Select or drag and drop an image', - }), - getImageInputDescription: () => - i18n.translate('xpack.canvas.customElementModal.imageInputDescription', { - defaultMessage: - 'Take a screenshot of your element and upload it here. This can also be done after saving.', - }), - getImageInputLabel: () => - i18n.translate('xpack.canvas.customElementModal.imageInputLabel', { - defaultMessage: 'Thumbnail image', - }), - getNameInputLabel: () => - i18n.translate('xpack.canvas.customElementModal.nameInputLabel', { - defaultMessage: 'Name', - }), - getSaveButtonLabel: () => - i18n.translate('xpack.canvas.customElementModal.saveButtonLabel', { - defaultMessage: 'Save', - }), - }, - DatasourceDatasourceComponent: { - getChangeButtonLabel: () => - i18n.translate('xpack.canvas.datasourceDatasourceComponent.changeButtonLabel', { - defaultMessage: 'Change element data source', - }), - getExpressionArgDescription: () => - i18n.translate('xpack.canvas.datasourceDatasourceComponent.expressionArgDescription', { - defaultMessage: - 'The datasource has an argument controlled by an expression. Use the expression editor to modify the datasource.', - }), - getPreviewButtonLabel: () => - i18n.translate('xpack.canvas.datasourceDatasourceComponent.previewButtonLabel', { - defaultMessage: 'Preview data', - }), - getSaveButtonLabel: () => - i18n.translate('xpack.canvas.datasourceDatasourceComponent.saveButtonLabel', { - defaultMessage: 'Save', - }), - }, - DatasourceDatasourcePreview: { - getEmptyFirstLineDescription: () => - i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptyFirstLineDescription', { - defaultMessage: "We couldn't find any documents matching your search criteria.", - }), - getEmptySecondLineDescription: () => - i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptySecondLineDescription', { - defaultMessage: 'Check your datasource settings and try again.', - }), - getEmptyTitle: () => - i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptyTitle', { - defaultMessage: 'No documents found', - }), - getModalTitle: () => - i18n.translate('xpack.canvas.datasourceDatasourcePreview.modalTitle', { - defaultMessage: 'Datasource preview', - }), - }, - DatasourceNoDatasource: { - getPanelDescription: () => - i18n.translate('xpack.canvas.datasourceNoDatasource.panelDescription', { - defaultMessage: - "This element does not have an attached data source. This is usually because the element is an image or other static asset. If that's not the case you might want to check your expression to make sure it is not malformed.", - }), - getPanelTitle: () => - i18n.translate('xpack.canvas.datasourceNoDatasource.panelTitle', { - defaultMessage: 'No data source present', - }), - }, - DropdownFilter: { - getMatchAllOptionLabel: () => - i18n.translate('xpack.canvas.renderer.dropdownFilter.matchAllOptionLabel', { - defaultMessage: 'ANY', - description: 'The dropdown filter option to match any value in the field.', - }), - }, - ElementConfig: { - getFailedLabel: () => - i18n.translate('xpack.canvas.elementConfig.failedLabel', { - defaultMessage: 'Failed', - description: - 'The label for the total number of elements in a workpad that have thrown an error or failed to load', - }), - getLoadedLabel: () => - i18n.translate('xpack.canvas.elementConfig.loadedLabel', { - defaultMessage: 'Loaded', - description: 'The label for the number of elements in a workpad that have loaded', - }), - getProgressLabel: () => - i18n.translate('xpack.canvas.elementConfig.progressLabel', { - defaultMessage: 'Progress', - description: 'The label for the percentage of elements that have finished loading', - }), - getTitle: () => - i18n.translate('xpack.canvas.elementConfig.title', { - defaultMessage: 'Element status', - description: - '"Elements" refers to the individual text, images, or visualizations that you can add to a Canvas workpad', - }), - getTotalLabel: () => - i18n.translate('xpack.canvas.elementConfig.totalLabel', { - defaultMessage: 'Total', - description: 'The label for the total number of elements in a workpad', - }), - }, - ElementControls: { - getDeleteAriaLabel: () => - i18n.translate('xpack.canvas.elementControls.deleteAriaLabel', { - defaultMessage: 'Delete element', - }), - getDeleteTooltip: () => - i18n.translate('xpack.canvas.elementControls.deleteToolTip', { - defaultMessage: 'Delete', - }), - getEditAriaLabel: () => - i18n.translate('xpack.canvas.elementControls.editAriaLabel', { - defaultMessage: 'Edit element', - }), - getEditTooltip: () => - i18n.translate('xpack.canvas.elementControls.editToolTip', { - defaultMessage: 'Edit', - }), - }, - ElementSettings: { - getDataTabLabel: () => - i18n.translate('xpack.canvas.elementSettings.dataTabLabel', { - defaultMessage: 'Data', - description: - 'This tab contains the settings for the data (i.e. Elasticsearch query) used as ' + - 'the source for a Canvas element', - }), - getDisplayTabLabel: () => - i18n.translate('xpack.canvas.elementSettings.displayTabLabel', { - defaultMessage: 'Display', - description: 'This tab contains the settings for how data is displayed in a Canvas element', - }), - }, - Error: { - getDescription: () => - i18n.translate('xpack.canvas.errorComponent.description', { - defaultMessage: 'Expression failed with the message:', - }), - getTitle: () => - i18n.translate('xpack.canvas.errorComponent.title', { - defaultMessage: 'Whoops! Expression failed', - }), - }, - Expression: { - getCancelButtonLabel: () => - i18n.translate('xpack.canvas.expression.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - getCloseButtonLabel: () => - i18n.translate('xpack.canvas.expression.closeButtonLabel', { - defaultMessage: 'Close', - }), - getLearnLinkText: () => - i18n.translate('xpack.canvas.expression.learnLinkText', { - defaultMessage: 'Learn expression syntax', - }), - getMaximizeButtonLabel: () => - i18n.translate('xpack.canvas.expression.maximizeButtonLabel', { - defaultMessage: 'Maximize editor', - }), - getMinimizeButtonLabel: () => - i18n.translate('xpack.canvas.expression.minimizeButtonLabel', { - defaultMessage: 'Minimize Editor', - }), - getRunButtonLabel: () => - i18n.translate('xpack.canvas.expression.runButtonLabel', { - defaultMessage: 'Run', - }), - getRunTooltip: () => - i18n.translate('xpack.canvas.expression.runTooltip', { - defaultMessage: 'Run the expression', - }), - }, - ExpressionElementNotSelected: { - getCloseButtonLabel: () => - i18n.translate('xpack.canvas.expressionElementNotSelected.closeButtonLabel', { - defaultMessage: 'Close', - }), - getSelectDescription: () => - i18n.translate('xpack.canvas.expressionElementNotSelected.selectDescription', { - defaultMessage: 'Select an element to show expression input', - }), - }, - ExpressionInput: { - getArgReferenceAliasesDetail: (aliases: string) => - i18n.translate('xpack.canvas.expressionInput.argReferenceAliasesDetail', { - defaultMessage: '{BOLD_MD_TOKEN}Aliases{BOLD_MD_TOKEN}: {aliases}', - values: { - BOLD_MD_TOKEN, - aliases, - }, - }), - getArgReferenceDefaultDetail: (defaultVal: string) => - i18n.translate('xpack.canvas.expressionInput.argReferenceDefaultDetail', { - defaultMessage: '{BOLD_MD_TOKEN}Default{BOLD_MD_TOKEN}: {defaultVal}', - values: { - BOLD_MD_TOKEN, - defaultVal, - }, - }), - getArgReferenceRequiredDetail: (required: string) => - i18n.translate('xpack.canvas.expressionInput.argReferenceRequiredDetail', { - defaultMessage: '{BOLD_MD_TOKEN}Required{BOLD_MD_TOKEN}: {required}', - values: { - BOLD_MD_TOKEN, - required, - }, - }), - getArgReferenceTypesDetail: (types: string) => - i18n.translate('xpack.canvas.expressionInput.argReferenceTypesDetail', { - defaultMessage: '{BOLD_MD_TOKEN}Types{BOLD_MD_TOKEN}: {types}', - values: { - BOLD_MD_TOKEN, - types, - }, - }), - getFunctionReferenceAcceptsDetail: (acceptTypes: string) => - i18n.translate('xpack.canvas.expressionInput.functionReferenceAccepts', { - defaultMessage: '{BOLD_MD_TOKEN}Accepts{BOLD_MD_TOKEN}: {acceptTypes}', - values: { - BOLD_MD_TOKEN, - acceptTypes, - }, - }), - getFunctionReferenceReturnsDetail: (returnType: string) => - i18n.translate('xpack.canvas.expressionInput.functionReferenceReturns', { - defaultMessage: '{BOLD_MD_TOKEN}Returns{BOLD_MD_TOKEN}: {returnType}', - values: { - BOLD_MD_TOKEN, - returnType, - }, - }), - }, - FunctionFormContextError: { - getContextErrorMessage: (errorMessage: string) => - i18n.translate('xpack.canvas.functionForm.contextError', { - defaultMessage: 'ERROR: {errorMessage}', - values: { - errorMessage, - }, - }), - }, - FunctionFormFunctionUnknown: { - getUnknownArgumentTypeErrorMessage: (expressionType: string) => - i18n.translate('xpack.canvas.functionForm.functionUnknown.unknownArgumentTypeError', { - defaultMessage: 'Unknown expression type "{expressionType}"', - values: { - expressionType, - }, - }), - }, - GroupSettings: { - getSaveGroupDescription: () => - i18n.translate('xpack.canvas.groupSettings.saveGroupDescription', { - defaultMessage: 'Save this group as a new element to re-use it throughout your workpad.', - }), - getUngroupDescription: () => - i18n.translate('xpack.canvas.groupSettings.ungroupDescription', { - defaultMessage: 'Ungroup ({uKey}) to edit individual element settings.', - values: { - uKey: 'U', - }, - }), - }, - HelpMenu: { - getDocumentationLinkLabel: () => - i18n.translate('xpack.canvas.helpMenu.documentationLinkLabel', { - defaultMessage: '{CANVAS} documentation', - values: { - CANVAS, - }, - }), - getHelpMenuDescription: () => - i18n.translate('xpack.canvas.helpMenu.description', { - defaultMessage: 'For {CANVAS} specific information', - values: { - CANVAS, - }, - }), - getKeyboardShortcutsLinkLabel: () => - i18n.translate('xpack.canvas.helpMenu.keyboardShortcutsLinkLabel', { - defaultMessage: 'Keyboard shortcuts', - }), - }, - KeyboardShortcutsDoc: { - getFlyoutCloseButtonAriaLabel: () => - i18n.translate('xpack.canvas.keyboardShortcutsDoc.flyout.closeButtonAriaLabel', { - defaultMessage: 'Closes keyboard shortcuts reference', - }), - getShortcutSeparator: () => - i18n.translate('xpack.canvas.keyboardShortcutsDoc.shortcutListSeparator', { - defaultMessage: 'or', - description: - 'Separates which keyboard shortcuts can be used for a single action. Example: "{shortcut1} or {shortcut2} or {shortcut3}"', - }), - getTitle: () => - i18n.translate('xpack.canvas.keyboardShortcutsDoc.flyoutHeaderTitle', { - defaultMessage: 'Keyboard shortcuts', - }), - }, - LabsControl: { - getLabsButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderLabsControlSettings.labsButtonLabel', { - defaultMessage: 'Labs', - }), - getAriaLabel: () => - i18n.translate('xpack.canvas.workpadHeaderLabsControlSettings.labsAriaLabel', { - defaultMessage: 'View labs projects', - }), - getTooltip: () => - i18n.translate('xpack.canvas.workpadHeaderLabsControlSettings.labsTooltip', { - defaultMessage: 'View labs projects', - }), - }, - Link: { - getErrorMessage: (message: string) => - i18n.translate('xpack.canvas.link.errorMessage', { - defaultMessage: 'LINK ERROR: {message}', - values: { - message, - }, - }), - }, - MultiElementSettings: { - getMultipleElementsActionsDescription: () => - i18n.translate('xpack.canvas.groupSettings.multipleElementsActionsDescription', { - defaultMessage: - 'Deselect these elements to edit their individual settings, press ({gKey}) to group them, or save this selection as a new ' + - 'element to re-use it throughout your workpad.', - values: { - gKey: 'G', - }, - }), - getMultipleElementsDescription: () => - i18n.translate('xpack.canvas.groupSettings.multipleElementsDescription', { - defaultMessage: 'Multiple elements are currently selected.', - }), - }, - PageConfig: { - getBackgroundColorDescription: () => - i18n.translate('xpack.canvas.pageConfig.backgroundColorDescription', { - defaultMessage: 'Accepts HEX, RGB or HTML color names', - }), - getBackgroundColorLabel: () => - i18n.translate('xpack.canvas.pageConfig.backgroundColorLabel', { - defaultMessage: 'Background', - }), - getNoTransitionDropDownOptionLabel: () => - i18n.translate('xpack.canvas.pageConfig.transitions.noneDropDownOptionLabel', { - defaultMessage: 'None', - description: - 'This is the option the user should choose if they do not want any page transition (i.e. fade in, fade out, etc) to ' + - 'be applied to the current page.', - }), - getTitle: () => - i18n.translate('xpack.canvas.pageConfig.title', { - defaultMessage: 'Page settings', - }), - getTransitionLabel: () => - i18n.translate('xpack.canvas.pageConfig.transitionLabel', { - defaultMessage: 'Transition', - description: - 'This refers to the transition effect, such as fade in or rotate, applied to a page in presentation mode.', - }), - getTransitionPreviewLabel: () => - i18n.translate('xpack.canvas.pageConfig.transitionPreviewLabel', { - defaultMessage: 'Preview', - description: 'This is the label for a preview of the transition effect selected.', - }), - }, - PageManager: { - getPageNumberAriaLabel: (pageNumber: number) => - i18n.translate('xpack.canvas.pageManager.pageNumberAriaLabel', { - defaultMessage: 'Load page number {pageNumber}', - values: { - pageNumber, - }, - }), - getAddPageTooltip: () => - i18n.translate('xpack.canvas.pageManager.addPageTooltip', { - defaultMessage: 'Add a new page to this workpad', - }), - getConfirmRemoveTitle: () => - i18n.translate('xpack.canvas.pageManager.confirmRemoveTitle', { - defaultMessage: 'Remove Page', - }), - getConfirmRemoveDescription: () => - i18n.translate('xpack.canvas.pageManager.confirmRemoveDescription', { - defaultMessage: 'Are you sure you want to remove this page?', - }), - getConfirmRemoveButtonLabel: () => - i18n.translate('xpack.canvas.pageManager.removeButtonLabel', { - defaultMessage: 'Remove', - }), - }, - PagePreviewPageControls: { - getClonePageAriaLabel: () => - i18n.translate('xpack.canvas.pagePreviewPageControls.clonePageAriaLabel', { - defaultMessage: 'Clone page', - }), - getClonePageTooltip: () => - i18n.translate('xpack.canvas.pagePreviewPageControls.clonePageTooltip', { - defaultMessage: 'Clone', - }), - getDeletePageAriaLabel: () => - i18n.translate('xpack.canvas.pagePreviewPageControls.deletePageAriaLabel', { - defaultMessage: 'Delete page', - }), - getDeletePageTooltip: () => - i18n.translate('xpack.canvas.pagePreviewPageControls.deletePageTooltip', { - defaultMessage: 'Delete', - }), - }, - PalettePicker: { - getEmptyPaletteLabel: () => - i18n.translate('xpack.canvas.palettePicker.emptyPaletteLabel', { - defaultMessage: 'None', - }), - getNoPaletteFoundErrorTitle: () => - i18n.translate('xpack.canvas.palettePicker.noPaletteFoundErrorTitle', { - defaultMessage: 'Color palette not found', - }), - }, - SavedElementsModal: { - getAddNewElementDescription: () => - i18n.translate('xpack.canvas.savedElementsModal.addNewElementDescription', { - defaultMessage: 'Group and save workpad elements to create new elements', - }), - getAddNewElementTitle: () => - i18n.translate('xpack.canvas.savedElementsModal.addNewElementTitle', { - defaultMessage: 'Add new elements', - }), - getCancelButtonLabel: () => - i18n.translate('xpack.canvas.savedElementsModal.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - getDeleteButtonLabel: () => - i18n.translate('xpack.canvas.savedElementsModal.deleteButtonLabel', { - defaultMessage: 'Delete', - }), - getDeleteElementDescription: () => - i18n.translate('xpack.canvas.savedElementsModal.deleteElementDescription', { - defaultMessage: 'Are you sure you want to delete this element?', - }), - getDeleteElementTitle: (elementName: string) => - i18n.translate('xpack.canvas.savedElementsModal.deleteElementTitle', { - defaultMessage: `Delete element '{elementName}'?`, - values: { - elementName, - }, - }), - getEditElementTitle: () => - i18n.translate('xpack.canvas.savedElementsModal.editElementTitle', { - defaultMessage: 'Edit element', - }), - getElementsTitle: () => - i18n.translate('xpack.canvas.savedElementsModal.elementsTitle', { - defaultMessage: 'Elements', - description: 'Title for the "Elements" tab when adding a new element', - }), - getFindElementPlaceholder: () => - i18n.translate('xpack.canvas.savedElementsModal.findElementPlaceholder', { - defaultMessage: 'Find element', - }), - getModalTitle: () => - i18n.translate('xpack.canvas.savedElementsModal.modalTitle', { - defaultMessage: 'My elements', - }), - getMyElementsTitle: () => - i18n.translate('xpack.canvas.savedElementsModal.myElementsTitle', { - defaultMessage: 'My elements', - description: 'Title for the "My elements" tab when adding a new element', - }), - getSavedElementsModalCloseButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeader.addElementModalCloseButtonLabel', { - defaultMessage: 'Close', - }), - }, - ShareWebsiteFlyout: { - getRuntimeStepTitle: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.downloadRuntimeTitle', { - defaultMessage: 'Download runtime', - }), - getSnippentsStepTitle: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.addSnippetsTitle', { - defaultMessage: 'Add snippets to website', - }), - getStepsDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.description', { - defaultMessage: - 'Follow these steps to share a static version of this workpad on an external website. It will be a visual snapshot of the current workpad, and will not have access to live data.', - }), - getTitle: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.flyoutTitle', { - defaultMessage: 'Share on a website', - }), - getUnsupportedRendererWarning: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.unsupportedRendererWarning', { - defaultMessage: - 'This workpad contains render functions that are not supported by the {CANVAS} Shareable Workpad Runtime. These elements will not be rendered:', - values: { - CANVAS, - }, - }), - getWorkpadStepTitle: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.downloadWorkpadTitle', { - defaultMessage: 'Download workpad', - }), - }, - ShareWebsiteRuntimeStep: { - getDownloadLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.runtimeStep.downloadLabel', { - defaultMessage: 'Download runtime', - }), - getStepDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.runtimeStep.description', { - defaultMessage: - 'In order to render a Shareable Workpad, you also need to include the {CANVAS} Shareable Workpad Runtime. You can skip this step if the runtime is already included on your website.', - values: { - CANVAS, - }, - }), - }, - ShareWebsiteSnippetsStep: { - getAutoplayParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.autoplayParameterDescription', { - defaultMessage: 'Should the runtime automatically move through the pages of the workpad?', - }), - getCallRuntimeLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.callRuntimeLabel', { - defaultMessage: 'Call Runtime', - }), - getHeightParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.heightParameterDescription', { - defaultMessage: 'The height of the Workpad. Defaults to the Workpad height.', - }), - getIncludeRuntimeLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.includeRuntimeLabel', { - defaultMessage: 'Include Runtime', - }), - getIntervalParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.intervalParameterDescription', { - defaultMessage: - 'The interval upon which the pages will advance in time format, (e.g. {twoSeconds}, {oneMinute})', - values: { - twoSeconds: '2s', - oneMinute: '1m', - }, - }), - getPageParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.pageParameterDescription', { - defaultMessage: 'The page to display. Defaults to the page specified by the Workpad.', - }), - getParametersDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.parametersDescription', { - defaultMessage: - 'There are a number of inline parameters to configure the Shareable Workpad.', - }), - getParametersTitle: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.parametersLabel', { - defaultMessage: 'Parameters', - }), - getPlaceholderLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.placeholderLabel', { - defaultMessage: 'Placeholder', - }), - getRequiredLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.requiredLabel', { - defaultMessage: 'required', - }), - getShareableParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.shareableParameterDescription', { - defaultMessage: 'The type of shareable. In this case, a {CANVAS} Workpad.', - values: { - CANVAS, - }, - }), - getSnippetsStepDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.description', { - defaultMessage: - 'The Workpad is placed within the {HTML} of the site by using an {HTML} placeholder. Parameters for the runtime are included inline. See the full list of parameters below. You can include more than one workpad on the page.', - values: { - HTML, - }, - }), - getToolbarParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.toolbarParameterDescription', { - defaultMessage: 'Should the toolbar be hidden?', - }), - getUrlParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.urlParameterDescription', { - defaultMessage: 'The {URL} of the Shareable Workpad {JSON} file.', - values: { - URL, - JSON, - }, - }), - getWidthParameterDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.widthParameterDescription', { - defaultMessage: 'The width of the Workpad. Defaults to the Workpad width.', - }), - }, - ShareWebsiteWorkpadStep: { - getDownloadLabel: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.workpadStep.downloadLabel', { - defaultMessage: 'Download workpad', - }), - getStepDescription: () => - i18n.translate('xpack.canvas.shareWebsiteFlyout.workpadStep.description', { - defaultMessage: - 'The workpad will be exported as a single {JSON} file for sharing in another site.', - values: { - JSON, - }, - }), - }, - SidebarContent: { - getGroupedElementSidebarTitle: () => - i18n.translate('xpack.canvas.sidebarContent.groupedElementSidebarTitle', { - defaultMessage: 'Grouped element', - description: - 'The title displayed when a grouped element is selected. "elements" refer to the different visualizations, images, ' + - 'text, etc that can be added in a Canvas workpad. These elements can be grouped into a larger "grouped element" ' + - 'that contains multiple individual elements.', - }), - getMultiElementSidebarTitle: () => - i18n.translate('xpack.canvas.sidebarContent.multiElementSidebarTitle', { - defaultMessage: 'Multiple elements', - description: - 'The title displayed when multiple elements are selected. "elements" refer to the different visualizations, images, ' + - 'text, etc that can be added in a Canvas workpad.', - }), - getSingleElementSidebarTitle: () => - i18n.translate('xpack.canvas.sidebarContent.singleElementSidebarTitle', { - defaultMessage: 'Selected element', - description: - 'The title displayed when a single element are selected. "element" refer to the different visualizations, images, ' + - 'text, etc that can be added in a Canvas workpad.', - }), - }, - SidebarHeader: { - getBringForwardAriaLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.bringForwardArialLabel', { - defaultMessage: 'Move element up one layer', - }), - getBringToFrontAriaLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.bringToFrontArialLabel', { - defaultMessage: 'Move element to top layer', - }), - getSendBackwardAriaLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.sendBackwardArialLabel', { - defaultMessage: 'Move element down one layer', - }), - getSendToBackAriaLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.sendToBackArialLabel', { - defaultMessage: 'Move element to bottom layer', - }), - }, - TextStylePicker: { - getAlignCenterOption: () => - i18n.translate('xpack.canvas.textStylePicker.alignCenterOption', { - defaultMessage: 'Align center', - }), - getAlignLeftOption: () => - i18n.translate('xpack.canvas.textStylePicker.alignLeftOption', { - defaultMessage: 'Align left', - }), - getAlignRightOption: () => - i18n.translate('xpack.canvas.textStylePicker.alignRightOption', { - defaultMessage: 'Align right', - }), - getAlignmentOptionsControlLegend: () => - i18n.translate('xpack.canvas.textStylePicker.alignmentOptionsControl', { - defaultMessage: 'Alignment options', - }), - getFontColorLabel: () => - i18n.translate('xpack.canvas.textStylePicker.fontColorLabel', { - defaultMessage: 'Font Color', - }), - getStyleBoldOption: () => - i18n.translate('xpack.canvas.textStylePicker.styleBoldOption', { - defaultMessage: 'Bold', - }), - getStyleItalicOption: () => - i18n.translate('xpack.canvas.textStylePicker.styleItalicOption', { - defaultMessage: 'Italic', - }), - getStyleUnderlineOption: () => - i18n.translate('xpack.canvas.textStylePicker.styleUnderlineOption', { - defaultMessage: 'Underline', - }), - getStyleOptionsControlLegend: () => - i18n.translate('xpack.canvas.textStylePicker.styleOptionsControl', { - defaultMessage: 'Style options', - }), - }, - TimePicker: { - getApplyButtonLabel: () => - i18n.translate('xpack.canvas.timePicker.applyButtonLabel', { - defaultMessage: 'Apply', - }), - }, - Toolbar: { - getEditorButtonLabel: () => - i18n.translate('xpack.canvas.toolbar.editorButtonLabel', { - defaultMessage: 'Expression editor', - }), - getNextPageAriaLabel: () => - i18n.translate('xpack.canvas.toolbar.nextPageAriaLabel', { - defaultMessage: 'Next Page', - }), - getPageButtonLabel: (pageNum: number, totalPages: number) => - i18n.translate('xpack.canvas.toolbar.pageButtonLabel', { - defaultMessage: 'Page {pageNum}{rest}', - values: { - pageNum, - rest: totalPages > 1 ? ` of ${totalPages}` : '', - }, - }), - getPreviousPageAriaLabel: () => - i18n.translate('xpack.canvas.toolbar.previousPageAriaLabel', { - defaultMessage: 'Previous Page', - }), - getWorkpadManagerCloseButtonLabel: () => - i18n.translate('xpack.canvas.toolbar.workpadManagerCloseButtonLabel', { - defaultMessage: 'Close', - }), - getErrorMessage: (message: string) => - i18n.translate('xpack.canvas.toolbar.errorMessage', { - defaultMessage: 'TOOLBAR ERROR: {message}', - values: { - message, - }, - }), - }, - ToolbarTray: { - getCloseTrayAriaLabel: () => - i18n.translate('xpack.canvas.toolbarTray.closeTrayAriaLabel', { - defaultMessage: 'Close tray', - }), - }, - VarConfig: { - getAddButtonLabel: () => - i18n.translate('xpack.canvas.varConfig.addButtonLabel', { - defaultMessage: 'Add a variable', - }), - getAddTooltipLabel: () => - i18n.translate('xpack.canvas.varConfig.addTooltipLabel', { - defaultMessage: 'Add a variable', - }), - getCopyActionButtonLabel: () => - i18n.translate('xpack.canvas.varConfig.copyActionButtonLabel', { - defaultMessage: 'Copy snippet', - }), - getCopyActionTooltipLabel: () => - i18n.translate('xpack.canvas.varConfig.copyActionTooltipLabel', { - defaultMessage: 'Copy variable syntax to clipboard', - }), - getCopyNotificationDescription: () => - i18n.translate('xpack.canvas.varConfig.copyNotificationDescription', { - defaultMessage: 'Variable syntax copied to clipboard', - }), - getDeleteActionButtonLabel: () => - i18n.translate('xpack.canvas.varConfig.deleteActionButtonLabel', { - defaultMessage: 'Delete variable', - }), - getDeleteNotificationDescription: () => - i18n.translate('xpack.canvas.varConfig.deleteNotificationDescription', { - defaultMessage: 'Variable successfully deleted', - }), - getEditActionButtonLabel: () => - i18n.translate('xpack.canvas.varConfig.editActionButtonLabel', { - defaultMessage: 'Edit variable', - }), - getEmptyDescription: () => - i18n.translate('xpack.canvas.varConfig.emptyDescription', { - defaultMessage: - 'This workpad has no variables currently. You may add variables to store and edit common values. These variables can then be used in elements or within the expression editor.', - }), - getTableNameLabel: () => - i18n.translate('xpack.canvas.varConfig.tableNameLabel', { - defaultMessage: 'Name', - }), - getTableTypeLabel: () => - i18n.translate('xpack.canvas.varConfig.tableTypeLabel', { - defaultMessage: 'Type', - }), - getTableValueLabel: () => - i18n.translate('xpack.canvas.varConfig.tableValueLabel', { - defaultMessage: 'Value', - }), - getTitle: () => - i18n.translate('xpack.canvas.varConfig.titleLabel', { - defaultMessage: 'Variables', - }), - getTitleTooltip: () => - i18n.translate('xpack.canvas.varConfig.titleTooltip', { - defaultMessage: 'Add variables to store and edit common values', - }), - }, - VarConfigDeleteVar: { - getCancelButtonLabel: () => - i18n.translate('xpack.canvas.varConfigDeleteVar.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - getDeleteButtonLabel: () => - i18n.translate('xpack.canvas.varConfigDeleteVar.deleteButtonLabel', { - defaultMessage: 'Delete variable', - }), - getTitle: () => - i18n.translate('xpack.canvas.varConfigDeleteVar.titleLabel', { - defaultMessage: 'Delete variable?', - }), - getWarningDescription: () => - i18n.translate('xpack.canvas.varConfigDeleteVar.warningDescription', { - defaultMessage: - 'Deleting this variable may adversely affect the workpad. Are you sure you wish to continue?', - }), - }, - VarConfigEditVar: { - getAddTitle: () => - i18n.translate('xpack.canvas.varConfigEditVar.addTitleLabel', { - defaultMessage: 'Add variable', - }), - getCancelButtonLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - getDuplicateNameError: () => - i18n.translate('xpack.canvas.varConfigEditVar.duplicateNameError', { - defaultMessage: 'Variable name already in use', - }), - getEditTitle: () => - i18n.translate('xpack.canvas.varConfigEditVar.editTitleLabel', { - defaultMessage: 'Edit variable', - }), - getEditWarning: () => - i18n.translate('xpack.canvas.varConfigEditVar.editWarning', { - defaultMessage: 'Editing a variable in use may adversely affect your workpad', - }), - getNameFieldLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.nameFieldLabel', { - defaultMessage: 'Name', - }), - getSaveButtonLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.saveButtonLabel', { - defaultMessage: 'Save changes', - }), - getTypeBooleanLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.typeBooleanLabel', { - defaultMessage: 'Boolean', - }), - getTypeFieldLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.typeFieldLabel', { - defaultMessage: 'Type', - }), - getTypeNumberLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.typeNumberLabel', { - defaultMessage: 'Number', - }), - getTypeStringLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.typeStringLabel', { - defaultMessage: 'String', - }), - getValueFieldLabel: () => - i18n.translate('xpack.canvas.varConfigEditVar.valueFieldLabel', { - defaultMessage: 'Value', - }), - }, - VarConfigVarValueField: { - getBooleanOptionsLegend: () => - i18n.translate('xpack.canvas.varConfigVarValueField.booleanOptionsLegend', { - defaultMessage: 'Boolean value', - }), - getFalseOption: () => - i18n.translate('xpack.canvas.varConfigVarValueField.falseOption', { - defaultMessage: 'False', - }), - getTrueOption: () => - i18n.translate('xpack.canvas.varConfigVarValueField.trueOption', { - defaultMessage: 'True', - }), - }, - WorkpadConfig: { - getApplyStylesheetButtonLabel: () => - i18n.translate('xpack.canvas.workpadConfig.applyStylesheetButtonLabel', { - defaultMessage: `Apply stylesheet`, - description: - '"stylesheet" refers to the collection of CSS style rules entered by the user.', - }), - getBackgroundColorLabel: () => - i18n.translate('xpack.canvas.workpadConfig.backgroundColorLabel', { - defaultMessage: 'Background color', - }), - getFlipDimensionAriaLabel: () => - i18n.translate('xpack.canvas.workpadConfig.swapDimensionsAriaLabel', { - defaultMessage: `Swap the page's width and height`, - }), - getFlipDimensionTooltip: () => - i18n.translate('xpack.canvas.workpadConfig.swapDimensionsTooltip', { - defaultMessage: 'Swap the width and height', - }), - getGlobalCSSLabel: () => - i18n.translate('xpack.canvas.workpadConfig.globalCSSLabel', { - defaultMessage: `Global CSS overrides`, - }), - getGlobalCSSTooltip: () => - i18n.translate('xpack.canvas.workpadConfig.globalCSSTooltip', { - defaultMessage: `Apply styles to all pages in this workpad`, - }), - getNameLabel: () => - i18n.translate('xpack.canvas.workpadConfig.nameLabel', { - defaultMessage: 'Name', - }), - getPageHeightLabel: () => - i18n.translate('xpack.canvas.workpadConfig.heightLabel', { - defaultMessage: 'Height', - }), - getPageSizeBadgeAriaLabel: (sizeName: string) => - i18n.translate('xpack.canvas.workpadConfig.pageSizeBadgeAriaLabel', { - defaultMessage: `Preset page size: {sizeName}`, - values: { - sizeName, - }, - }), - getPageSizeBadgeOnClickAriaLabel: (sizeName: string) => - i18n.translate('xpack.canvas.workpadConfig.pageSizeBadgeOnClickAriaLabel', { - defaultMessage: `Set page size to {sizeName}`, - values: { - sizeName, - }, - }), - getPageWidthLabel: () => - i18n.translate('xpack.canvas.workpadConfig.widthLabel', { - defaultMessage: 'Width', - }), - getTitle: () => - i18n.translate('xpack.canvas.workpadConfig.title', { - defaultMessage: 'Workpad settings', - }), - getUSLetterButtonLabel: () => - i18n.translate('xpack.canvas.workpadConfig.USLetterButtonLabel', { - defaultMessage: 'US Letter', - description: 'This is referring to the dimensions of U.S. standard letter paper.', - }), - }, - WorkpadHeader: { - getAddElementButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeader.addElementButtonLabel', { - defaultMessage: 'Add element', - }), - getFullScreenButtonAriaLabel: () => - i18n.translate('xpack.canvas.workpadHeader.fullscreenButtonAriaLabel', { - defaultMessage: 'View fullscreen', - }), - getFullScreenTooltip: () => - i18n.translate('xpack.canvas.workpadHeader.fullscreenTooltip', { - defaultMessage: 'Enter fullscreen mode', - }), - getHideEditControlTooltip: () => - i18n.translate('xpack.canvas.workpadHeader.hideEditControlTooltip', { - defaultMessage: 'Hide editing controls', - }), - getNoWritePermissionTooltipText: () => - i18n.translate('xpack.canvas.workpadHeader.noWritePermissionTooltip', { - defaultMessage: "You don't have permission to edit this workpad", - }), - getShowEditControlTooltip: () => - i18n.translate('xpack.canvas.workpadHeader.showEditControlTooltip', { - defaultMessage: 'Show editing controls', - }), - }, - WorkpadHeaderAutoRefreshControls: { - getDisableTooltip: () => - i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.disableTooltip', { - defaultMessage: 'Disable auto-refresh', - }), - getIntervalFormLabelText: () => - i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.intervalFormLabel', { - defaultMessage: 'Change auto-refresh interval', - }), - getRefreshListDurationManualText: () => - i18n.translate( - 'xpack.canvas.workpadHeaderAutoRefreshControls.refreshListDurationManualText', - { - defaultMessage: 'Manually', - } - ), - getRefreshListTitle: () => - i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.refreshListTitle', { - defaultMessage: 'Refresh elements', - }), - }, - WorkpadHeaderCustomInterval: { - getButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderCustomInterval.confirmButtonLabel', { - defaultMessage: 'Set', - }), - getFormDescription: () => - i18n.translate('xpack.canvas.workpadHeaderCustomInterval.formDescription', { - defaultMessage: - 'Use shorthand notation, like {secondsExample}, {minutesExample}, or {hoursExample}', - values: { - secondsExample: '30s', - minutesExample: '10m', - hoursExample: '1h', - }, - }), - getFormLabel: () => - i18n.translate('xpack.canvas.workpadHeaderCustomInterval.formLabel', { - defaultMessage: 'Set a custom interval', - }), - }, - WorkpadHeaderEditMenu: { - getAlignmentMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.alignmentMenuItemLabel', { - defaultMessage: 'Alignment', - description: - 'This refers to the vertical (i.e. left, center, right) and horizontal (i.e. top, middle, bottom) ' + - 'alignment options of the selected elements', - }), - getBottomAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.bottomAlignMenuItemLabel', { - defaultMessage: 'Bottom', - }), - getCenterAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.centerAlignMenuItemLabel', { - defaultMessage: 'Center', - description: 'This refers to alignment centered horizontally.', - }), - getCreateElementModalTitle: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.createElementModalTitle', { - defaultMessage: 'Create new element', - }), - getDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.distributionMenutItemLabel', { - defaultMessage: 'Distribution', - description: - 'This refers to the options to evenly spacing the selected elements horizontall or vertically.', - }), - getEditMenuButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuButtonLabel', { - defaultMessage: 'Edit', - }), - getEditMenuLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuLabel', { - defaultMessage: 'Edit options', - }), - getGroupMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.groupMenuItemLabel', { - defaultMessage: 'Group', - description: 'This refers to grouping multiple selected elements.', - }), - getHorizontalDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.horizontalDistributionMenutItemLabel', { - defaultMessage: 'Horizontal', - }), - getLeftAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.leftAlignMenuItemLabel', { - defaultMessage: 'Left', - }), - getMiddleAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.middleAlignMenuItemLabel', { - defaultMessage: 'Middle', - description: 'This refers to alignment centered vertically.', - }), - getOrderMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.orderMenuItemLabel', { - defaultMessage: 'Order', - description: 'Refers to the order of the elements displayed on the page from front to back', - }), - getRedoMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.redoMenuItemLabel', { - defaultMessage: 'Redo', - }), - getRightAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.rightAlignMenuItemLabel', { - defaultMessage: 'Right', - }), - getSaveElementMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.savedElementMenuItemLabel', { - defaultMessage: 'Save as new element', - }), - getTopAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.topAlignMenuItemLabel', { - defaultMessage: 'Top', - }), - getUndoMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.undoMenuItemLabel', { - defaultMessage: 'Undo', - }), - getUngroupMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.ungroupMenuItemLabel', { - defaultMessage: 'Ungroup', - description: 'This refers to ungrouping a grouped element', - }), - getVerticalDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderEditMenu.verticalDistributionMenutItemLabel', { - defaultMessage: 'Vertical', - }), - }, - WorkpadHeaderElementMenu: { - getAssetsMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.manageAssetsMenuItemLabel', { - defaultMessage: 'Manage assets', - }), - getChartMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.chartMenuItemLabel', { - defaultMessage: 'Chart', - }), - getElementMenuButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.elementMenuButtonLabel', { - defaultMessage: 'Add element', - }), - getElementMenuLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.elementMenuLabel', { - defaultMessage: 'Add an element', - }), - getEmbedObjectMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.embedObjectMenuItemLabel', { - defaultMessage: 'Add from Kibana', - }), - getFilterMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.filterMenuItemLabel', { - defaultMessage: 'Filter', - }), - getImageMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.imageMenuItemLabel', { - defaultMessage: 'Image', - }), - getMyElementsMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.myElementsMenuItemLabel', { - defaultMessage: 'My elements', - }), - getOtherMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.otherMenuItemLabel', { - defaultMessage: 'Other', - }), - getProgressMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.progressMenuItemLabel', { - defaultMessage: 'Progress', - }), - getShapeMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.shapeMenuItemLabel', { - defaultMessage: 'Shape', - }), - getTextMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderElementMenu.textMenuItemLabel', { - defaultMessage: 'Text', - }), - }, - WorkpadHeaderKioskControls: { - getCycleFormLabel: () => - i18n.translate('xpack.canvas.workpadHeaderKioskControl.cycleFormLabel', { - defaultMessage: 'Change cycling interval', - }), - getCycleToggleSwitch: () => - i18n.translate('xpack.canvas.workpadHeaderKioskControl.cycleToggleSwitch', { - defaultMessage: 'Cycle slides automatically', - }), - getTitle: () => - i18n.translate('xpack.canvas.workpadHeaderKioskControl.controlTitle', { - defaultMessage: 'Cycle fullscreen pages', - }), - getAutoplayListDurationManualText: () => - i18n.translate('xpack.canvas.workpadHeaderKioskControl.autoplayListDurationManual', { - defaultMessage: 'Manually', - }), - getDisableTooltip: () => - i18n.translate('xpack.canvas.workpadHeaderKioskControl.disableTooltip', { - defaultMessage: 'Disable auto-play', - }), - }, - WorkpadHeaderRefreshControlSettings: { - getRefreshAriaLabel: () => - i18n.translate('xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel', { - defaultMessage: 'Refresh Elements', - }), - getRefreshTooltip: () => - i18n.translate('xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip', { - defaultMessage: 'Refresh data', - }), - }, - WorkpadHeaderShareMenu: { - getCopyPDFMessage: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.copyPDFMessage', { - defaultMessage: 'The {PDF} generation {URL} was copied to your clipboard.', - values: { - PDF, - URL, - }, - }), - getCopyShareConfigMessage: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage', { - defaultMessage: 'Copied share markup to clipboard', - }), - getShareableZipErrorTitle: (workpadName: string) => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWebsiteErrorTitle', { - defaultMessage: - "Failed to create {ZIP} file for '{workpadName}'. The workpad may be too large. You'll need to download the files separately.", - values: { - ZIP, - workpadName, - }, - }), - getShareDownloadJSONTitle: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle', { - defaultMessage: 'Download as {JSON}', - values: { - JSON, - }, - }), - getShareDownloadPDFTitle: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle', { - defaultMessage: '{PDF} reports', - values: { - PDF, - }, - }), - getShareMenuButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareMenuButtonLabel', { - defaultMessage: 'Share', - }), - getShareWebsiteTitle: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWebsiteTitle', { - defaultMessage: 'Share on a website', - }), - getShareWorkpadMessage: () => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWorkpadMessage', { - defaultMessage: 'Share this workpad', - }), - getUnknownExportErrorMessage: (type: string) => - i18n.translate('xpack.canvas.workpadHeaderShareMenu.unknownExportErrorMessage', { - defaultMessage: 'Unknown export type: {type}', - values: { - type, - }, - }), - }, - WorkpadHeaderViewMenu: { - getAutoplayOffMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplayOffMenuItemLabel', { - defaultMessage: 'Turn autoplay off', - }), - getAutoplayOnMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplayOnMenuItemLabel', { - defaultMessage: 'Turn autoplay on', - }), - getAutoplaySettingsMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplaySettingsMenuItemLabel', { - defaultMessage: 'Autoplay settings', - }), - getFullscreenMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.fullscreenMenuLabel', { - defaultMessage: 'Enter fullscreen mode', - }), - getHideEditModeLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.hideEditModeLabel', { - defaultMessage: 'Hide editing controls', - }), - getRefreshMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshMenuItemLabel', { - defaultMessage: 'Refresh data', - }), - getRefreshSettingsMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshSettingsMenuItemLabel', { - defaultMessage: 'Auto refresh settings', - }), - getShowEditModeLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.showEditModeLabel', { - defaultMessage: 'Show editing controls', - }), - getViewMenuButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.viewMenuButtonLabel', { - defaultMessage: 'View', - }), - getViewMenuLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.viewMenuLabel', { - defaultMessage: 'View options', - }), - getZoomControlsAriaLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomControlsAriaLabel', { - defaultMessage: 'Zoom controls', - }), - getZoomControlsTooltip: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomControlsTooltip', { - defaultMessage: 'Zoom controls', - }), - getZoomFitToWindowText: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomFitToWindowText', { - defaultMessage: 'Fit to window', - }), - getZoomInText: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomInText', { - defaultMessage: 'Zoom in', - }), - getZoomMenuItemLabel: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomMenuItemLabel', { - defaultMessage: 'Zoom', - }), - getZoomOutText: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomOutText', { - defaultMessage: 'Zoom out', - }), - getZoomPanelTitle: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomPanelTitle', { - defaultMessage: 'Zoom', - }), - getZoomPercentage: (scale: number) => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomResetText', { - defaultMessage: '{scalePercentage}%', - values: { - scalePercentage: scale * 100, - }, - }), - getZoomResetText: () => - i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomPrecentageValue', { - defaultMessage: 'Reset', - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/index.ts b/x-pack/plugins/canvas/i18n/index.ts index 14c9e5d221b7..d35b915ea7fb 100644 --- a/x-pack/plugins/canvas/i18n/index.ts +++ b/x-pack/plugins/canvas/i18n/index.ts @@ -6,7 +6,6 @@ */ export * from './capabilities'; -export * from './components'; export * from './constants'; export * from './errors'; export * from './expression_types'; diff --git a/x-pack/plugins/canvas/public/components/arg_add_popover/arg_add_popover.tsx b/x-pack/plugins/canvas/public/components/arg_add_popover/arg_add_popover.tsx index 194d2d8b3ddf..d9df1e4661fb 100644 --- a/x-pack/plugins/canvas/public/components/arg_add_popover/arg_add_popover.tsx +++ b/x-pack/plugins/canvas/public/components/arg_add_popover/arg_add_popover.tsx @@ -8,15 +8,20 @@ import React, { MouseEventHandler, FC } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + // @ts-expect-error untyped local import { Popover, PopoverChildrenProps } from '../popover'; import { ArgAdd } from '../arg_add'; // @ts-expect-error untyped local import { Arg } from '../../expression_types/arg'; -import { ComponentStrings } from '../../../i18n'; - -const { ArgAddPopover: strings } = ComponentStrings; +const strings = { + getAddAriaLabel: () => + i18n.translate('xpack.canvas.argAddPopover.addAriaLabel', { + defaultMessage: 'Add argument', + }), +}; interface ArgOptions { arg: Arg; diff --git a/x-pack/plugins/canvas/public/components/arg_form/advanced_failure.js b/x-pack/plugins/canvas/public/components/arg_form/advanced_failure.js index c40e74186e87..14f47553002a 100644 --- a/x-pack/plugins/canvas/public/components/arg_form/advanced_failure.js +++ b/x-pack/plugins/canvas/public/components/arg_form/advanced_failure.js @@ -9,12 +9,25 @@ import React from 'react'; import PropTypes from 'prop-types'; import { compose, withProps, withPropsOnChange } from 'recompose'; import { EuiTextArea, EuiButton, EuiButtonEmpty, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { fromExpression, toExpression } from '@kbn/interpreter/common'; -import { createStatefulPropHoc } from '../../components/enhance/stateful_prop'; -import { ComponentStrings } from '../../../i18n'; +import { createStatefulPropHoc } from '../../components/enhance/stateful_prop'; -const { ArgFormAdvancedFailure: strings } = ComponentStrings; +const strings = { + getApplyButtonLabel: () => + i18n.translate('xpack.canvas.argFormAdvancedFailure.applyButtonLabel', { + defaultMessage: 'Apply', + }), + getResetButtonLabel: () => + i18n.translate('xpack.canvas.argFormAdvancedFailure.resetButtonLabel', { + defaultMessage: 'Reset', + }), + getRowErrorMessage: () => + i18n.translate('xpack.canvas.argFormAdvancedFailure.rowErrorMessage', { + defaultMessage: 'Invalid Expression', + }), +}; export const AdvancedFailureComponent = (props) => { const { diff --git a/x-pack/plugins/canvas/public/components/arg_form/arg_simple_form.tsx b/x-pack/plugins/canvas/public/components/arg_form/arg_simple_form.tsx index 2ae772cdc197..84b87373c1c5 100644 --- a/x-pack/plugins/canvas/public/components/arg_form/arg_simple_form.tsx +++ b/x-pack/plugins/canvas/public/components/arg_form/arg_simple_form.tsx @@ -8,12 +8,20 @@ import React, { ReactNode, MouseEventHandler } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import { TooltipIcon, IconType } from '../tooltip_icon'; - -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; -const { ArgFormArgSimpleForm: strings } = ComponentStrings; +import { TooltipIcon, IconType } from '../tooltip_icon'; +const strings = { + getRemoveAriaLabel: () => + i18n.translate('xpack.canvas.argFormArgSimpleForm.removeAriaLabel', { + defaultMessage: 'Remove', + }), + getRequiredTooltip: () => + i18n.translate('xpack.canvas.argFormArgSimpleForm.requiredTooltip', { + defaultMessage: 'This argument is required, you should specify a value.', + }), +}; interface Props { children?: ReactNode; required?: boolean; diff --git a/x-pack/plugins/canvas/public/components/arg_form/pending_arg_value.js b/x-pack/plugins/canvas/public/components/arg_form/pending_arg_value.js index ff390a770f80..f933230f3992 100644 --- a/x-pack/plugins/canvas/public/components/arg_form/pending_arg_value.js +++ b/x-pack/plugins/canvas/public/components/arg_form/pending_arg_value.js @@ -7,11 +7,17 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; + import { Loading } from '../loading'; import { ArgLabel } from './arg_label'; -const { ArgFormPendingArgValue: strings } = ComponentStrings; +const strings = { + getLoadingMessage: () => + i18n.translate('xpack.canvas.argFormPendingArgValue.loadingMessage', { + defaultMessage: 'Loading', + }), +}; export class PendingArgValue extends React.PureComponent { static propTypes = { diff --git a/x-pack/plugins/canvas/public/components/arg_form/simple_failure.tsx b/x-pack/plugins/canvas/public/components/arg_form/simple_failure.tsx index cc4e92679a87..57173fa413e8 100644 --- a/x-pack/plugins/canvas/public/components/arg_form/simple_failure.tsx +++ b/x-pack/plugins/canvas/public/components/arg_form/simple_failure.tsx @@ -6,11 +6,17 @@ */ import React from 'react'; -import { TooltipIcon, IconType } from '../tooltip_icon'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../i18n'; +import { TooltipIcon, IconType } from '../tooltip_icon'; -const { ArgFormSimpleFailure: strings } = ComponentStrings; +const strings = { + getFailureTooltip: () => + i18n.translate('xpack.canvas.argFormSimpleFailure.failureTooltip', { + defaultMessage: + 'The interface for this argument could not parse the value, so a fallback input is being used', + }), +}; // This is what is being generated by render() from the Arg class. It is called in FunctionForm export const SimpleFailure = () => ( diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset.component.tsx b/x-pack/plugins/canvas/public/components/asset_manager/asset.component.tsx index 8f9d90ccbe1d..024137f64063 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset.component.tsx +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset.component.tsx @@ -17,6 +17,7 @@ import { EuiTextColor, EuiToolTip, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { useNotifyService } from '../../services'; @@ -25,9 +26,40 @@ import { Clipboard } from '../clipboard'; import { Download } from '../download'; import { AssetType } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; - -const { Asset: strings } = ComponentStrings; +const strings = { + getCopyAssetTooltip: () => + i18n.translate('xpack.canvas.asset.copyAssetTooltip', { + defaultMessage: 'Copy id to clipboard', + }), + getCreateImageTooltip: () => + i18n.translate('xpack.canvas.asset.createImageTooltip', { + defaultMessage: 'Create image element', + }), + getDeleteAssetTooltip: () => + i18n.translate('xpack.canvas.asset.deleteAssetTooltip', { + defaultMessage: 'Delete', + }), + getDownloadAssetTooltip: () => + i18n.translate('xpack.canvas.asset.downloadAssetTooltip', { + defaultMessage: 'Download', + }), + getThumbnailAltText: () => + i18n.translate('xpack.canvas.asset.thumbnailAltText', { + defaultMessage: 'Asset thumbnail', + }), + getConfirmModalButtonLabel: () => + i18n.translate('xpack.canvas.asset.confirmModalButtonLabel', { + defaultMessage: 'Remove', + }), + getConfirmModalMessageText: () => + i18n.translate('xpack.canvas.asset.confirmModalDetail', { + defaultMessage: 'Are you sure you want to remove this asset?', + }), + getConfirmModalTitle: () => + i18n.translate('xpack.canvas.asset.confirmModalTitle', { + defaultMessage: 'Remove Asset', + }), +}; export interface Props { /** The asset to be rendered */ diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx index 7795aa9671b8..7b004d5ab509 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx @@ -24,14 +24,47 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ASSET_MAX_SIZE } from '../../../common/lib/constants'; import { Loading } from '../loading'; import { Asset } from './asset'; import { AssetType } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; -const { AssetManager: strings } = ComponentStrings; +const strings = { + getDescription: () => + i18n.translate('xpack.canvas.assetModal.modalDescription', { + defaultMessage: + 'Below are the image assets in this workpad. Any assets that are currently in use cannot be determined at this time. To reclaim space, delete assets.', + }), + getEmptyAssetsDescription: () => + i18n.translate('xpack.canvas.assetModal.emptyAssetsDescription', { + defaultMessage: 'Import your assets to get started', + }), + getFilePickerPromptText: () => + i18n.translate('xpack.canvas.assetModal.filePickerPromptText', { + defaultMessage: 'Select or drag and drop images', + }), + getLoadingText: () => + i18n.translate('xpack.canvas.assetModal.loadingText', { + defaultMessage: 'Uploading images', + }), + getModalCloseButtonLabel: () => + i18n.translate('xpack.canvas.assetModal.modalCloseButtonLabel', { + defaultMessage: 'Close', + }), + getModalTitle: () => + i18n.translate('xpack.canvas.assetModal.modalTitle', { + defaultMessage: 'Manage workpad assets', + }), + getSpaceUsedText: (percentageUsed: number) => + i18n.translate('xpack.canvas.assetModal.spacedUsedText', { + defaultMessage: '{percentageUsed}% space used', + values: { + percentageUsed, + }, + }), +}; export interface Props { /** The assets to display within the modal */ diff --git a/x-pack/plugins/canvas/public/components/asset_picker/asset_picker.tsx b/x-pack/plugins/canvas/public/components/asset_picker/asset_picker.tsx index c2e2d8a05324..4bf13577aff5 100644 --- a/x-pack/plugins/canvas/public/components/asset_picker/asset_picker.tsx +++ b/x-pack/plugins/canvas/public/components/asset_picker/asset_picker.tsx @@ -8,12 +8,16 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGrid, EuiFlexItem, EuiLink, EuiImage, EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { CanvasAsset } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; - -const { AssetPicker: strings } = ComponentStrings; +const strings = { + getAssetAltText: () => + i18n.translate('xpack.canvas.assetpicker.assetAltText', { + defaultMessage: 'Asset thumbnail', + }), +}; interface Props { assets: CanvasAsset[]; diff --git a/x-pack/plugins/canvas/public/components/canvas_loading/canvas_loading.component.tsx b/x-pack/plugins/canvas/public/components/canvas_loading/canvas_loading.component.tsx index 38e62f46c945..8f55c3193329 100644 --- a/x-pack/plugins/canvas/public/components/canvas_loading/canvas_loading.component.tsx +++ b/x-pack/plugins/canvas/public/components/canvas_loading/canvas_loading.component.tsx @@ -7,9 +7,14 @@ import React, { FC } from 'react'; import { EuiPanel, EuiLoadingChart, EuiSpacer, EuiText } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n/components'; +import { i18n } from '@kbn/i18n'; -const { CanvasLoading: strings } = ComponentStrings; +const strings = { + getLoadingLabel: () => + i18n.translate('xpack.canvas.canvasLoading.loadingMessage', { + defaultMessage: 'Loading', + }), +}; export const CanvasLoading: FC<{ msg?: string }> = ({ msg = `${strings.getLoadingLabel()}...`, diff --git a/x-pack/plugins/canvas/public/components/color_manager/color_manager.tsx b/x-pack/plugins/canvas/public/components/color_manager/color_manager.tsx index ae5cfac85bdc..50c679c2a1e5 100644 --- a/x-pack/plugins/canvas/public/components/color_manager/color_manager.tsx +++ b/x-pack/plugins/canvas/public/components/color_manager/color_manager.tsx @@ -9,11 +9,24 @@ import React, { FC } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonIcon, EuiFieldText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import tinycolor from 'tinycolor2'; -import { ColorDot } from '../color_dot/color_dot'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../i18n/components'; +import { ColorDot } from '../color_dot/color_dot'; -const { ColorManager: strings } = ComponentStrings; +const strings = { + getAddAriaLabel: () => + i18n.translate('xpack.canvas.colorManager.addAriaLabel', { + defaultMessage: 'Add Color', + }), + getCodePlaceholder: () => + i18n.translate('xpack.canvas.colorManager.codePlaceholder', { + defaultMessage: 'Color code', + }), + getRemoveAriaLabel: () => + i18n.translate('xpack.canvas.colorManager.removeAriaLabel', { + defaultMessage: 'Remove Color', + }), +}; export interface Props { /** diff --git a/x-pack/plugins/canvas/public/components/custom_element_modal/custom_element_modal.tsx b/x-pack/plugins/canvas/public/components/custom_element_modal/custom_element_modal.tsx index 5d9cccba924a..86d9cab4eeea 100644 --- a/x-pack/plugins/canvas/public/components/custom_element_modal/custom_element_modal.tsx +++ b/x-pack/plugins/canvas/public/components/custom_element_modal/custom_element_modal.tsx @@ -26,16 +26,57 @@ import { EuiTextArea, EuiTitle, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { VALID_IMAGE_TYPES } from '../../../common/lib/constants'; import { encode } from '../../../common/lib/dataurl'; import { ElementCard } from '../element_card'; -import { ComponentStrings } from '../../../i18n/components'; const MAX_NAME_LENGTH = 40; const MAX_DESCRIPTION_LENGTH = 100; -const { CustomElementModal: strings } = ComponentStrings; - +const strings = { + getCancelButtonLabel: () => + i18n.translate('xpack.canvas.customElementModal.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + getCharactersRemainingDescription: (numberOfRemainingCharacter: number) => + i18n.translate('xpack.canvas.customElementModal.remainingCharactersDescription', { + defaultMessage: '{numberOfRemainingCharacter} characters remaining', + values: { + numberOfRemainingCharacter, + }, + }), + getDescriptionInputLabel: () => + i18n.translate('xpack.canvas.customElementModal.descriptionInputLabel', { + defaultMessage: 'Description', + }), + getElementPreviewTitle: () => + i18n.translate('xpack.canvas.customElementModal.elementPreviewTitle', { + defaultMessage: 'Element preview', + }), + getImageFilePickerPlaceholder: () => + i18n.translate('xpack.canvas.customElementModal.imageFilePickerPlaceholder', { + defaultMessage: 'Select or drag and drop an image', + }), + getImageInputDescription: () => + i18n.translate('xpack.canvas.customElementModal.imageInputDescription', { + defaultMessage: + 'Take a screenshot of your element and upload it here. This can also be done after saving.', + }), + getImageInputLabel: () => + i18n.translate('xpack.canvas.customElementModal.imageInputLabel', { + defaultMessage: 'Thumbnail image', + }), + getNameInputLabel: () => + i18n.translate('xpack.canvas.customElementModal.nameInputLabel', { + defaultMessage: 'Name', + }), + getSaveButtonLabel: () => + i18n.translate('xpack.canvas.customElementModal.saveButtonLabel', { + defaultMessage: 'Save', + }), +}; interface Props { /** * initial value of the name of the custom element diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js index faddc3a60b99..f09ce4c92582 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js @@ -18,13 +18,27 @@ import { EuiHorizontalRule, } from '@elastic/eui'; import { isEqual } from 'lodash'; -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; + import { getDefaultIndex } from '../../lib/es_service'; import { DatasourceSelector } from './datasource_selector'; import { DatasourcePreview } from './datasource_preview'; -const { DatasourceDatasourceComponent: strings } = ComponentStrings; - +const strings = { + getExpressionArgDescription: () => + i18n.translate('xpack.canvas.datasourceDatasourceComponent.expressionArgDescription', { + defaultMessage: + 'The datasource has an argument controlled by an expression. Use the expression editor to modify the datasource.', + }), + getPreviewButtonLabel: () => + i18n.translate('xpack.canvas.datasourceDatasourceComponent.previewButtonLabel', { + defaultMessage: 'Preview data', + }), + getSaveButtonLabel: () => + i18n.translate('xpack.canvas.datasourceDatasourceComponent.saveButtonLabel', { + defaultMessage: 'Save', + }), +}; export class DatasourceComponent extends PureComponent { static propTypes = { args: PropTypes.object.isRequired, diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js index a55f73a08746..2eb42c5cb98d 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js @@ -18,12 +18,33 @@ import { EuiSpacer, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + import { Datatable } from '../../datatable'; import { Error } from '../../error'; -import { ComponentStrings } from '../../../../i18n'; -const { DatasourceDatasourcePreview: strings } = ComponentStrings; -const { DatasourceDatasourceComponent: datasourceStrings } = ComponentStrings; +const strings = { + getEmptyFirstLineDescription: () => + i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptyFirstLineDescription', { + defaultMessage: "We couldn't find any documents matching your search criteria.", + }), + getEmptySecondLineDescription: () => + i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptySecondLineDescription', { + defaultMessage: 'Check your datasource settings and try again.', + }), + getEmptyTitle: () => + i18n.translate('xpack.canvas.datasourceDatasourcePreview.emptyTitle', { + defaultMessage: 'No documents found', + }), + getModalTitle: () => + i18n.translate('xpack.canvas.datasourceDatasourcePreview.modalTitle', { + defaultMessage: 'Datasource preview', + }), + getSaveButtonLabel: () => + i18n.translate('xpack.canvas.datasourceDatasourcePreview.saveButtonLabel', { + defaultMessage: 'Save', + }), +}; export const DatasourcePreview = ({ done, datatable }) => ( @@ -37,7 +58,7 @@ export const DatasourcePreview = ({ done, datatable }) => ( id="xpack.canvas.datasourceDatasourcePreview.modalDescription" defaultMessage="The following data will be available to the selected element upon clicking {saveLabel} in the sidebar." values={{ - saveLabel: {datasourceStrings.getSaveButtonLabel()}, + saveLabel: {strings.getSaveButtonLabel()}, }} />

diff --git a/x-pack/plugins/canvas/public/components/datasource/no_datasource.js b/x-pack/plugins/canvas/public/components/datasource/no_datasource.js index ef86361a4a3a..f496d493e9d9 100644 --- a/x-pack/plugins/canvas/public/components/datasource/no_datasource.js +++ b/x-pack/plugins/canvas/public/components/datasource/no_datasource.js @@ -8,9 +8,19 @@ import React from 'react'; import PropTypes from 'prop-types'; import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../i18n'; -const { DatasourceNoDatasource: strings } = ComponentStrings; +const strings = { + getPanelDescription: () => + i18n.translate('xpack.canvas.datasourceNoDatasource.panelDescription', { + defaultMessage: + "This element does not have an attached data source. This is usually because the element is an image or other static asset. If that's not the case you might want to check your expression to make sure it is not malformed.", + }), + getPanelTitle: () => + i18n.translate('xpack.canvas.datasourceNoDatasource.panelTitle', { + defaultMessage: 'No data source present', + }), +}; export const NoDatasource = () => (
diff --git a/x-pack/plugins/canvas/public/components/element_config/element_config.tsx b/x-pack/plugins/canvas/public/components/element_config/element_config.tsx index 683c12f13f0f..bf09ac3c5ab7 100644 --- a/x-pack/plugins/canvas/public/components/element_config/element_config.tsx +++ b/x-pack/plugins/canvas/public/components/element_config/element_config.tsx @@ -5,13 +5,42 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiAccordion } from '@elastic/eui'; -import PropTypes from 'prop-types'; import React from 'react'; -import { ComponentStrings } from '../../../i18n'; +import PropTypes from 'prop-types'; +import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiAccordion } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { State } from '../../../types'; -const { ElementConfig: strings } = ComponentStrings; +const strings = { + getFailedLabel: () => + i18n.translate('xpack.canvas.elementConfig.failedLabel', { + defaultMessage: 'Failed', + description: + 'The label for the total number of elements in a workpad that have thrown an error or failed to load', + }), + getLoadedLabel: () => + i18n.translate('xpack.canvas.elementConfig.loadedLabel', { + defaultMessage: 'Loaded', + description: 'The label for the number of elements in a workpad that have loaded', + }), + getProgressLabel: () => + i18n.translate('xpack.canvas.elementConfig.progressLabel', { + defaultMessage: 'Progress', + description: 'The label for the percentage of elements that have finished loading', + }), + getTitle: () => + i18n.translate('xpack.canvas.elementConfig.title', { + defaultMessage: 'Element status', + description: + '"Elements" refers to the individual text, images, or visualizations that you can add to a Canvas workpad', + }), + getTotalLabel: () => + i18n.translate('xpack.canvas.elementConfig.totalLabel', { + defaultMessage: 'Total', + description: 'The label for the total number of elements in a workpad', + }), +}; interface Props { elementStats: State['transient']['elementStats']; diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index c86b1d6405e2..716f757b7c25 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -7,15 +7,24 @@ import React, { FC } from 'react'; import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { SavedObjectFinderUi, SavedObjectMetaData, } from '../../../../../../src/plugins/saved_objects/public/'; -import { ComponentStrings } from '../../../i18n'; import { useServices } from '../../services'; -const { AddEmbeddableFlyout: strings } = ComponentStrings; - +const strings = { + getNoItemsText: () => + i18n.translate('xpack.canvas.embedObject.noMatchingObjectsMessage', { + defaultMessage: 'No matching objects found.', + }), + getTitleText: () => + i18n.translate('xpack.canvas.embedObject.titleText', { + defaultMessage: 'Add from Kibana', + }), +}; export interface Props { onClose: () => void; onSelect: (id: string, embeddableType: string) => void; diff --git a/x-pack/plugins/canvas/public/components/error/error.tsx b/x-pack/plugins/canvas/public/components/error/error.tsx index b4cc85ba336e..cb2c2cd5d58c 100644 --- a/x-pack/plugins/canvas/public/components/error/error.tsx +++ b/x-pack/plugins/canvas/public/components/error/error.tsx @@ -8,18 +8,27 @@ import React, { FC } from 'react'; import PropTypes from 'prop-types'; import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { ComponentStrings } from '../../../i18n'; + import { ShowDebugging } from './show_debugging'; +const strings = { + getDescription: () => + i18n.translate('xpack.canvas.errorComponent.description', { + defaultMessage: 'Expression failed with the message:', + }), + getTitle: () => + i18n.translate('xpack.canvas.errorComponent.title', { + defaultMessage: 'Whoops! Expression failed', + }), +}; export interface Props { payload: { error: Error; }; } -const { Error: strings } = ComponentStrings; - export const Error: FC = ({ payload }) => { const message = get(payload, 'error.message'); diff --git a/x-pack/plugins/canvas/public/components/expression/element_not_selected.js b/x-pack/plugins/canvas/public/components/expression/element_not_selected.js index c7c8c1b063cf..5f717af6101c 100644 --- a/x-pack/plugins/canvas/public/components/expression/element_not_selected.js +++ b/x-pack/plugins/canvas/public/components/expression/element_not_selected.js @@ -8,9 +8,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import { EuiButton } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; -const { ExpressionElementNotSelected: strings } = ComponentStrings; +const strings = { + getCloseButtonLabel: () => + i18n.translate('xpack.canvas.expressionElementNotSelected.closeButtonLabel', { + defaultMessage: 'Close', + }), + getSelectDescription: () => + i18n.translate('xpack.canvas.expressionElementNotSelected.selectDescription', { + defaultMessage: 'Select an element to show expression input', + }), +}; export const ElementNotSelected = ({ done }) => (
diff --git a/x-pack/plugins/canvas/public/components/expression/expression.tsx b/x-pack/plugins/canvas/public/components/expression/expression.tsx index 74fdefc322cc..ff3fed32c0ac 100644 --- a/x-pack/plugins/canvas/public/components/expression/expression.tsx +++ b/x-pack/plugins/canvas/public/components/expression/expression.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, MutableRefObject } from 'react'; +import React, { FC, MutableRefObject, useRef } from 'react'; import PropTypes from 'prop-types'; import { EuiPanel, @@ -17,17 +17,46 @@ import { EuiLink, EuiPortal, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + // @ts-expect-error import { Shortcuts } from 'react-shortcuts'; -import { ComponentStrings } from '../../../i18n'; + import { ExpressionInput } from '../expression_input'; import { ToolTipShortcut } from '../tool_tip_shortcut'; import { ExpressionFunction } from '../../../types'; import { FormState } from './'; -const { Expression: strings } = ComponentStrings; - -const { useRef } = React; +const strings = { + getCancelButtonLabel: () => + i18n.translate('xpack.canvas.expression.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + getCloseButtonLabel: () => + i18n.translate('xpack.canvas.expression.closeButtonLabel', { + defaultMessage: 'Close', + }), + getLearnLinkText: () => + i18n.translate('xpack.canvas.expression.learnLinkText', { + defaultMessage: 'Learn expression syntax', + }), + getMaximizeButtonLabel: () => + i18n.translate('xpack.canvas.expression.maximizeButtonLabel', { + defaultMessage: 'Maximize editor', + }), + getMinimizeButtonLabel: () => + i18n.translate('xpack.canvas.expression.minimizeButtonLabel', { + defaultMessage: 'Minimize Editor', + }), + getRunButtonLabel: () => + i18n.translate('xpack.canvas.expression.runButtonLabel', { + defaultMessage: 'Run', + }), + getRunTooltip: () => + i18n.translate('xpack.canvas.expression.runTooltip', { + defaultMessage: 'Run the expression', + }), +}; const shortcut = ( ref: MutableRefObject, diff --git a/x-pack/plugins/canvas/public/components/expression_input/reference.ts b/x-pack/plugins/canvas/public/components/expression_input/reference.ts index 95d27360aafc..94a369e6cb8d 100644 --- a/x-pack/plugins/canvas/public/components/expression_input/reference.ts +++ b/x-pack/plugins/canvas/public/components/expression_input/reference.ts @@ -5,13 +5,64 @@ * 2.0. */ -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; import { ExpressionFunction, ExpressionFunctionParameter, } from '../../../../../../src/plugins/expressions'; -const { ExpressionInput: strings } = ComponentStrings; +import { BOLD_MD_TOKEN } from '../../../i18n/constants'; + +const strings = { + getArgReferenceAliasesDetail: (aliases: string) => + i18n.translate('xpack.canvas.expressionInput.argReferenceAliasesDetail', { + defaultMessage: '{BOLD_MD_TOKEN}Aliases{BOLD_MD_TOKEN}: {aliases}', + values: { + BOLD_MD_TOKEN, + aliases, + }, + }), + getArgReferenceDefaultDetail: (defaultVal: string) => + i18n.translate('xpack.canvas.expressionInput.argReferenceDefaultDetail', { + defaultMessage: '{BOLD_MD_TOKEN}Default{BOLD_MD_TOKEN}: {defaultVal}', + values: { + BOLD_MD_TOKEN, + defaultVal, + }, + }), + getArgReferenceRequiredDetail: (required: string) => + i18n.translate('xpack.canvas.expressionInput.argReferenceRequiredDetail', { + defaultMessage: '{BOLD_MD_TOKEN}Required{BOLD_MD_TOKEN}: {required}', + values: { + BOLD_MD_TOKEN, + required, + }, + }), + getArgReferenceTypesDetail: (types: string) => + i18n.translate('xpack.canvas.expressionInput.argReferenceTypesDetail', { + defaultMessage: '{BOLD_MD_TOKEN}Types{BOLD_MD_TOKEN}: {types}', + values: { + BOLD_MD_TOKEN, + types, + }, + }), + getFunctionReferenceAcceptsDetail: (acceptTypes: string) => + i18n.translate('xpack.canvas.expressionInput.functionReferenceAccepts', { + defaultMessage: '{BOLD_MD_TOKEN}Accepts{BOLD_MD_TOKEN}: {acceptTypes}', + values: { + BOLD_MD_TOKEN, + acceptTypes, + }, + }), + getFunctionReferenceReturnsDetail: (returnType: string) => + i18n.translate('xpack.canvas.expressionInput.functionReferenceReturns', { + defaultMessage: '{BOLD_MD_TOKEN}Returns{BOLD_MD_TOKEN}: {returnType}', + values: { + BOLD_MD_TOKEN, + returnType, + }, + }), +}; /** * Given an expression function, this function returns a markdown string diff --git a/x-pack/plugins/canvas/public/components/function_form/function_form_context_error.tsx b/x-pack/plugins/canvas/public/components/function_form/function_form_context_error.tsx index a022f98d14e1..2ee709edbf91 100644 --- a/x-pack/plugins/canvas/public/components/function_form/function_form_context_error.tsx +++ b/x-pack/plugins/canvas/public/components/function_form/function_form_context_error.tsx @@ -7,16 +7,23 @@ import React, { FunctionComponent } from 'react'; import PropTypes from 'prop-types'; -import { ComponentStrings } from '../../../i18n/components'; +import { i18n } from '@kbn/i18n'; +const strings = { + getContextErrorMessage: (errorMessage: string) => + i18n.translate('xpack.canvas.functionForm.contextError', { + defaultMessage: 'ERROR: {errorMessage}', + values: { + errorMessage, + }, + }), +}; interface Props { context: { error: string; }; } -const { FunctionFormContextError: strings } = ComponentStrings; - export const FunctionFormContextError: FunctionComponent = ({ context }) => (
{strings.getContextErrorMessage(context.error)} diff --git a/x-pack/plugins/canvas/public/components/function_form/function_unknown.tsx b/x-pack/plugins/canvas/public/components/function_form/function_unknown.tsx index b3054e280bbe..cd7e2f27912a 100644 --- a/x-pack/plugins/canvas/public/components/function_form/function_unknown.tsx +++ b/x-pack/plugins/canvas/public/components/function_form/function_unknown.tsx @@ -7,13 +7,22 @@ import React, { FunctionComponent } from 'react'; import PropTypes from 'prop-types'; -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; + +const strings = { + getUnknownArgumentTypeErrorMessage: (expressionType: string) => + i18n.translate('xpack.canvas.functionForm.functionUnknown.unknownArgumentTypeError', { + defaultMessage: 'Unknown expression type "{expressionType}"', + values: { + expressionType, + }, + }), +}; interface Props { /** the type of the argument */ argType: string; } -const { FunctionFormFunctionUnknown: strings } = ComponentStrings; export const FunctionUnknown: FunctionComponent = ({ argType }) => (
diff --git a/x-pack/plugins/canvas/public/components/help_menu/help_menu.tsx b/x-pack/plugins/canvas/public/components/help_menu/help_menu.tsx index b10103e1824e..2877ccf41056 100644 --- a/x-pack/plugins/canvas/public/components/help_menu/help_menu.tsx +++ b/x-pack/plugins/canvas/public/components/help_menu/help_menu.tsx @@ -7,11 +7,13 @@ import React, { FC, useState, lazy, Suspense } from 'react'; import { EuiButtonEmpty, EuiPortal, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ExpressionFunction } from 'src/plugins/expressions'; -import { ComponentStrings } from '../../../i18n'; + import { KeyboardShortcutsDoc } from '../keyboard_shortcuts_doc'; let FunctionReferenceGenerator: null | React.LazyExoticComponent = null; + if (process.env.NODE_ENV === 'development') { FunctionReferenceGenerator = lazy(() => import('../function_reference_generator').then((module) => ({ @@ -20,7 +22,12 @@ if (process.env.NODE_ENV === 'development') { ); } -const { HelpMenu: strings } = ComponentStrings; +const strings = { + getKeyboardShortcutsLinkLabel: () => + i18n.translate('xpack.canvas.helpMenu.keyboardShortcutsLinkLabel', { + defaultMessage: 'Keyboard shortcuts', + }), +}; interface Props { functionRegistry: Record; diff --git a/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/keyboard_shortcuts_doc.tsx b/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/keyboard_shortcuts_doc.tsx index 0c98ea70b5b9..a71976006d51 100644 --- a/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/keyboard_shortcuts_doc.tsx +++ b/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/keyboard_shortcuts_doc.tsx @@ -17,14 +17,30 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { keymap } from '../../lib/keymap'; import { ShortcutMap, ShortcutNameSpace } from '../../../types/shortcuts'; import { getClientPlatform } from '../../lib/get_client_platform'; import { getId } from '../../lib/get_id'; import { getPrettyShortcut } from '../../lib/get_pretty_shortcut'; -import { ComponentStrings } from '../../../i18n/components'; -const { KeyboardShortcutsDoc: strings } = ComponentStrings; +const strings = { + getFlyoutCloseButtonAriaLabel: () => + i18n.translate('xpack.canvas.keyboardShortcutsDoc.flyout.closeButtonAriaLabel', { + defaultMessage: 'Closes keyboard shortcuts reference', + }), + getShortcutSeparator: () => + i18n.translate('xpack.canvas.keyboardShortcutsDoc.shortcutListSeparator', { + defaultMessage: 'or', + description: + 'Separates which keyboard shortcuts can be used for a single action. Example: "{shortcut1} or {shortcut2} or {shortcut3}"', + }), + getTitle: () => + i18n.translate('xpack.canvas.keyboardShortcutsDoc.flyoutHeaderTitle', { + defaultMessage: 'Keyboard shortcuts', + }), +}; interface DescriptionListItem { title: string; diff --git a/x-pack/plugins/canvas/public/components/page_config/index.js b/x-pack/plugins/canvas/public/components/page_config/index.js index 59f0ac99fd73..898ac60e68e3 100644 --- a/x-pack/plugins/canvas/public/components/page_config/index.js +++ b/x-pack/plugins/canvas/public/components/page_config/index.js @@ -7,13 +7,22 @@ import { connect } from 'react-redux'; import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; + import { transitionsRegistry } from '../../lib/transitions_registry'; import { getSelectedPageIndex, getPages } from '../../state/selectors/workpad'; import { stylePage, setPageTransition } from '../../state/actions/pages'; -import { ComponentStrings } from '../../../i18n'; import { PageConfig as Component } from './page_config'; -const { PageConfig: strings } = ComponentStrings; +const strings = { + getNoTransitionDropDownOptionLabel: () => + i18n.translate('xpack.canvas.pageConfig.transitions.noneDropDownOptionLabel', { + defaultMessage: 'None', + description: + 'This is the option the user should choose if they do not want any page transition (i.e. fade in, fade out, etc) to ' + + 'be applied to the current page.', + }), +}; const mapStateToProps = (state) => { const pageIndex = getSelectedPageIndex(state); diff --git a/x-pack/plugins/canvas/public/components/page_config/page_config.js b/x-pack/plugins/canvas/public/components/page_config/page_config.js index bc7d92de2273..8b0c2fedf3af 100644 --- a/x-pack/plugins/canvas/public/components/page_config/page_config.js +++ b/x-pack/plugins/canvas/public/components/page_config/page_config.js @@ -16,10 +16,35 @@ import { EuiToolTip, EuiIcon, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { WorkpadColorPicker } from '../workpad_color_picker'; -import { ComponentStrings } from '../../../i18n'; -const { PageConfig: strings } = ComponentStrings; +const strings = { + getBackgroundColorDescription: () => + i18n.translate('xpack.canvas.pageConfig.backgroundColorDescription', { + defaultMessage: 'Accepts HEX, RGB or HTML color names', + }), + getBackgroundColorLabel: () => + i18n.translate('xpack.canvas.pageConfig.backgroundColorLabel', { + defaultMessage: 'Background', + }), + getTitle: () => + i18n.translate('xpack.canvas.pageConfig.title', { + defaultMessage: 'Page settings', + }), + getTransitionLabel: () => + i18n.translate('xpack.canvas.pageConfig.transitionLabel', { + defaultMessage: 'Transition', + description: + 'This refers to the transition effect, such as fade in or rotate, applied to a page in presentation mode.', + }), + getTransitionPreviewLabel: () => + i18n.translate('xpack.canvas.pageConfig.transitionPreviewLabel', { + defaultMessage: 'Preview', + description: 'This is the label for a preview of the transition effect selected.', + }), +}; export const PageConfig = ({ pageIndex, diff --git a/x-pack/plugins/canvas/public/components/page_manager/page_manager.component.tsx b/x-pack/plugins/canvas/public/components/page_manager/page_manager.component.tsx index 06968d2e4be0..9d1939db43fd 100644 --- a/x-pack/plugins/canvas/public/components/page_manager/page_manager.component.tsx +++ b/x-pack/plugins/canvas/public/components/page_manager/page_manager.component.tsx @@ -8,7 +8,9 @@ import React, { Fragment, Component } from 'react'; import PropTypes from 'prop-types'; import { EuiIcon, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { DragDropContext, Droppable, Draggable, DragDropContextProps } from 'react-beautiful-dnd'; + // @ts-expect-error untyped dependency import Style from 'style-it'; import { ConfirmModal } from '../confirm_modal'; @@ -16,11 +18,26 @@ import { RoutingLink } from '../routing'; import { WorkpadRoutingContext } from '../../routes/workpad'; import { PagePreview } from '../page_preview'; -import { ComponentStrings } from '../../../i18n'; import { CanvasPage } from '../../../types'; -const { PageManager: strings } = ComponentStrings; - +const strings = { + getAddPageTooltip: () => + i18n.translate('xpack.canvas.pageManager.addPageTooltip', { + defaultMessage: 'Add a new page to this workpad', + }), + getConfirmRemoveTitle: () => + i18n.translate('xpack.canvas.pageManager.confirmRemoveTitle', { + defaultMessage: 'Remove Page', + }), + getConfirmRemoveDescription: () => + i18n.translate('xpack.canvas.pageManager.confirmRemoveDescription', { + defaultMessage: 'Are you sure you want to remove this page?', + }), + getConfirmRemoveButtonLabel: () => + i18n.translate('xpack.canvas.pageManager.removeButtonLabel', { + defaultMessage: 'Remove', + }), +}; export interface Props { isWriteable: boolean; onAddPage: () => void; diff --git a/x-pack/plugins/canvas/public/components/page_preview/page_controls.tsx b/x-pack/plugins/canvas/public/components/page_preview/page_controls.tsx index b29ef1e7fd08..5246fcf822a7 100644 --- a/x-pack/plugins/canvas/public/components/page_preview/page_controls.tsx +++ b/x-pack/plugins/canvas/public/components/page_preview/page_controls.tsx @@ -8,10 +8,26 @@ import React, { FC, ReactEventHandler } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../i18n'; - -const { PagePreviewPageControls: strings } = ComponentStrings; +const strings = { + getClonePageAriaLabel: () => + i18n.translate('xpack.canvas.pagePreviewPageControls.clonePageAriaLabel', { + defaultMessage: 'Clone page', + }), + getClonePageTooltip: () => + i18n.translate('xpack.canvas.pagePreviewPageControls.clonePageTooltip', { + defaultMessage: 'Clone', + }), + getDeletePageAriaLabel: () => + i18n.translate('xpack.canvas.pagePreviewPageControls.deletePageAriaLabel', { + defaultMessage: 'Delete page', + }), + getDeletePageTooltip: () => + i18n.translate('xpack.canvas.pagePreviewPageControls.deletePageTooltip', { + defaultMessage: 'Delete', + }), +}; interface Props { pageId: string; diff --git a/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx b/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx index 7ad7bcd8c49c..dcc77b75f25c 100644 --- a/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx +++ b/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx @@ -8,10 +8,20 @@ import React, { FC } from 'react'; import PropTypes from 'prop-types'; import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { palettes, ColorPalette } from '../../../common/lib/palettes'; -import { ComponentStrings } from '../../../i18n'; -const { PalettePicker: strings } = ComponentStrings; +const strings = { + getEmptyPaletteLabel: () => + i18n.translate('xpack.canvas.palettePicker.emptyPaletteLabel', { + defaultMessage: 'None', + }), + getNoPaletteFoundErrorTitle: () => + i18n.translate('xpack.canvas.palettePicker.noPaletteFoundErrorTitle', { + defaultMessage: 'Color palette not found', + }), +}; interface RequiredProps { id?: string; diff --git a/x-pack/plugins/canvas/public/components/saved_elements_modal/element_controls.tsx b/x-pack/plugins/canvas/public/components/saved_elements_modal/element_controls.tsx index 220ea193c902..ad0a0053f55a 100644 --- a/x-pack/plugins/canvas/public/components/saved_elements_modal/element_controls.tsx +++ b/x-pack/plugins/canvas/public/components/saved_elements_modal/element_controls.tsx @@ -8,9 +8,26 @@ import React, { FunctionComponent, MouseEvent } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n/components'; +import { i18n } from '@kbn/i18n'; -const { ElementControls: strings } = ComponentStrings; +const strings = { + getDeleteAriaLabel: () => + i18n.translate('xpack.canvas.elementControls.deleteAriaLabel', { + defaultMessage: 'Delete element', + }), + getDeleteTooltip: () => + i18n.translate('xpack.canvas.elementControls.deleteToolTip', { + defaultMessage: 'Delete', + }), + getEditAriaLabel: () => + i18n.translate('xpack.canvas.elementControls.editAriaLabel', { + defaultMessage: 'Edit element', + }), + getEditTooltip: () => + i18n.translate('xpack.canvas.elementControls.editToolTip', { + defaultMessage: 'Edit', + }), +}; interface Props { /** diff --git a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx index bc0039245f43..ee14e89dc4b7 100644 --- a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx +++ b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx @@ -25,14 +25,59 @@ import { EuiSpacer, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { sortBy } from 'lodash'; -import { ComponentStrings } from '../../../i18n'; import { CustomElement } from '../../../types'; import { ConfirmModal } from '../confirm_modal/confirm_modal'; import { CustomElementModal } from '../custom_element_modal'; import { ElementGrid } from './element_grid'; -const { SavedElementsModal: strings } = ComponentStrings; +const strings = { + getAddNewElementDescription: () => + i18n.translate('xpack.canvas.savedElementsModal.addNewElementDescription', { + defaultMessage: 'Group and save workpad elements to create new elements', + }), + getAddNewElementTitle: () => + i18n.translate('xpack.canvas.savedElementsModal.addNewElementTitle', { + defaultMessage: 'Add new elements', + }), + getCancelButtonLabel: () => + i18n.translate('xpack.canvas.savedElementsModal.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + getDeleteButtonLabel: () => + i18n.translate('xpack.canvas.savedElementsModal.deleteButtonLabel', { + defaultMessage: 'Delete', + }), + getDeleteElementDescription: () => + i18n.translate('xpack.canvas.savedElementsModal.deleteElementDescription', { + defaultMessage: 'Are you sure you want to delete this element?', + }), + getDeleteElementTitle: (elementName: string) => + i18n.translate('xpack.canvas.savedElementsModal.deleteElementTitle', { + defaultMessage: `Delete element '{elementName}'?`, + values: { + elementName, + }, + }), + getEditElementTitle: () => + i18n.translate('xpack.canvas.savedElementsModal.editElementTitle', { + defaultMessage: 'Edit element', + }), + getFindElementPlaceholder: () => + i18n.translate('xpack.canvas.savedElementsModal.findElementPlaceholder', { + defaultMessage: 'Find element', + }), + getModalTitle: () => + i18n.translate('xpack.canvas.savedElementsModal.modalTitle', { + defaultMessage: 'My elements', + }), + getSavedElementsModalCloseButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeader.addElementModalCloseButtonLabel', { + defaultMessage: 'Close', + }), +}; export interface Props { /** diff --git a/x-pack/plugins/canvas/public/components/sidebar/element_settings/element_settings.component.tsx b/x-pack/plugins/canvas/public/components/sidebar/element_settings/element_settings.component.tsx index cc0ad5a728b1..e8f2c7a559f5 100644 --- a/x-pack/plugins/canvas/public/components/sidebar/element_settings/element_settings.component.tsx +++ b/x-pack/plugins/canvas/public/components/sidebar/element_settings/element_settings.component.tsx @@ -8,12 +8,28 @@ import React, { FunctionComponent } from 'react'; import PropTypes from 'prop-types'; import { EuiTabbedContent } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + // @ts-expect-error unconverted component import { Datasource } from '../../datasource'; // @ts-expect-error unconverted component import { FunctionFormList } from '../../function_form_list'; import { PositionedElement } from '../../../../types'; -import { ComponentStrings } from '../../../../i18n'; + +const strings = { + getDataTabLabel: () => + i18n.translate('xpack.canvas.elementSettings.dataTabLabel', { + defaultMessage: 'Data', + description: + 'This tab contains the settings for the data (i.e. Elasticsearch query) used as ' + + 'the source for a Canvas element', + }), + getDisplayTabLabel: () => + i18n.translate('xpack.canvas.elementSettings.displayTabLabel', { + defaultMessage: 'Display', + description: 'This tab contains the settings for how data is displayed in a Canvas element', + }), +}; interface Props { /** @@ -22,8 +38,6 @@ interface Props { element: PositionedElement; } -const { ElementSettings: strings } = ComponentStrings; - export const ElementSettings: FunctionComponent = ({ element }) => { const tabs = [ { diff --git a/x-pack/plugins/canvas/public/components/sidebar/group_settings.tsx b/x-pack/plugins/canvas/public/components/sidebar/group_settings.tsx index e13cf338a2bd..9d95a6978ff5 100644 --- a/x-pack/plugins/canvas/public/components/sidebar/group_settings.tsx +++ b/x-pack/plugins/canvas/public/components/sidebar/group_settings.tsx @@ -7,9 +7,21 @@ import React, { FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n/components'; +import { i18n } from '@kbn/i18n'; -const { GroupSettings: strings } = ComponentStrings; +const strings = { + getSaveGroupDescription: () => + i18n.translate('xpack.canvas.groupSettings.saveGroupDescription', { + defaultMessage: 'Save this group as a new element to re-use it throughout your workpad.', + }), + getUngroupDescription: () => + i18n.translate('xpack.canvas.groupSettings.ungroupDescription', { + defaultMessage: 'Ungroup ({uKey}) to edit individual element settings.', + values: { + uKey: 'U', + }, + }), +}; export const GroupSettings: FunctionComponent = () => (
diff --git a/x-pack/plugins/canvas/public/components/sidebar/multi_element_settings.tsx b/x-pack/plugins/canvas/public/components/sidebar/multi_element_settings.tsx index f3bd11f60324..0d73e6397adc 100644 --- a/x-pack/plugins/canvas/public/components/sidebar/multi_element_settings.tsx +++ b/x-pack/plugins/canvas/public/components/sidebar/multi_element_settings.tsx @@ -7,9 +7,23 @@ import React, { FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n/components'; +import { i18n } from '@kbn/i18n'; -const { MultiElementSettings: strings } = ComponentStrings; +const strings = { + getMultipleElementsActionsDescription: () => + i18n.translate('xpack.canvas.groupSettings.multipleElementsActionsDescription', { + defaultMessage: + 'Deselect these elements to edit their individual settings, press ({gKey}) to group them, or save this selection as a new ' + + 'element to re-use it throughout your workpad.', + values: { + gKey: 'G', + }, + }), + getMultipleElementsDescription: () => + i18n.translate('xpack.canvas.groupSettings.multipleElementsDescription', { + defaultMessage: 'Multiple elements are currently selected.', + }), +}; export const MultiElementSettings: FunctionComponent = () => (
diff --git a/x-pack/plugins/canvas/public/components/sidebar/sidebar_content.js b/x-pack/plugins/canvas/public/components/sidebar/sidebar_content.js index a284fc327843..7292a98fa91a 100644 --- a/x-pack/plugins/canvas/public/components/sidebar/sidebar_content.js +++ b/x-pack/plugins/canvas/public/components/sidebar/sidebar_content.js @@ -9,15 +9,39 @@ import React, { Fragment } from 'react'; import { connect } from 'react-redux'; import { compose, branch, renderComponent } from 'recompose'; import { EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { getSelectedToplevelNodes, getSelectedElementId } from '../../state/selectors/workpad'; import { SidebarHeader } from '../sidebar_header'; -import { ComponentStrings } from '../../../i18n'; import { MultiElementSettings } from './multi_element_settings'; import { GroupSettings } from './group_settings'; import { GlobalConfig } from './global_config'; import { ElementSettings } from './element_settings'; -const { SidebarContent: strings } = ComponentStrings; +const strings = { + getGroupedElementSidebarTitle: () => + i18n.translate('xpack.canvas.sidebarContent.groupedElementSidebarTitle', { + defaultMessage: 'Grouped element', + description: + 'The title displayed when a grouped element is selected. "elements" refer to the different visualizations, images, ' + + 'text, etc that can be added in a Canvas workpad. These elements can be grouped into a larger "grouped element" ' + + 'that contains multiple individual elements.', + }), + getMultiElementSidebarTitle: () => + i18n.translate('xpack.canvas.sidebarContent.multiElementSidebarTitle', { + defaultMessage: 'Multiple elements', + description: + 'The title displayed when multiple elements are selected. "elements" refer to the different visualizations, images, ' + + 'text, etc that can be added in a Canvas workpad.', + }), + getSingleElementSidebarTitle: () => + i18n.translate('xpack.canvas.sidebarContent.singleElementSidebarTitle', { + defaultMessage: 'Selected element', + description: + 'The title displayed when a single element are selected. "element" refer to the different visualizations, images, ' + + 'text, etc that can be added in a Canvas workpad.', + }), +}; const mapStateToProps = (state) => ({ selectedToplevelNodes: getSelectedToplevelNodes(state), diff --git a/x-pack/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx b/x-pack/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx index d4f8c7642830..4ba3a7f90f64 100644 --- a/x-pack/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx +++ b/x-pack/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx @@ -8,11 +8,30 @@ import React, { FunctionComponent } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { ToolTipShortcut } from '../tool_tip_shortcut/'; -import { ComponentStrings } from '../../../i18n/components'; import { ShortcutStrings } from '../../../i18n/shortcuts'; -const { SidebarHeader: strings } = ComponentStrings; +const strings = { + getBringForwardAriaLabel: () => + i18n.translate('xpack.canvas.sidebarHeader.bringForwardArialLabel', { + defaultMessage: 'Move element up one layer', + }), + getBringToFrontAriaLabel: () => + i18n.translate('xpack.canvas.sidebarHeader.bringToFrontArialLabel', { + defaultMessage: 'Move element to top layer', + }), + getSendBackwardAriaLabel: () => + i18n.translate('xpack.canvas.sidebarHeader.sendBackwardArialLabel', { + defaultMessage: 'Move element down one layer', + }), + getSendToBackAriaLabel: () => + i18n.translate('xpack.canvas.sidebarHeader.sendToBackArialLabel', { + defaultMessage: 'Move element to bottom layer', + }), +}; + const shortcutHelp = ShortcutStrings.getShortcutHelp(); interface Props { diff --git a/x-pack/plugins/canvas/public/components/text_style_picker/text_style_picker.tsx b/x-pack/plugins/canvas/public/components/text_style_picker/text_style_picker.tsx index 51b9cf7d6026..8d4a1506ad8a 100644 --- a/x-pack/plugins/canvas/public/components/text_style_picker/text_style_picker.tsx +++ b/x-pack/plugins/canvas/public/components/text_style_picker/text_style_picker.tsx @@ -8,13 +8,51 @@ import React, { FC, useState } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiSelect, EuiSpacer, EuiButtonGroup } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FontValue } from 'src/plugins/expressions'; -import { ComponentStrings } from '../../../i18n'; + import { FontPicker } from '../font_picker'; import { ColorPickerPopover } from '../color_picker_popover'; import { fontSizes } from './font_sizes'; -const { TextStylePicker: strings } = ComponentStrings; +const strings = { + getAlignCenterOption: () => + i18n.translate('xpack.canvas.textStylePicker.alignCenterOption', { + defaultMessage: 'Align center', + }), + getAlignLeftOption: () => + i18n.translate('xpack.canvas.textStylePicker.alignLeftOption', { + defaultMessage: 'Align left', + }), + getAlignRightOption: () => + i18n.translate('xpack.canvas.textStylePicker.alignRightOption', { + defaultMessage: 'Align right', + }), + getAlignmentOptionsControlLegend: () => + i18n.translate('xpack.canvas.textStylePicker.alignmentOptionsControl', { + defaultMessage: 'Alignment options', + }), + getFontColorLabel: () => + i18n.translate('xpack.canvas.textStylePicker.fontColorLabel', { + defaultMessage: 'Font Color', + }), + getStyleBoldOption: () => + i18n.translate('xpack.canvas.textStylePicker.styleBoldOption', { + defaultMessage: 'Bold', + }), + getStyleItalicOption: () => + i18n.translate('xpack.canvas.textStylePicker.styleItalicOption', { + defaultMessage: 'Italic', + }), + getStyleUnderlineOption: () => + i18n.translate('xpack.canvas.textStylePicker.styleUnderlineOption', { + defaultMessage: 'Underline', + }), + getStyleOptionsControlLegend: () => + i18n.translate('xpack.canvas.textStylePicker.styleOptionsControl', { + defaultMessage: 'Style options', + }), +}; export interface StyleProps { family?: FontValue; diff --git a/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx b/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx index 9e89ad4c4f27..13cc4db7c621 100644 --- a/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx +++ b/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx @@ -8,18 +8,39 @@ import React, { FC, useState, useContext, useEffect } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { PageManager } from '../page_manager'; import { Expression } from '../expression'; import { Tray } from './tray'; import { CanvasElement } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; import { RoutingButtonIcon } from '../routing'; import { WorkpadRoutingContext } from '../../routes/workpad'; -const { Toolbar: strings } = ComponentStrings; +const strings = { + getEditorButtonLabel: () => + i18n.translate('xpack.canvas.toolbar.editorButtonLabel', { + defaultMessage: 'Expression editor', + }), + getNextPageAriaLabel: () => + i18n.translate('xpack.canvas.toolbar.nextPageAriaLabel', { + defaultMessage: 'Next Page', + }), + getPageButtonLabel: (pageNum: number, totalPages: number) => + i18n.translate('xpack.canvas.toolbar.pageButtonLabel', { + defaultMessage: 'Page {pageNum}{rest}', + values: { + pageNum, + rest: totalPages > 1 ? ` of ${totalPages}` : '', + }, + }), + getPreviousPageAriaLabel: () => + i18n.translate('xpack.canvas.toolbar.previousPageAriaLabel', { + defaultMessage: 'Previous Page', + }), +}; type TrayType = 'pageManager' | 'expression'; diff --git a/x-pack/plugins/canvas/public/components/toolbar/tray/tray.tsx b/x-pack/plugins/canvas/public/components/toolbar/tray/tray.tsx index 0230eb86e121..bc6eb455bb9b 100644 --- a/x-pack/plugins/canvas/public/components/toolbar/tray/tray.tsx +++ b/x-pack/plugins/canvas/public/components/toolbar/tray/tray.tsx @@ -8,9 +8,14 @@ import React, { ReactNode, MouseEventHandler } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../../i18n'; -const { ToolbarTray: strings } = ComponentStrings; +const strings = { + getCloseTrayAriaLabel: () => + i18n.translate('xpack.canvas.toolbarTray.closeTrayAriaLabel', { + defaultMessage: 'Close tray', + }), +}; interface Props { children: ReactNode; diff --git a/x-pack/plugins/canvas/public/components/var_config/delete_var.tsx b/x-pack/plugins/canvas/public/components/var_config/delete_var.tsx index 69b3306d85ea..f6ba2d7e2882 100644 --- a/x-pack/plugins/canvas/public/components/var_config/delete_var.tsx +++ b/x-pack/plugins/canvas/public/components/var_config/delete_var.tsx @@ -15,10 +15,29 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { CanvasVariable } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; -const { VarConfigDeleteVar: strings } = ComponentStrings; +const strings = { + getCancelButtonLabel: () => + i18n.translate('xpack.canvas.varConfigDeleteVar.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + getDeleteButtonLabel: () => + i18n.translate('xpack.canvas.varConfigDeleteVar.deleteButtonLabel', { + defaultMessage: 'Delete variable', + }), + getTitle: () => + i18n.translate('xpack.canvas.varConfigDeleteVar.titleLabel', { + defaultMessage: 'Delete variable?', + }), + getWarningDescription: () => + i18n.translate('xpack.canvas.varConfigDeleteVar.warningDescription', { + defaultMessage: + 'Deleting this variable may adversely affect the workpad. Are you sure you wish to continue?', + }), +}; import './var_panel.scss'; diff --git a/x-pack/plugins/canvas/public/components/var_config/edit_var.tsx b/x-pack/plugins/canvas/public/components/var_config/edit_var.tsx index 64ec8af29144..35f9e67745ae 100644 --- a/x-pack/plugins/canvas/public/components/var_config/edit_var.tsx +++ b/x-pack/plugins/canvas/public/components/var_config/edit_var.tsx @@ -20,12 +20,61 @@ import { EuiSpacer, EuiCallOut, } from '@elastic/eui'; -import { CanvasVariable } from '../../../types'; +import { i18n } from '@kbn/i18n'; +import { CanvasVariable } from '../../../types'; import { VarValueField } from './var_value_field'; -import { ComponentStrings } from '../../../i18n'; -const { VarConfigEditVar: strings } = ComponentStrings; +const strings = { + getAddTitle: () => + i18n.translate('xpack.canvas.varConfigEditVar.addTitleLabel', { + defaultMessage: 'Add variable', + }), + getCancelButtonLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + getDuplicateNameError: () => + i18n.translate('xpack.canvas.varConfigEditVar.duplicateNameError', { + defaultMessage: 'Variable name already in use', + }), + getEditTitle: () => + i18n.translate('xpack.canvas.varConfigEditVar.editTitleLabel', { + defaultMessage: 'Edit variable', + }), + getEditWarning: () => + i18n.translate('xpack.canvas.varConfigEditVar.editWarning', { + defaultMessage: 'Editing a variable in use may adversely affect your workpad', + }), + getNameFieldLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.nameFieldLabel', { + defaultMessage: 'Name', + }), + getSaveButtonLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.saveButtonLabel', { + defaultMessage: 'Save changes', + }), + getTypeBooleanLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.typeBooleanLabel', { + defaultMessage: 'Boolean', + }), + getTypeFieldLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.typeFieldLabel', { + defaultMessage: 'Type', + }), + getTypeNumberLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.typeNumberLabel', { + defaultMessage: 'Number', + }), + getTypeStringLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.typeStringLabel', { + defaultMessage: 'String', + }), + getValueFieldLabel: () => + i18n.translate('xpack.canvas.varConfigEditVar.valueFieldLabel', { + defaultMessage: 'Value', + }), +}; import './edit_var.scss'; import './var_panel.scss'; diff --git a/x-pack/plugins/canvas/public/components/var_config/index.tsx b/x-pack/plugins/canvas/public/components/var_config/index.tsx index 3f072e2f9514..db2a84e93a5d 100644 --- a/x-pack/plugins/canvas/public/components/var_config/index.tsx +++ b/x-pack/plugins/canvas/public/components/var_config/index.tsx @@ -7,12 +7,22 @@ import React, { FC } from 'react'; import copy from 'copy-to-clipboard'; +import { i18n } from '@kbn/i18n'; + import { VarConfig as ChildComponent } from './var_config'; import { useNotifyService } from '../../services'; -import { ComponentStrings } from '../../../i18n'; import { CanvasVariable } from '../../../types'; -const { VarConfig: strings } = ComponentStrings; +const strings = { + getCopyNotificationDescription: () => + i18n.translate('xpack.canvas.varConfig.copyNotificationDescription', { + defaultMessage: 'Variable syntax copied to clipboard', + }), + getDeleteNotificationDescription: () => + i18n.translate('xpack.canvas.varConfig.deleteNotificationDescription', { + defaultMessage: 'Variable successfully deleted', + }), +}; interface Props { variables: CanvasVariable[]; diff --git a/x-pack/plugins/canvas/public/components/var_config/var_config.tsx b/x-pack/plugins/canvas/public/components/var_config/var_config.tsx index 0fe506715d07..dc8898e2132e 100644 --- a/x-pack/plugins/canvas/public/components/var_config/var_config.tsx +++ b/x-pack/plugins/canvas/public/components/var_config/var_config.tsx @@ -18,17 +18,15 @@ import { EuiSpacer, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { CanvasVariable } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; import { EditVar } from './edit_var'; import { DeleteVar } from './delete_var'; import './var_config.scss'; -const { VarConfig: strings } = ComponentStrings; - enum PanelMode { List, Edit, @@ -49,6 +47,58 @@ interface Props { onEditVar: (oldVar: CanvasVariable, newVar: CanvasVariable) => void; } +const strings = { + getAddButtonLabel: () => + i18n.translate('xpack.canvas.varConfig.addButtonLabel', { + defaultMessage: 'Add a variable', + }), + getAddTooltipLabel: () => + i18n.translate('xpack.canvas.varConfig.addTooltipLabel', { + defaultMessage: 'Add a variable', + }), + getCopyActionButtonLabel: () => + i18n.translate('xpack.canvas.varConfig.copyActionButtonLabel', { + defaultMessage: 'Copy snippet', + }), + getCopyActionTooltipLabel: () => + i18n.translate('xpack.canvas.varConfig.copyActionTooltipLabel', { + defaultMessage: 'Copy variable syntax to clipboard', + }), + getDeleteActionButtonLabel: () => + i18n.translate('xpack.canvas.varConfig.deleteActionButtonLabel', { + defaultMessage: 'Delete variable', + }), + getEditActionButtonLabel: () => + i18n.translate('xpack.canvas.varConfig.editActionButtonLabel', { + defaultMessage: 'Edit variable', + }), + getEmptyDescription: () => + i18n.translate('xpack.canvas.varConfig.emptyDescription', { + defaultMessage: + 'This workpad has no variables currently. You may add variables to store and edit common values. These variables can then be used in elements or within the expression editor.', + }), + getTableNameLabel: () => + i18n.translate('xpack.canvas.varConfig.tableNameLabel', { + defaultMessage: 'Name', + }), + getTableTypeLabel: () => + i18n.translate('xpack.canvas.varConfig.tableTypeLabel', { + defaultMessage: 'Type', + }), + getTableValueLabel: () => + i18n.translate('xpack.canvas.varConfig.tableValueLabel', { + defaultMessage: 'Value', + }), + getTitle: () => + i18n.translate('xpack.canvas.varConfig.titleLabel', { + defaultMessage: 'Variables', + }), + getTitleTooltip: () => + i18n.translate('xpack.canvas.varConfig.titleTooltip', { + defaultMessage: 'Add variables to store and edit common values', + }), +}; + export const VarConfig: FC = ({ variables, onCopyVar, diff --git a/x-pack/plugins/canvas/public/components/var_config/var_value_field.tsx b/x-pack/plugins/canvas/public/components/var_config/var_value_field.tsx index c89164dc6efd..1232ba3977d7 100644 --- a/x-pack/plugins/canvas/public/components/var_config/var_value_field.tsx +++ b/x-pack/plugins/canvas/public/components/var_config/var_value_field.tsx @@ -8,11 +8,24 @@ import React, { FC } from 'react'; import { EuiFieldText, EuiFieldNumber, EuiButtonGroup } from '@elastic/eui'; import { htmlIdGenerator } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { CanvasVariable } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; -const { VarConfigVarValueField: strings } = ComponentStrings; +const strings = { + getBooleanOptionsLegend: () => + i18n.translate('xpack.canvas.varConfigVarValueField.booleanOptionsLegend', { + defaultMessage: 'Boolean value', + }), + getFalseOption: () => + i18n.translate('xpack.canvas.varConfigVarValueField.falseOption', { + defaultMessage: 'False', + }), + getTrueOption: () => + i18n.translate('xpack.canvas.varConfigVarValueField.trueOption', { + defaultMessage: 'True', + }), +}; interface Props { type: CanvasVariable['type']; diff --git a/x-pack/plugins/canvas/public/components/workpad_color_picker/workpad_color_picker.component.tsx b/x-pack/plugins/canvas/public/components/workpad_color_picker/workpad_color_picker.component.tsx index cc6271e376c0..0561ac005519 100644 --- a/x-pack/plugins/canvas/public/components/workpad_color_picker/workpad_color_picker.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_color_picker/workpad_color_picker.component.tsx @@ -6,10 +6,15 @@ */ import React from 'react'; +import { i18n } from '@kbn/i18n'; import { ColorPickerPopover, Props } from '../color_picker_popover'; -import { ComponentStrings } from '../../../i18n'; -const { WorkpadConfig: strings } = ComponentStrings; +const strings = { + getBackgroundColorLabel: () => + i18n.translate('xpack.canvas.workpadConfig.backgroundColorLabel', { + defaultMessage: 'Background color', + }), +}; export const WorkpadColorPicker = (props: Props) => { return ( diff --git a/x-pack/plugins/canvas/public/components/workpad_config/workpad_config.component.tsx b/x-pack/plugins/canvas/public/components/workpad_config/workpad_config.component.tsx index 2776280d17b3..18e3f2dac977 100644 --- a/x-pack/plugins/canvas/public/components/workpad_config/workpad_config.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_config/workpad_config.component.tsx @@ -22,14 +22,70 @@ import { EuiAccordion, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { VarConfig } from '../var_config'; - import { DEFAULT_WORKPAD_CSS } from '../../../common/lib/constants'; import { CanvasVariable } from '../../../types'; -import { ComponentStrings } from '../../../i18n'; -const { WorkpadConfig: strings } = ComponentStrings; +const strings = { + getApplyStylesheetButtonLabel: () => + i18n.translate('xpack.canvas.workpadConfig.applyStylesheetButtonLabel', { + defaultMessage: `Apply stylesheet`, + description: '"stylesheet" refers to the collection of CSS style rules entered by the user.', + }), + getFlipDimensionAriaLabel: () => + i18n.translate('xpack.canvas.workpadConfig.swapDimensionsAriaLabel', { + defaultMessage: `Swap the page's width and height`, + }), + getFlipDimensionTooltip: () => + i18n.translate('xpack.canvas.workpadConfig.swapDimensionsTooltip', { + defaultMessage: 'Swap the width and height', + }), + getGlobalCSSLabel: () => + i18n.translate('xpack.canvas.workpadConfig.globalCSSLabel', { + defaultMessage: `Global CSS overrides`, + }), + getGlobalCSSTooltip: () => + i18n.translate('xpack.canvas.workpadConfig.globalCSSTooltip', { + defaultMessage: `Apply styles to all pages in this workpad`, + }), + getNameLabel: () => + i18n.translate('xpack.canvas.workpadConfig.nameLabel', { + defaultMessage: 'Name', + }), + getPageHeightLabel: () => + i18n.translate('xpack.canvas.workpadConfig.heightLabel', { + defaultMessage: 'Height', + }), + getPageSizeBadgeAriaLabel: (sizeName: string) => + i18n.translate('xpack.canvas.workpadConfig.pageSizeBadgeAriaLabel', { + defaultMessage: `Preset page size: {sizeName}`, + values: { + sizeName, + }, + }), + getPageSizeBadgeOnClickAriaLabel: (sizeName: string) => + i18n.translate('xpack.canvas.workpadConfig.pageSizeBadgeOnClickAriaLabel', { + defaultMessage: `Set page size to {sizeName}`, + values: { + sizeName, + }, + }), + getPageWidthLabel: () => + i18n.translate('xpack.canvas.workpadConfig.widthLabel', { + defaultMessage: 'Width', + }), + getTitle: () => + i18n.translate('xpack.canvas.workpadConfig.title', { + defaultMessage: 'Workpad settings', + }), + getUSLetterButtonLabel: () => + i18n.translate('xpack.canvas.workpadConfig.USLetterButtonLabel', { + defaultMessage: 'US Letter', + description: 'This is referring to the dimensions of U.S. standard letter paper.', + }), +}; export interface Props { size: { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.component.tsx index cb66eceac97c..c78bdb2a7882 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.component.tsx @@ -8,7 +8,8 @@ import React, { Fragment, FunctionComponent, useState } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonEmpty, EuiContextMenu, EuiIcon } from '@elastic/eui'; -import { ComponentStrings } from '../../../../i18n/components'; +import { i18n } from '@kbn/i18n'; + import { ShortcutStrings } from '../../../../i18n/shortcuts'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { Popover, ClosePopoverFn } from '../../popover'; @@ -16,8 +17,95 @@ import { CustomElementModal } from '../../custom_element_modal'; import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib/constants'; import { PositionedElement } from '../../../../types'; -const { WorkpadHeaderEditMenu: strings } = ComponentStrings; const shortcutHelp = ShortcutStrings.getShortcutHelp(); +const strings = { + getAlignmentMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.alignmentMenuItemLabel', { + defaultMessage: 'Alignment', + description: + 'This refers to the vertical (i.e. left, center, right) and horizontal (i.e. top, middle, bottom) ' + + 'alignment options of the selected elements', + }), + getBottomAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.bottomAlignMenuItemLabel', { + defaultMessage: 'Bottom', + }), + getCenterAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.centerAlignMenuItemLabel', { + defaultMessage: 'Center', + description: 'This refers to alignment centered horizontally.', + }), + getCreateElementModalTitle: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.createElementModalTitle', { + defaultMessage: 'Create new element', + }), + getDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.distributionMenutItemLabel', { + defaultMessage: 'Distribution', + description: + 'This refers to the options to evenly spacing the selected elements horizontall or vertically.', + }), + getEditMenuButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuButtonLabel', { + defaultMessage: 'Edit', + }), + getEditMenuLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuLabel', { + defaultMessage: 'Edit options', + }), + getGroupMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.groupMenuItemLabel', { + defaultMessage: 'Group', + description: 'This refers to grouping multiple selected elements.', + }), + getHorizontalDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.horizontalDistributionMenutItemLabel', { + defaultMessage: 'Horizontal', + }), + getLeftAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.leftAlignMenuItemLabel', { + defaultMessage: 'Left', + }), + getMiddleAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.middleAlignMenuItemLabel', { + defaultMessage: 'Middle', + description: 'This refers to alignment centered vertically.', + }), + getOrderMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.orderMenuItemLabel', { + defaultMessage: 'Order', + description: 'Refers to the order of the elements displayed on the page from front to back', + }), + getRedoMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.redoMenuItemLabel', { + defaultMessage: 'Redo', + }), + getRightAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.rightAlignMenuItemLabel', { + defaultMessage: 'Right', + }), + getSaveElementMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.savedElementMenuItemLabel', { + defaultMessage: 'Save as new element', + }), + getTopAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.topAlignMenuItemLabel', { + defaultMessage: 'Top', + }), + getUndoMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.undoMenuItemLabel', { + defaultMessage: 'Undo', + }), + getUngroupMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.ungroupMenuItemLabel', { + defaultMessage: 'Ungroup', + description: 'This refers to ungrouping a grouped element', + }), + getVerticalDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.verticalDistributionMenutItemLabel', { + defaultMessage: 'Vertical', + }), +}; export interface Props { /** diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx index 19414f7c8d96..e1d69163e076 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx @@ -14,8 +14,9 @@ import { EuiIcon, EuiContextMenuPanelItemDescriptor, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib'; -import { ComponentStrings } from '../../../../i18n/components'; import { ElementSpec } from '../../../../types'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { getId } from '../../../lib/get_id'; @@ -31,7 +32,56 @@ interface ElementTypeMeta { [key: string]: { name: string; icon: string }; } -export const { WorkpadHeaderElementMenu: strings } = ComponentStrings; +const strings = { + getAssetsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.manageAssetsMenuItemLabel', { + defaultMessage: 'Manage assets', + }), + getChartMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.chartMenuItemLabel', { + defaultMessage: 'Chart', + }), + getElementMenuButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.elementMenuButtonLabel', { + defaultMessage: 'Add element', + }), + getElementMenuLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.elementMenuLabel', { + defaultMessage: 'Add an element', + }), + getEmbedObjectMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.embedObjectMenuItemLabel', { + defaultMessage: 'Add from Kibana', + }), + getFilterMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.filterMenuItemLabel', { + defaultMessage: 'Filter', + }), + getImageMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.imageMenuItemLabel', { + defaultMessage: 'Image', + }), + getMyElementsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.myElementsMenuItemLabel', { + defaultMessage: 'My elements', + }), + getOtherMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.otherMenuItemLabel', { + defaultMessage: 'Other', + }), + getProgressMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.progressMenuItemLabel', { + defaultMessage: 'Progress', + }), + getShapeMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.shapeMenuItemLabel', { + defaultMessage: 'Shape', + }), + getTextMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderElementMenu.textMenuItemLabel', { + defaultMessage: 'Text', + }), +}; // label and icon for the context menu item for each element type const elementTypeMeta: ElementTypeMeta = { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx index eea59e6aa49f..fde21c7c85c3 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx @@ -7,15 +7,21 @@ import React, { useState } from 'react'; import { EuiButtonEmpty, EuiNotificationBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { LazyLabsFlyout, withSuspense, } from '../../../../../../../src/plugins/presentation_util/public'; -import { ComponentStrings } from '../../../../i18n'; import { useLabsService } from '../../../services'; -const { LabsControl: strings } = ComponentStrings; + +const strings = { + getLabsButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderLabsControlSettings.labsButtonLabel', { + defaultMessage: 'Labs', + }), +}; const Flyout = withSuspense(LazyLabsFlyout, null); diff --git a/x-pack/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.component.tsx index dd9ddc2707ba..7b1df158087b 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.component.tsx @@ -8,10 +8,20 @@ import React, { MouseEventHandler } from 'react'; import PropTypes from 'prop-types'; import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { ToolTipShortcut } from '../../tool_tip_shortcut'; -import { ComponentStrings } from '../../../../i18n'; -const { WorkpadHeaderRefreshControlSettings: strings } = ComponentStrings; +const strings = { + getRefreshAriaLabel: () => + i18n.translate('xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel', { + defaultMessage: 'Refresh Elements', + }), + getRefreshTooltip: () => + i18n.translate('xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip', { + defaultMessage: 'Refresh data', + }), +}; export interface Props { doRefresh: MouseEventHandler; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.component.tsx index 7c90a6fb045b..5da009e050a2 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.component.tsx @@ -21,16 +21,46 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ComponentStrings } from '../../../../../i18n/components'; import { ZIP, CANVAS, HTML } from '../../../../../i18n/constants'; import { OnCloseFn } from '../share_menu.component'; import { WorkpadStep } from './workpad_step'; import { RuntimeStep } from './runtime_step'; import { SnippetsStep } from './snippets_step'; -const { ShareWebsiteFlyout: strings } = ComponentStrings; +const strings = { + getRuntimeStepTitle: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.downloadRuntimeTitle', { + defaultMessage: 'Download runtime', + }), + getSnippentsStepTitle: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.addSnippetsTitle', { + defaultMessage: 'Add snippets to website', + }), + getStepsDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.description', { + defaultMessage: + 'Follow these steps to share a static version of this workpad on an external website. It will be a visual snapshot of the current workpad, and will not have access to live data.', + }), + getTitle: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.flyoutTitle', { + defaultMessage: 'Share on a website', + }), + getUnsupportedRendererWarning: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.unsupportedRendererWarning', { + defaultMessage: + 'This workpad contains render functions that are not supported by the {CANVAS} Shareable Workpad Runtime. These elements will not be rendered:', + values: { + CANVAS, + }, + }), + getWorkpadStepTitle: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.downloadWorkpadTitle', { + defaultMessage: 'Download workpad', + }), +}; export type OnDownloadFn = (type: 'share' | 'shareRuntime' | 'shareZip') => void; export type OnCopyFn = () => void; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.ts b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.ts index 05d0070a5ea6..65c9d6598578 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/flyout.ts @@ -7,6 +7,8 @@ import { connect } from 'react-redux'; import { compose, withProps } from 'recompose'; +import { i18n } from '@kbn/i18n'; + import { getWorkpad, getRenderedWorkpad, @@ -24,14 +26,35 @@ import { arrayBufferFetch } from '../../../../../common/lib/fetch'; import { API_ROUTE_SHAREABLE_ZIP } from '../../../../../common/lib/constants'; import { renderFunctionNames } from '../../../../../shareable_runtime/supported_renderers'; -import { ComponentStrings } from '../../../../../i18n/components'; import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/'; import { OnCloseFn } from '../share_menu.component'; +import { ZIP } from '../../../../../i18n/constants'; import { WithKibanaProps } from '../../../../index'; export { OnDownloadFn, OnCopyFn } from './flyout.component'; -const { WorkpadHeaderShareMenu: strings } = ComponentStrings; +const strings = { + getCopyShareConfigMessage: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage', { + defaultMessage: 'Copied share markup to clipboard', + }), + getShareableZipErrorTitle: (workpadName: string) => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWebsiteErrorTitle', { + defaultMessage: + "Failed to create {ZIP} file for '{workpadName}'. The workpad may be too large. You'll need to download the files separately.", + values: { + ZIP, + workpadName, + }, + }), + getUnknownExportErrorMessage: (type: string) => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.unknownExportErrorMessage', { + defaultMessage: 'Unknown export type: {type}', + values: { + type, + }, + }), +}; const getUnsupportedRenderers = (state: State) => { const renderers: string[] = []; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/runtime_step.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/runtime_step.tsx index c686c403a9a4..8b2fe1a1c039 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/runtime_step.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/runtime_step.tsx @@ -7,12 +7,26 @@ import React, { FC } from 'react'; import { EuiText, EuiSpacer, EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../../../i18n/components'; +import { CANVAS } from '../../../../../i18n/constants'; import { OnDownloadFn } from './flyout'; -const { ShareWebsiteRuntimeStep: strings } = ComponentStrings; +const strings = { + getDownloadLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.runtimeStep.downloadLabel', { + defaultMessage: 'Download runtime', + }), + getStepDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.runtimeStep.description', { + defaultMessage: + 'In order to render a Shareable Workpad, you also need to include the {CANVAS} Shareable Workpad Runtime. You can skip this step if the runtime is already included on your website.', + values: { + CANVAS, + }, + }), +}; export const RuntimeStep: FC<{ onDownload: OnDownloadFn }> = ({ onDownload }) => ( diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/snippets_step.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/snippets_step.tsx index bc9f123c623f..1bac3068e7db 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/snippets_step.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/snippets_step.tsx @@ -16,13 +16,91 @@ import { EuiDescriptionListDescription, EuiHorizontalRule, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../../../i18n/components'; +import { CANVAS, URL, JSON } from '../../../../../i18n/constants'; import { Clipboard } from '../../../clipboard'; import { OnCopyFn } from './flyout'; -const { ShareWebsiteSnippetsStep: strings } = ComponentStrings; +const strings = { + getAutoplayParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.autoplayParameterDescription', { + defaultMessage: 'Should the runtime automatically move through the pages of the workpad?', + }), + getCallRuntimeLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.callRuntimeLabel', { + defaultMessage: 'Call Runtime', + }), + getHeightParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.heightParameterDescription', { + defaultMessage: 'The height of the Workpad. Defaults to the Workpad height.', + }), + getIncludeRuntimeLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.includeRuntimeLabel', { + defaultMessage: 'Include Runtime', + }), + getIntervalParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.intervalParameterDescription', { + defaultMessage: + 'The interval upon which the pages will advance in time format, (e.g. {twoSeconds}, {oneMinute})', + values: { + twoSeconds: '2s', + oneMinute: '1m', + }, + }), + getPageParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.pageParameterDescription', { + defaultMessage: 'The page to display. Defaults to the page specified by the Workpad.', + }), + getParametersDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.parametersDescription', { + defaultMessage: 'There are a number of inline parameters to configure the Shareable Workpad.', + }), + getParametersTitle: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.parametersLabel', { + defaultMessage: 'Parameters', + }), + getPlaceholderLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.placeholderLabel', { + defaultMessage: 'Placeholder', + }), + getRequiredLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.requiredLabel', { + defaultMessage: 'required', + }), + getShareableParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.shareableParameterDescription', { + defaultMessage: 'The type of shareable. In this case, a {CANVAS} Workpad.', + values: { + CANVAS, + }, + }), + getSnippetsStepDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.description', { + defaultMessage: + 'The Workpad is placed within the {HTML} of the site by using an {HTML} placeholder. Parameters for the runtime are included inline. See the full list of parameters below. You can include more than one workpad on the page.', + values: { + HTML, + }, + }), + getToolbarParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.toolbarParameterDescription', { + defaultMessage: 'Should the toolbar be hidden?', + }), + getUrlParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.urlParameterDescription', { + defaultMessage: 'The {URL} of the Shareable Workpad {JSON} file.', + values: { + URL, + JSON, + }, + }), + getWidthParameterDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.snippetsStep.widthParameterDescription', { + defaultMessage: 'The width of the Workpad. Defaults to the Workpad width.', + }), +}; const HTML = ` diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/workpad_step.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/workpad_step.tsx index c5a6a4478c76..3ab358d0fe32 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/workpad_step.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/workpad_step.tsx @@ -7,12 +7,26 @@ import React, { FC } from 'react'; import { EuiText, EuiSpacer, EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { ComponentStrings } from '../../../../../i18n/components'; +import { JSON } from '../../../../../i18n/constants'; import { OnDownloadFn } from './flyout'; -const { ShareWebsiteWorkpadStep: strings } = ComponentStrings; +const strings = { + getDownloadLabel: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.workpadStep.downloadLabel', { + defaultMessage: 'Download workpad', + }), + getStepDescription: () => + i18n.translate('xpack.canvas.shareWebsiteFlyout.workpadStep.description', { + defaultMessage: + 'The workpad will be exported as a single {JSON} file for sharing in another site.', + values: { + JSON, + }, + }), +}; export const WorkpadStep: FC<{ onDownload: OnDownloadFn }> = ({ onDownload }) => ( diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.component.tsx index d4cb4d0736bb..5ccc09bf3586 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.component.tsx @@ -5,18 +5,47 @@ * 2.0. */ +import React, { FunctionComponent, useState } from 'react'; +import PropTypes from 'prop-types'; import { EuiButtonEmpty, EuiContextMenu, EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { IBasePath } from 'kibana/public'; -import PropTypes from 'prop-types'; -import React, { FunctionComponent, useState } from 'react'; + import { ReportingStart } from '../../../../../reporting/public'; -import { ComponentStrings } from '../../../../i18n/components'; +import { PDF, JSON } from '../../../../i18n/constants'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { ClosePopoverFn, Popover } from '../../popover'; import { ShareWebsiteFlyout } from './flyout'; import { CanvasWorkpadSharingData, getPdfJobParams } from './utils'; -const { WorkpadHeaderShareMenu: strings } = ComponentStrings; +const strings = { + getShareDownloadJSONTitle: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle', { + defaultMessage: 'Download as {JSON}', + values: { + JSON, + }, + }), + getShareDownloadPDFTitle: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle', { + defaultMessage: '{PDF} reports', + values: { + PDF, + }, + }), + getShareMenuButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareMenuButtonLabel', { + defaultMessage: 'Share', + }), + getShareWebsiteTitle: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWebsiteTitle', { + defaultMessage: 'Share on a website', + }), + getShareWorkpadMessage: () => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWorkpadMessage', { + defaultMessage: 'Share this workpad', + }), +}; type CopyTypes = 'pdf' | 'reportingConfig'; type ExportTypes = 'pdf' | 'json'; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.ts b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.ts index fc4906817cf6..ef13655b66ac 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.ts @@ -7,14 +7,23 @@ import { connect } from 'react-redux'; import { compose, withProps } from 'recompose'; -import { ComponentStrings } from '../../../../i18n'; +import { i18n } from '@kbn/i18n'; + import { CanvasWorkpad, State } from '../../../../types'; import { downloadWorkpad } from '../../../lib/download_workpad'; import { withServices, WithServicesProps } from '../../../services'; import { getPages, getWorkpad } from '../../../state/selectors/workpad'; import { Props as ComponentProps, ShareMenu as Component } from './share_menu.component'; -const { WorkpadHeaderShareMenu: strings } = ComponentStrings; +const strings = { + getUnknownExportErrorMessage: (type: string) => + i18n.translate('xpack.canvas.workpadHeaderShareMenu.unknownExportErrorMessage', { + defaultMessage: 'Unknown export type: {type}', + values: { + type, + }, + }), +}; const mapStateToProps = (state: State) => ({ workpad: getWorkpad(state), diff --git a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx index 1508f8683b8c..6815ef351e0b 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx @@ -22,14 +22,34 @@ import { EuiToolTip, htmlIdGenerator, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { timeDuration } from '../../../lib/time_duration'; +import { UnitStrings } from '../../../../i18n'; import { CustomInterval } from './custom_interval'; -import { ComponentStrings, UnitStrings } from '../../../../i18n'; -const { WorkpadHeaderAutoRefreshControls: strings } = ComponentStrings; const { time: timeStrings } = UnitStrings; const { getSecondsText, getMinutesText, getHoursText } = timeStrings; +const strings = { + getDisableTooltip: () => + i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.disableTooltip', { + defaultMessage: 'Disable auto-refresh', + }), + getIntervalFormLabelText: () => + i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.intervalFormLabel', { + defaultMessage: 'Change auto-refresh interval', + }), + getRefreshListDurationManualText: () => + i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.refreshListDurationManualText', { + defaultMessage: 'Manually', + }), + getRefreshListTitle: () => + i18n.translate('xpack.canvas.workpadHeaderAutoRefreshControls.refreshListTitle', { + defaultMessage: 'Refresh elements', + }), +}; + interface Props { refreshInterval: number; setRefresh: (interval: number) => void; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx index d4d28d19131f..284749340e44 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx @@ -8,12 +8,31 @@ import React, { useState, ChangeEvent } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiButton, EuiFieldText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ButtonSize } from '@elastic/eui/src/components/button/button'; import { FlexGroupGutterSize } from '@elastic/eui/src/components/flex/flex_group'; import { getTimeInterval } from '../../../lib/time_interval'; -import { ComponentStrings } from '../../../../i18n'; -const { WorkpadHeaderCustomInterval: strings } = ComponentStrings; +const strings = { + getButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderCustomInterval.confirmButtonLabel', { + defaultMessage: 'Set', + }), + getFormDescription: () => + i18n.translate('xpack.canvas.workpadHeaderCustomInterval.formDescription', { + defaultMessage: + 'Use shorthand notation, like {secondsExample}, {minutesExample}, or {hoursExample}', + values: { + secondsExample: '30s', + minutesExample: '10m', + hoursExample: '1h', + }, + }), + getFormLabel: () => + i18n.translate('xpack.canvas.workpadHeaderCustomInterval.formLabel', { + defaultMessage: 'Set a custom interval', + }), +}; interface Props { gutterSize: FlexGroupGutterSize; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx index 55373d7a3515..b8ed80c870f2 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx @@ -22,14 +22,34 @@ import { EuiFlexGroup, htmlIdGenerator, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { timeDuration } from '../../../lib/time_duration'; +import { UnitStrings } from '../../../../i18n'; import { CustomInterval } from './custom_interval'; -import { ComponentStrings, UnitStrings } from '../../../../i18n'; -const { WorkpadHeaderKioskControls: strings } = ComponentStrings; const { time: timeStrings } = UnitStrings; const { getSecondsText, getMinutesText } = timeStrings; +const strings = { + getCycleFormLabel: () => + i18n.translate('xpack.canvas.workpadHeaderKioskControl.cycleFormLabel', { + defaultMessage: 'Change cycling interval', + }), + getTitle: () => + i18n.translate('xpack.canvas.workpadHeaderKioskControl.controlTitle', { + defaultMessage: 'Cycle fullscreen pages', + }), + getAutoplayListDurationManualText: () => + i18n.translate('xpack.canvas.workpadHeaderKioskControl.autoplayListDurationManual', { + defaultMessage: 'Manually', + }), + getDisableTooltip: () => + i18n.translate('xpack.canvas.workpadHeaderKioskControl.disableTooltip', { + defaultMessage: 'Disable auto-play', + }), +}; + interface Props { autoplayInterval: number; onSetInterval: (interval: number) => void; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx index 8fb24c1f3c62..168ddc690c4d 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx @@ -13,18 +13,80 @@ import { EuiIcon, EuiContextMenuPanelItemDescriptor, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, CONTEXT_MENU_TOP_BORDER_CLASSNAME, } from '../../../../common/lib/constants'; -import { ComponentStrings } from '../../../../i18n/components'; + import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { Popover, ClosePopoverFn } from '../../popover'; import { AutoRefreshControls } from './auto_refresh_controls'; import { KioskControls } from './kiosk_controls'; -const { WorkpadHeaderViewMenu: strings } = ComponentStrings; +const strings = { + getAutoplaySettingsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplaySettingsMenuItemLabel', { + defaultMessage: 'Autoplay settings', + }), + getFullscreenMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.fullscreenMenuLabel', { + defaultMessage: 'Enter fullscreen mode', + }), + getHideEditModeLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.hideEditModeLabel', { + defaultMessage: 'Hide editing controls', + }), + getRefreshMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshMenuItemLabel', { + defaultMessage: 'Refresh data', + }), + getRefreshSettingsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshSettingsMenuItemLabel', { + defaultMessage: 'Auto refresh settings', + }), + getShowEditModeLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.showEditModeLabel', { + defaultMessage: 'Show editing controls', + }), + getViewMenuButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.viewMenuButtonLabel', { + defaultMessage: 'View', + }), + getViewMenuLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.viewMenuLabel', { + defaultMessage: 'View options', + }), + getZoomFitToWindowText: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomFitToWindowText', { + defaultMessage: 'Fit to window', + }), + getZoomInText: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomInText', { + defaultMessage: 'Zoom in', + }), + getZoomMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomMenuItemLabel', { + defaultMessage: 'Zoom', + }), + getZoomOutText: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomOutText', { + defaultMessage: 'Zoom out', + }), + getZoomPercentage: (scale: number) => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomResetText', { + defaultMessage: '{scalePercentage}%', + values: { + scalePercentage: scale * 100, + }, + }), + getZoomResetText: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.zoomPrecentageValue', { + defaultMessage: 'Reset', + }), +}; const QUICK_ZOOM_LEVELS = [0.5, 1, 2]; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx index 415d3ddf4670..5320a65a9040 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx @@ -10,7 +10,8 @@ import PropTypes from 'prop-types'; // @ts-expect-error no @types definition import { Shortcuts } from 'react-shortcuts'; import { EuiFlexItem, EuiFlexGroup, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; -import { ComponentStrings } from '../../../i18n'; +import { i18n } from '@kbn/i18n'; + import { ToolTipShortcut } from '../tool_tip_shortcut/'; import { RefreshControl } from './refresh_control'; // @ts-expect-error untyped local @@ -22,7 +23,28 @@ import { ViewMenu } from './view_menu'; import { LabsControl } from './labs_control'; import { CommitFn } from '../../../types'; -const { WorkpadHeader: strings } = ComponentStrings; +const strings = { + getFullScreenButtonAriaLabel: () => + i18n.translate('xpack.canvas.workpadHeader.fullscreenButtonAriaLabel', { + defaultMessage: 'View fullscreen', + }), + getFullScreenTooltip: () => + i18n.translate('xpack.canvas.workpadHeader.fullscreenTooltip', { + defaultMessage: 'Enter fullscreen mode', + }), + getHideEditControlTooltip: () => + i18n.translate('xpack.canvas.workpadHeader.hideEditControlTooltip', { + defaultMessage: 'Hide editing controls', + }), + getNoWritePermissionTooltipText: () => + i18n.translate('xpack.canvas.workpadHeader.noWritePermissionTooltip', { + defaultMessage: "You don't have permission to edit this workpad", + }), + getShowEditControlTooltip: () => + i18n.translate('xpack.canvas.workpadHeader.showEditControlTooltip', { + defaultMessage: 'Show editing controls', + }), +}; export interface Props { isWriteable: boolean; diff --git a/x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.test.ts b/x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.test.ts similarity index 65% rename from x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.test.ts rename to x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.test.ts index c0a48d5d4486..0a80f1c06998 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.test.ts @@ -5,10 +5,7 @@ * 2.0. */ -import { - checkRunningSessions as checkRunningSessions$, - CheckRunningSessionsDeps, -} from './check_running_sessions'; +import { checkNonPersistedSessions as checkNonPersistedSessions$ } from './check_non_persiseted_sessions'; import { SearchSessionStatus, SearchSessionSavedObjectAttributes, @@ -16,22 +13,20 @@ import { EQL_SEARCH_STRATEGY, } from '../../../../../../src/plugins/data/common'; import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; -import { SearchSessionsConfig, SearchStatus } from './types'; +import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchStatus } from './types'; import moment from 'moment'; import { SavedObjectsBulkUpdateObject, SavedObjectsDeleteOptions, SavedObjectsClientContract, } from '../../../../../../src/core/server'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; jest.useFakeTimers(); -const checkRunningSessions = (deps: CheckRunningSessionsDeps, config: SearchSessionsConfig) => - checkRunningSessions$(deps, config).toPromise(); +const checkNonPersistedSessions = (deps: CheckSearchSessionsDeps, config: SearchSessionsConfig) => + checkNonPersistedSessions$(deps, config).toPromise(); -describe('getSearchStatus', () => { +describe('checkNonPersistedSessions', () => { let mockClient: any; let savedObjectsClient: jest.Mocked; const config: SearchSessionsConfig = { @@ -42,7 +37,9 @@ describe('getSearchStatus', () => { maxUpdateRetries: 3, defaultExpiration: moment.duration(7, 'd'), trackingInterval: moment.duration(10, 's'), + expireInterval: moment.duration(10, 'm'), monitoringTaskTimeout: moment.duration(5, 'm'), + cleanupInterval: moment.duration(10, 's'), management: {} as any, }; const mockLogger: any = { @@ -51,16 +48,6 @@ describe('getSearchStatus', () => { error: jest.fn(), }; - const emptySO = { - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(10, 's')), - idMapping: {}, - }, - }; - beforeEach(() => { savedObjectsClient = savedObjectsClientMock.create(); mockClient = { @@ -81,7 +68,7 @@ describe('getSearchStatus', () => { total: 0, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -94,240 +81,7 @@ describe('getSearchStatus', () => { expect(savedObjectsClient.delete).not.toBeCalled(); }); - describe('pagination', () => { - test('fetches one page if not objects exist', async () => { - savedObjectsClient.find.mockResolvedValueOnce({ - saved_objects: [], - total: 0, - } as any); - - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - }); - - test('fetches one page if less than page size object are returned', async () => { - savedObjectsClient.find.mockResolvedValueOnce({ - saved_objects: [emptySO, emptySO], - total: 5, - } as any); - - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - }); - - test('fetches two pages if exactly page size objects are returned', async () => { - let i = 0; - savedObjectsClient.find.mockImplementation(() => { - return new Promise((resolve) => { - resolve({ - saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], - total: 5, - page: i, - } as any); - }); - }); - - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.find).toHaveBeenCalledTimes(2); - - // validate that page number increases - const { page: page1 } = savedObjectsClient.find.mock.calls[0][0]; - const { page: page2 } = savedObjectsClient.find.mock.calls[1][0]; - expect(page1).toBe(1); - expect(page2).toBe(2); - }); - - test('fetches two pages if page size +1 objects are returned', async () => { - let i = 0; - savedObjectsClient.find.mockImplementation(() => { - return new Promise((resolve) => { - resolve({ - saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [emptySO], - total: 5, - page: i, - } as any); - }); - }); - - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.find).toHaveBeenCalledTimes(2); - }); - - test('fetching is abortable', async () => { - let i = 0; - const abort$ = new Subject(); - savedObjectsClient.find.mockImplementation(() => { - return new Promise((resolve) => { - if (++i === 2) { - abort$.next(); - } - resolve({ - saved_objects: i <= 5 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], - total: 25, - page: i, - } as any); - }); - }); - - await checkRunningSessions$( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ) - .pipe(takeUntil(abort$)) - .toPromise(); - - jest.runAllTimers(); - - // if not for `abort$` then this would be called 6 times! - expect(savedObjectsClient.find).toHaveBeenCalledTimes(2); - }); - - test('sorting is by "touched"', async () => { - savedObjectsClient.find.mockResolvedValueOnce({ - saved_objects: [], - total: 0, - } as any); - - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.find).toHaveBeenCalledWith( - expect.objectContaining({ sortField: 'touched', sortOrder: 'asc' }) - ); - }); - - test('sessions fetched in the beginning are processed even if sessions in the end fail', async () => { - let i = 0; - savedObjectsClient.find.mockImplementation(() => { - return new Promise((resolve, reject) => { - if (++i === 2) { - reject(new Error('Fake find error...')); - } - resolve({ - saved_objects: - i <= 5 - ? [ - i === 1 - ? { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(2, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - }, - }, - }, - } - : emptySO, - emptySO, - emptySO, - emptySO, - emptySO, - ] - : [], - total: 25, - page: i, - } as any); - }); - }); - - await checkRunningSessions$( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ).toPromise(); - - jest.runAllTimers(); - - expect(savedObjectsClient.find).toHaveBeenCalledTimes(2); - - // by checking that delete was called we validate that sessions from session that were successfully fetched were processed - expect(mockClient.asyncSearch.delete).toBeCalled(); - const { id } = mockClient.asyncSearch.delete.mock.calls[0][0]; - expect(id).toBe('async-id'); - }); - }); - describe('delete', () => { - test('doesnt delete a persisted session', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: true, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(30, 'm')), - touched: moment().subtract(moment.duration(10, 'm')), - idMapping: {}, - }, - }, - ], - total: 1, - } as any); - await checkRunningSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - test('doesnt delete a non persisted, recently touched session', async () => { savedObjectsClient.find.mockResolvedValue({ saved_objects: [ @@ -336,6 +90,7 @@ describe('getSearchStatus', () => { attributes: { persisted: false, status: SearchSessionStatus.IN_PROGRESS, + expires: moment().add(moment.duration(3, 'm')), created: moment().subtract(moment.duration(3, 'm')), touched: moment().subtract(moment.duration(10, 's')), idMapping: {}, @@ -344,7 +99,7 @@ describe('getSearchStatus', () => { ], total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -367,6 +122,7 @@ describe('getSearchStatus', () => { status: SearchSessionStatus.COMPLETE, created: moment().subtract(moment.duration(3, 'm')), touched: moment().subtract(moment.duration(1, 'm')), + expires: moment().add(moment.duration(3, 'm')), idMapping: { 'search-hash': { id: 'search-id', @@ -379,7 +135,7 @@ describe('getSearchStatus', () => { ], total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -401,6 +157,7 @@ describe('getSearchStatus', () => { attributes: { persisted: false, status: SearchSessionStatus.IN_PROGRESS, + expires: moment().add(moment.duration(3, 'm')), created: moment().subtract(moment.duration(3, 'm')), touched: moment().subtract(moment.duration(2, 'm')), idMapping: { @@ -415,7 +172,7 @@ describe('getSearchStatus', () => { total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -441,6 +198,7 @@ describe('getSearchStatus', () => { status: SearchSessionStatus.IN_PROGRESS, created: moment().subtract(moment.duration(3, 'm')), touched: moment().subtract(moment.duration(2, 'm')), + expires: moment().add(moment.duration(3, 'm')), idMapping: { 'map-key': { strategy: ENHANCED_ES_SEARCH_STRATEGY, @@ -453,7 +211,7 @@ describe('getSearchStatus', () => { total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -481,6 +239,7 @@ describe('getSearchStatus', () => { attributes: { persisted: false, status: SearchSessionStatus.COMPLETE, + expires: moment().add(moment.duration(3, 'm')), created: moment().subtract(moment.duration(30, 'm')), touched: moment().subtract(moment.duration(6, 'm')), idMapping: { @@ -501,7 +260,7 @@ describe('getSearchStatus', () => { total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -530,6 +289,7 @@ describe('getSearchStatus', () => { attributes: { persisted: false, status: SearchSessionStatus.COMPLETE, + expires: moment().add(moment.duration(3, 'm')), created: moment().subtract(moment.duration(30, 'm')), touched: moment().subtract(moment.duration(6, 'm')), idMapping: { @@ -545,7 +305,7 @@ describe('getSearchStatus', () => { total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -573,6 +333,7 @@ describe('getSearchStatus', () => { status: SearchSessionStatus.IN_PROGRESS, created: moment().subtract(moment.duration(3, 'm')), touched: moment().subtract(moment.duration(10, 's')), + expires: moment().add(moment.duration(3, 'm')), idMapping: { 'search-hash': { id: 'search-id', @@ -594,7 +355,7 @@ describe('getSearchStatus', () => { }, }); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -614,6 +375,7 @@ describe('getSearchStatus', () => { id: '123', attributes: { status: SearchSessionStatus.ERROR, + expires: moment().add(moment.duration(3, 'm')), idMapping: { 'search-hash': { id: 'search-id', @@ -633,7 +395,7 @@ describe('getSearchStatus', () => { total: 1, } as any); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -653,6 +415,7 @@ describe('getSearchStatus', () => { namespaces: ['awesome'], attributes: { status: SearchSessionStatus.IN_PROGRESS, + expires: moment().add(moment.duration(3, 'm')), touched: '123', idMapping: { 'search-hash': { @@ -676,7 +439,7 @@ describe('getSearchStatus', () => { }, }); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -696,6 +459,7 @@ describe('getSearchStatus', () => { const so = { attributes: { status: SearchSessionStatus.IN_PROGRESS, + expires: moment().add(moment.duration(3, 'm')), touched: '123', idMapping: { 'search-hash': { @@ -719,7 +483,7 @@ describe('getSearchStatus', () => { }, }); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, @@ -744,6 +508,7 @@ describe('getSearchStatus', () => { savedObjectsClient.bulkUpdate = jest.fn(); const so = { attributes: { + expires: moment().add(moment.duration(3, 'm')), idMapping: { 'search-hash': { id: 'search-id', @@ -766,7 +531,7 @@ describe('getSearchStatus', () => { }, }); - await checkRunningSessions( + await checkNonPersistedSessions( { savedObjectsClient, client: mockClient, diff --git a/x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.ts b/x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.ts new file mode 100644 index 000000000000..8c75ce91cac6 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/check_non_persiseted_sessions.ts @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsFindResult } from 'kibana/server'; +import moment from 'moment'; +import { EMPTY } from 'rxjs'; +import { catchError, concatMap } from 'rxjs/operators'; +import { + nodeBuilder, + ENHANCED_ES_SEARCH_STRATEGY, + SEARCH_SESSION_TYPE, + SearchSessionSavedObjectAttributes, + SearchSessionStatus, + KueryNode, +} from '../../../../../../src/plugins/data/common'; +import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; +import { SearchSessionsConfig, CheckSearchSessionsDeps } from './types'; +import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; + +export const SEARCH_SESSIONS_CLEANUP_TASK_TYPE = 'search_sessions_cleanup'; +export const SEARCH_SESSIONS_CLEANUP_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_CLEANUP_TASK_TYPE}`; + +function isSessionStale( + session: SavedObjectsFindResult, + config: SearchSessionsConfig +) { + const curTime = moment(); + // Delete cancelled sessions immediately + if (session.attributes.status === SearchSessionStatus.CANCELLED) return true; + // Delete if a running session wasn't polled for in the last notTouchedInProgressTimeout OR + // if a completed \ errored \ canceled session wasn't saved for within notTouchedTimeout + return ( + (session.attributes.status === SearchSessionStatus.IN_PROGRESS && + curTime.diff(moment(session.attributes.touched), 'ms') > + config.notTouchedInProgressTimeout.asMilliseconds()) || + (session.attributes.status !== SearchSessionStatus.IN_PROGRESS && + curTime.diff(moment(session.attributes.touched), 'ms') > + config.notTouchedTimeout.asMilliseconds()) + ); +} + +function checkNonPersistedSessionsPage( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig, + filter: KueryNode, + page: number +) { + const { logger, client, savedObjectsClient } = deps; + logger.debug(`${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Fetching sessions from page ${page}`); + return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( + concatMap(async (nonPersistedSearchSessions) => { + if (!nonPersistedSearchSessions.total) return nonPersistedSearchSessions; + + logger.debug( + `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Found ${nonPersistedSearchSessions.total} sessions, processing ${nonPersistedSearchSessions.saved_objects.length}` + ); + + const updatedSessions = await getAllSessionsStatusUpdates(deps, nonPersistedSearchSessions); + const deletedSessionIds: string[] = []; + + await Promise.all( + nonPersistedSearchSessions.saved_objects.map(async (session) => { + if (isSessionStale(session, config)) { + // delete saved object to free up memory + // TODO: there's a potential rare edge case of deleting an object and then receiving a new trackId for that same session! + // Maybe we want to change state to deleted and cleanup later? + logger.debug(`Deleting stale session | ${session.id}`); + try { + deletedSessionIds.push(session.id); + await savedObjectsClient.delete(SEARCH_SESSION_TYPE, session.id, { + namespace: session.namespaces?.[0], + }); + } catch (e) { + logger.error( + `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while deleting session ${session.id}: ${e.message}` + ); + } + + // Send a delete request for each async search to ES + Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { + const searchInfo = session.attributes.idMapping[searchKey]; + if (searchInfo.strategy === ENHANCED_ES_SEARCH_STRATEGY) { + try { + await client.asyncSearch.delete({ id: searchInfo.id }); + } catch (e) { + if (e.message !== 'resource_not_found_exception') { + logger.error( + `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while deleting async_search ${searchInfo.id}: ${e.message}` + ); + } + } + } + }); + } + }) + ); + + const nonDeletedSessions = updatedSessions.filter((updateSession) => { + return deletedSessionIds.indexOf(updateSession.id) === -1; + }); + + await bulkUpdateSessions(deps, nonDeletedSessions); + + return nonPersistedSearchSessions; + }) + ); +} + +export function checkNonPersistedSessions( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig +) { + const { logger } = deps; + + const filters = nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'false'); + + return checkSearchSessionsByPage(checkNonPersistedSessionsPage, deps, config, filters).pipe( + catchError((e) => { + logger.error( + `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while processing sessions: ${e?.message}` + ); + return EMPTY; + }) + ); +} diff --git a/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.test.ts b/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.test.ts new file mode 100644 index 000000000000..e0b1b74b57d0 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { checkPersistedSessionsProgress } from './check_persisted_sessions'; +import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; +import { SearchSessionsConfig } from './types'; +import moment from 'moment'; +import { SavedObjectsClientContract } from '../../../../../../src/core/server'; + +describe('checkPersistedSessionsProgress', () => { + let mockClient: any; + let savedObjectsClient: jest.Mocked; + const config: SearchSessionsConfig = { + enabled: true, + pageSize: 5, + notTouchedInProgressTimeout: moment.duration(1, 'm'), + notTouchedTimeout: moment.duration(5, 'm'), + maxUpdateRetries: 3, + defaultExpiration: moment.duration(7, 'd'), + trackingInterval: moment.duration(10, 's'), + cleanupInterval: moment.duration(10, 's'), + expireInterval: moment.duration(10, 'm'), + monitoringTaskTimeout: moment.duration(5, 'm'), + management: {} as any, + }; + const mockLogger: any = { + debug: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + beforeEach(() => { + savedObjectsClient = savedObjectsClientMock.create(); + mockClient = { + asyncSearch: { + status: jest.fn(), + delete: jest.fn(), + }, + eql: { + status: jest.fn(), + delete: jest.fn(), + }, + }; + }); + + test('fetches only running persisted sessions', async () => { + savedObjectsClient.find.mockResolvedValue({ + saved_objects: [], + total: 0, + } as any); + + await checkPersistedSessionsProgress( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config + ); + + const [findInput] = savedObjectsClient.find.mock.calls[0]; + + expect(findInput.filter.arguments[0].arguments[0].value).toBe( + 'search-session.attributes.persisted' + ); + expect(findInput.filter.arguments[0].arguments[1].value).toBe('true'); + expect(findInput.filter.arguments[1].arguments[0].value).toBe( + 'search-session.attributes.status' + ); + expect(findInput.filter.arguments[1].arguments[1].value).toBe('in_progress'); + }); +}); diff --git a/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.ts b/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.ts new file mode 100644 index 000000000000..0d51e9795227 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/check_persisted_sessions.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EMPTY, Observable } from 'rxjs'; +import { catchError, concatMap } from 'rxjs/operators'; +import { + nodeBuilder, + SEARCH_SESSION_TYPE, + SearchSessionStatus, + KueryNode, +} from '../../../../../../src/plugins/data/common'; +import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; +import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchSessionsResponse } from './types'; +import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; + +export const SEARCH_SESSIONS_TASK_TYPE = 'search_sessions_monitor'; +export const SEARCH_SESSIONS_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_TASK_TYPE}`; + +function checkPersistedSessionsPage( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig, + filter: KueryNode, + page: number +): Observable { + const { logger } = deps; + logger.debug(`${SEARCH_SESSIONS_TASK_TYPE} Fetching sessions from page ${page}`); + return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( + concatMap(async (persistedSearchSessions) => { + if (!persistedSearchSessions.total) return persistedSearchSessions; + + logger.debug( + `${SEARCH_SESSIONS_TASK_TYPE} Found ${persistedSearchSessions.total} sessions, processing ${persistedSearchSessions.saved_objects.length}` + ); + + const updatedSessions = await getAllSessionsStatusUpdates(deps, persistedSearchSessions); + await bulkUpdateSessions(deps, updatedSessions); + + return persistedSearchSessions; + }) + ); +} + +export function checkPersistedSessionsProgress( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig +) { + const { logger } = deps; + + const persistedSessionsFilter = nodeBuilder.and([ + nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'true'), + nodeBuilder.is( + `${SEARCH_SESSION_TYPE}.attributes.status`, + SearchSessionStatus.IN_PROGRESS.toString() + ), + ]); + + return checkSearchSessionsByPage( + checkPersistedSessionsPage, + deps, + config, + persistedSessionsFilter + ).pipe( + catchError((e) => { + logger.error(`${SEARCH_SESSIONS_TASK_TYPE} Error while processing sessions: ${e?.message}`); + return EMPTY; + }) + ); +} diff --git a/x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.ts b/x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.ts deleted file mode 100644 index 6787d31ed2b7..000000000000 --- a/x-pack/plugins/data_enhanced/server/search/session/check_running_sessions.ts +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ElasticsearchClient, - Logger, - SavedObjectsClientContract, - SavedObjectsFindResult, - SavedObjectsUpdateResponse, -} from 'kibana/server'; -import moment from 'moment'; -import { EMPTY, from, Observable } from 'rxjs'; -import { catchError, concatMap } from 'rxjs/operators'; -import { - nodeBuilder, - ENHANCED_ES_SEARCH_STRATEGY, - SEARCH_SESSION_TYPE, - SearchSessionRequestInfo, - SearchSessionSavedObjectAttributes, - SearchSessionStatus, -} from '../../../../../../src/plugins/data/common'; -import { getSearchStatus } from './get_search_status'; -import { getSessionStatus } from './get_session_status'; -import { SearchSessionsConfig, SearchStatus } from './types'; - -export interface CheckRunningSessionsDeps { - savedObjectsClient: SavedObjectsClientContract; - client: ElasticsearchClient; - logger: Logger; -} - -function isSessionStale( - session: SavedObjectsFindResult, - config: SearchSessionsConfig, - logger: Logger -) { - const curTime = moment(); - // Delete if a running session wasn't polled for in the last notTouchedInProgressTimeout OR - // if a completed \ errored \ canceled session wasn't saved for within notTouchedTimeout - return ( - (session.attributes.status === SearchSessionStatus.IN_PROGRESS && - curTime.diff(moment(session.attributes.touched), 'ms') > - config.notTouchedInProgressTimeout.asMilliseconds()) || - (session.attributes.status !== SearchSessionStatus.IN_PROGRESS && - curTime.diff(moment(session.attributes.touched), 'ms') > - config.notTouchedTimeout.asMilliseconds()) - ); -} - -async function updateSessionStatus( - session: SavedObjectsFindResult, - client: ElasticsearchClient, - logger: Logger -) { - let sessionUpdated = false; - - // Check statuses of all running searches - await Promise.all( - Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { - const updateSearchRequest = ( - currentStatus: Pick - ) => { - sessionUpdated = true; - session.attributes.idMapping[searchKey] = { - ...session.attributes.idMapping[searchKey], - ...currentStatus, - }; - }; - - const searchInfo = session.attributes.idMapping[searchKey]; - if (searchInfo.status === SearchStatus.IN_PROGRESS) { - try { - const currentStatus = await getSearchStatus(client, searchInfo.id); - - if (currentStatus.status !== searchInfo.status) { - logger.debug(`search ${searchInfo.id} | status changed to ${currentStatus.status}`); - updateSearchRequest(currentStatus); - } - } catch (e) { - logger.error(e); - updateSearchRequest({ - status: SearchStatus.ERROR, - error: e.message || e.meta.error?.caused_by?.reason, - }); - } - } - }) - ); - - // And only then derive the session's status - const sessionStatus = getSessionStatus(session.attributes); - if (sessionStatus !== session.attributes.status) { - const now = new Date().toISOString(); - session.attributes.status = sessionStatus; - session.attributes.touched = now; - if (sessionStatus === SearchSessionStatus.COMPLETE) { - session.attributes.completed = now; - } else if (session.attributes.completed) { - session.attributes.completed = null; - } - sessionUpdated = true; - } - - return sessionUpdated; -} - -function getSavedSearchSessionsPage$( - { savedObjectsClient, logger }: CheckRunningSessionsDeps, - config: SearchSessionsConfig, - page: number -) { - logger.debug(`Fetching saved search sessions page ${page}`); - return from( - savedObjectsClient.find({ - page, - perPage: config.pageSize, - type: SEARCH_SESSION_TYPE, - namespaces: ['*'], - // process older sessions first - sortField: 'touched', - sortOrder: 'asc', - filter: nodeBuilder.or([ - nodeBuilder.and([ - nodeBuilder.is( - `${SEARCH_SESSION_TYPE}.attributes.status`, - SearchSessionStatus.IN_PROGRESS.toString() - ), - nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'true'), - ]), - nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'false'), - ]), - }) - ); -} - -function checkRunningSessionsPage( - deps: CheckRunningSessionsDeps, - config: SearchSessionsConfig, - page: number -) { - const { logger, client, savedObjectsClient } = deps; - return getSavedSearchSessionsPage$(deps, config, page).pipe( - concatMap(async (runningSearchSessionsResponse) => { - if (!runningSearchSessionsResponse.total) return; - - logger.debug( - `Found ${runningSearchSessionsResponse.total} running sessions, processing ${runningSearchSessionsResponse.saved_objects.length} sessions from page ${page}` - ); - - const updatedSessions = new Array< - SavedObjectsFindResult - >(); - - await Promise.all( - runningSearchSessionsResponse.saved_objects.map(async (session) => { - const updated = await updateSessionStatus(session, client, logger); - let deleted = false; - - if (!session.attributes.persisted) { - if (isSessionStale(session, config, logger)) { - // delete saved object to free up memory - // TODO: there's a potential rare edge case of deleting an object and then receiving a new trackId for that same session! - // Maybe we want to change state to deleted and cleanup later? - logger.debug(`Deleting stale session | ${session.id}`); - try { - await savedObjectsClient.delete(SEARCH_SESSION_TYPE, session.id, { - namespace: session.namespaces?.[0], - }); - deleted = true; - } catch (e) { - logger.error( - `Error while deleting stale search session ${session.id}: ${e.message}` - ); - } - - // Send a delete request for each async search to ES - Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { - const searchInfo = session.attributes.idMapping[searchKey]; - if (searchInfo.strategy === ENHANCED_ES_SEARCH_STRATEGY) { - try { - await client.asyncSearch.delete({ id: searchInfo.id }); - } catch (e) { - logger.error( - `Error while deleting async_search ${searchInfo.id}: ${e.message}` - ); - } - } - }); - } - } - - if (updated && !deleted) { - updatedSessions.push(session); - } - }) - ); - - // Do a bulk update - if (updatedSessions.length) { - // If there's an error, we'll try again in the next iteration, so there's no need to check the output. - const updatedResponse = await savedObjectsClient.bulkUpdate( - updatedSessions.map((session) => ({ - ...session, - namespace: session.namespaces?.[0], - })) - ); - - const success: Array> = []; - const fail: Array> = []; - - updatedResponse.saved_objects.forEach((savedObjectResponse) => { - if ('error' in savedObjectResponse) { - fail.push(savedObjectResponse); - logger.error( - `Error while updating search session ${savedObjectResponse?.id}: ${savedObjectResponse.error?.message}` - ); - } else { - success.push(savedObjectResponse); - } - }); - - logger.debug(`Updating search sessions: success: ${success.length}, fail: ${fail.length}`); - } - - return runningSearchSessionsResponse; - }) - ); -} - -export function checkRunningSessions(deps: CheckRunningSessionsDeps, config: SearchSessionsConfig) { - const { logger } = deps; - - const checkRunningSessionsByPage = (nextPage = 1): Observable => - checkRunningSessionsPage(deps, config, nextPage).pipe( - concatMap((result) => { - if (!result || !result.saved_objects || result.saved_objects.length < config.pageSize) { - return EMPTY; - } else { - // TODO: while processing previous page session list might have been changed and we might skip a session, - // because it would appear now on a different "page". - // This isn't critical, as we would pick it up on a next task iteration, but maybe we could improve this somehow - return checkRunningSessionsByPage(result.page + 1); - } - }) - ); - - return checkRunningSessionsByPage().pipe( - catchError((e) => { - logger.error(`Error while processing search sessions: ${e?.message}`); - return EMPTY; - }) - ); -} diff --git a/x-pack/plugins/data_enhanced/server/search/session/expire_persisted_sessions.ts b/x-pack/plugins/data_enhanced/server/search/session/expire_persisted_sessions.ts new file mode 100644 index 000000000000..e261c324f440 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/expire_persisted_sessions.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EMPTY, Observable } from 'rxjs'; +import { catchError, concatMap } from 'rxjs/operators'; +import { + nodeBuilder, + SEARCH_SESSION_TYPE, + SearchSessionStatus, + KueryNode, +} from '../../../../../../src/plugins/data/common'; +import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; +import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchSessionsResponse } from './types'; +import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; + +export const SEARCH_SESSIONS_EXPIRE_TASK_TYPE = 'search_sessions_expire'; +export const SEARCH_SESSIONS_EXPIRE_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_EXPIRE_TASK_TYPE}`; + +function checkSessionExpirationPage( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig, + filter: KueryNode, + page: number +): Observable { + const { logger } = deps; + logger.debug(`${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Fetching sessions from page ${page}`); + return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( + concatMap(async (searchSessions) => { + if (!searchSessions.total) return searchSessions; + + logger.debug( + `${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Found ${searchSessions.total} sessions, processing ${searchSessions.saved_objects.length}` + ); + + const updatedSessions = await getAllSessionsStatusUpdates(deps, searchSessions); + await bulkUpdateSessions(deps, updatedSessions); + + return searchSessions; + }) + ); +} + +export function checkPersistedCompletedSessionExpiration( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig +) { + const { logger } = deps; + + const persistedSessionsFilter = nodeBuilder.and([ + nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'true'), + nodeBuilder.is( + `${SEARCH_SESSION_TYPE}.attributes.status`, + SearchSessionStatus.COMPLETE.toString() + ), + ]); + + return checkSearchSessionsByPage( + checkSessionExpirationPage, + deps, + config, + persistedSessionsFilter + ).pipe( + catchError((e) => { + logger.error( + `${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Error while processing sessions: ${e?.message}` + ); + return EMPTY; + }) + ); +} diff --git a/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.test.ts b/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.test.ts new file mode 100644 index 000000000000..df2b7d964642 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.test.ts @@ -0,0 +1,282 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; +import { + SearchSessionStatus, + ENHANCED_ES_SEARCH_STRATEGY, +} from '../../../../../../src/plugins/data/common'; +import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; +import { SearchSessionsConfig, SearchStatus } from './types'; +import moment from 'moment'; +import { SavedObjectsClientContract } from '../../../../../../src/core/server'; +import { of, Subject, throwError } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +jest.useFakeTimers(); + +describe('checkSearchSessionsByPage', () => { + const mockClient = {} as any; + let savedObjectsClient: jest.Mocked; + const config: SearchSessionsConfig = { + enabled: true, + pageSize: 5, + management: {} as any, + } as any; + const mockLogger: any = { + debug: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const emptySO = { + attributes: { + persisted: false, + status: SearchSessionStatus.IN_PROGRESS, + created: moment().subtract(moment.duration(3, 'm')), + touched: moment().subtract(moment.duration(10, 's')), + idMapping: {}, + }, + }; + + beforeEach(() => { + savedObjectsClient = savedObjectsClientMock.create(); + }); + + describe('getSearchSessionsPage$', () => { + test('sorting is by "touched"', async () => { + savedObjectsClient.find.mockResolvedValueOnce({ + saved_objects: [], + total: 0, + } as any); + + await getSearchSessionsPage$( + { + savedObjectsClient, + } as any, + { + type: 'literal', + }, + 1, + 1 + ); + + expect(savedObjectsClient.find).toHaveBeenCalledWith( + expect.objectContaining({ sortField: 'touched', sortOrder: 'asc' }) + ); + }); + }); + + describe('pagination', () => { + test('fetches one page if got empty response', async () => { + const checkFn = jest.fn().mockReturnValue(of(undefined)); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ).toPromise(); + + expect(checkFn).toHaveBeenCalledTimes(1); + }); + + test('fetches one page if got response with no saved objects', async () => { + const checkFn = jest.fn().mockReturnValue( + of({ + total: 0, + }) + ); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ).toPromise(); + + expect(checkFn).toHaveBeenCalledTimes(1); + }); + + test('fetches one page if less than page size object are returned', async () => { + const checkFn = jest.fn().mockReturnValue( + of({ + saved_objects: [emptySO, emptySO], + total: 5, + }) + ); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ).toPromise(); + + expect(checkFn).toHaveBeenCalledTimes(1); + }); + + test('fetches two pages if exactly page size objects are returned', async () => { + let i = 0; + + const checkFn = jest.fn().mockImplementation(() => + of({ + saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], + total: 5, + page: i, + }) + ); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ).toPromise(); + + expect(checkFn).toHaveBeenCalledTimes(2); + + // validate that page number increases + const page1 = checkFn.mock.calls[0][3]; + const page2 = checkFn.mock.calls[1][3]; + expect(page1).toBe(1); + expect(page2).toBe(2); + }); + + test('fetches two pages if page size +1 objects are returned', async () => { + let i = 0; + + const checkFn = jest.fn().mockImplementation(() => + of({ + saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [emptySO], + total: i === 0 ? 5 : 1, + page: i, + }) + ); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ).toPromise(); + + expect(checkFn).toHaveBeenCalledTimes(2); + }); + + test('sessions fetched in the beginning are processed even if sessions in the end fail', async () => { + let i = 0; + + const checkFn = jest.fn().mockImplementation(() => { + if (++i === 2) { + return throwError('Fake find error...'); + } + return of({ + saved_objects: + i <= 5 + ? [ + i === 1 + ? { + id: '123', + attributes: { + persisted: false, + status: SearchSessionStatus.IN_PROGRESS, + created: moment().subtract(moment.duration(3, 'm')), + touched: moment().subtract(moment.duration(2, 'm')), + idMapping: { + 'map-key': { + strategy: ENHANCED_ES_SEARCH_STRATEGY, + id: 'async-id', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } + : emptySO, + emptySO, + emptySO, + emptySO, + emptySO, + ] + : [], + total: 25, + page: i, + }); + }); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ) + .toPromise() + .catch(() => {}); + + expect(checkFn).toHaveBeenCalledTimes(2); + }); + + test('fetching is abortable', async () => { + let i = 0; + const abort$ = new Subject(); + + const checkFn = jest.fn().mockImplementation(() => { + if (++i === 2) { + abort$.next(); + } + + return of({ + saved_objects: i <= 5 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], + total: 25, + page: i, + }); + }); + + await checkSearchSessionsByPage( + checkFn, + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + config, + [] + ) + .pipe(takeUntil(abort$)) + .toPromise() + .catch(() => {}); + + jest.runAllTimers(); + + // if not for `abort$` then this would be called 6 times! + expect(checkFn).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.ts b/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.ts new file mode 100644 index 000000000000..74306bac39f7 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/get_search_session_page.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsClientContract, Logger } from 'kibana/server'; +import { from, Observable, EMPTY } from 'rxjs'; +import { concatMap } from 'rxjs/operators'; +import { + SearchSessionSavedObjectAttributes, + SEARCH_SESSION_TYPE, + KueryNode, +} from '../../../../../../src/plugins/data/common'; +import { CheckSearchSessionsDeps, CheckSearchSessionsFn, SearchSessionsConfig } from './types'; + +export interface GetSessionsDeps { + savedObjectsClient: SavedObjectsClientContract; + logger: Logger; +} + +export function getSearchSessionsPage$( + { savedObjectsClient }: GetSessionsDeps, + filter: KueryNode, + pageSize: number, + page: number +) { + return from( + savedObjectsClient.find({ + page, + perPage: pageSize, + type: SEARCH_SESSION_TYPE, + namespaces: ['*'], + // process older sessions first + sortField: 'touched', + sortOrder: 'asc', + filter, + }) + ); +} + +export const checkSearchSessionsByPage = ( + checkFn: CheckSearchSessionsFn, + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig, + filters: any, + nextPage = 1 +): Observable => + checkFn(deps, config, filters, nextPage).pipe( + concatMap((result) => { + if (!result || !result.saved_objects || result.saved_objects.length < config.pageSize) { + return EMPTY; + } else { + // TODO: while processing previous page session list might have been changed and we might skip a session, + // because it would appear now on a different "page". + // This isn't critical, as we would pick it up on a next task iteration, but maybe we could improve this somehow + return checkSearchSessionsByPage(checkFn, deps, config, filters, result.page + 1); + } + }) + ); diff --git a/x-pack/plugins/data_enhanced/server/search/session/index.ts b/x-pack/plugins/data_enhanced/server/search/session/index.ts index deadeb3f8f07..1e6841211bb6 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/index.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/index.ts @@ -6,4 +6,3 @@ */ export * from './session_service'; -export { registerSearchSessionsTask, scheduleSearchSessionsTasks } from './monitoring_task'; diff --git a/x-pack/plugins/data_enhanced/server/search/session/monitoring_task.ts b/x-pack/plugins/data_enhanced/server/search/session/monitoring_task.ts deleted file mode 100644 index 7b7b1412987b..000000000000 --- a/x-pack/plugins/data_enhanced/server/search/session/monitoring_task.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Duration } from 'moment'; -import { filter, takeUntil } from 'rxjs/operators'; -import { BehaviorSubject } from 'rxjs'; -import { - TaskManagerSetupContract, - TaskManagerStartContract, - RunContext, - TaskRunCreatorFunction, -} from '../../../../task_manager/server'; -import { checkRunningSessions } from './check_running_sessions'; -import { CoreSetup, SavedObjectsClient, Logger } from '../../../../../../src/core/server'; -import { ConfigSchema } from '../../../config'; -import { SEARCH_SESSION_TYPE } from '../../../../../../src/plugins/data/common'; -import { DataEnhancedStartDependencies } from '../../type'; - -export const SEARCH_SESSIONS_TASK_TYPE = 'search_sessions_monitor'; -export const SEARCH_SESSIONS_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_TASK_TYPE}`; - -interface SearchSessionTaskDeps { - taskManager: TaskManagerSetupContract; - logger: Logger; - config: ConfigSchema; -} - -function searchSessionRunner( - core: CoreSetup, - { logger, config }: SearchSessionTaskDeps -): TaskRunCreatorFunction { - return ({ taskInstance }: RunContext) => { - const aborted$ = new BehaviorSubject(false); - return { - async run() { - const sessionConfig = config.search.sessions; - const [coreStart] = await core.getStartServices(); - if (!sessionConfig.enabled) { - logger.debug('Search sessions are disabled. Skipping task.'); - return; - } - if (aborted$.getValue()) return; - - const internalRepo = coreStart.savedObjects.createInternalRepository([SEARCH_SESSION_TYPE]); - const internalSavedObjectsClient = new SavedObjectsClient(internalRepo); - await checkRunningSessions( - { - savedObjectsClient: internalSavedObjectsClient, - client: coreStart.elasticsearch.client.asInternalUser, - logger, - }, - sessionConfig - ) - .pipe(takeUntil(aborted$.pipe(filter((aborted) => aborted)))) - .toPromise(); - - return { - state: {}, - }; - }, - cancel: async () => { - aborted$.next(true); - }, - }; - }; -} - -export function registerSearchSessionsTask( - core: CoreSetup, - deps: SearchSessionTaskDeps -) { - deps.taskManager.registerTaskDefinitions({ - [SEARCH_SESSIONS_TASK_TYPE]: { - title: 'Search Sessions Monitor', - createTaskRunner: searchSessionRunner(core, deps), - timeout: `${deps.config.search.sessions.monitoringTaskTimeout.asSeconds()}s`, - }, - }); -} - -export async function unscheduleSearchSessionsTask( - taskManager: TaskManagerStartContract, - logger: Logger -) { - try { - await taskManager.removeIfExists(SEARCH_SESSIONS_TASK_ID); - logger.debug(`Search sessions cleared`); - } catch (e) { - logger.error(`Error clearing task, received ${e.message}`); - } -} - -export async function scheduleSearchSessionsTasks( - taskManager: TaskManagerStartContract, - logger: Logger, - trackingInterval: Duration -) { - await taskManager.removeIfExists(SEARCH_SESSIONS_TASK_ID); - - try { - await taskManager.ensureScheduled({ - id: SEARCH_SESSIONS_TASK_ID, - taskType: SEARCH_SESSIONS_TASK_TYPE, - schedule: { - interval: `${trackingInterval.asSeconds()}s`, - }, - state: {}, - params: {}, - }); - - logger.debug(`Search sessions task, scheduled to run`); - } catch (e) { - logger.error(`Error scheduling task, received ${e.message}`); - } -} diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 374dbee2384d..dd1eafa5d60f 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -79,7 +79,9 @@ describe('SearchSessionService', () => { maxUpdateRetries: MAX_UPDATE_RETRIES, defaultExpiration: moment.duration(7, 'd'), monitoringTaskTimeout: moment.duration(5, 'm'), + cleanupInterval: moment.duration(10, 's'), trackingInterval: moment.duration(10, 's'), + expireInterval: moment.duration(10, 'm'), management: {} as any, }, }, @@ -157,7 +159,9 @@ describe('SearchSessionService', () => { maxUpdateRetries: MAX_UPDATE_RETRIES, defaultExpiration: moment.duration(7, 'd'), trackingInterval: moment.duration(10, 's'), + expireInterval: moment.duration(10, 'm'), monitoringTaskTimeout: moment.duration(5, 'm'), + cleanupInterval: moment.duration(10, 's'), management: {} as any, }, }, diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 81a12f607935..0998c1f42e18 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -43,11 +43,26 @@ import { createRequestHash } from './utils'; import { ConfigSchema } from '../../../config'; import { registerSearchSessionsTask, - scheduleSearchSessionsTasks, + scheduleSearchSessionsTask, unscheduleSearchSessionsTask, -} from './monitoring_task'; +} from './setup_task'; import { SearchSessionsConfig, SearchStatus } from './types'; import { DataEnhancedStartDependencies } from '../../type'; +import { + checkPersistedSessionsProgress, + SEARCH_SESSIONS_TASK_ID, + SEARCH_SESSIONS_TASK_TYPE, +} from './check_persisted_sessions'; +import { + SEARCH_SESSIONS_CLEANUP_TASK_TYPE, + checkNonPersistedSessions, + SEARCH_SESSIONS_CLEANUP_TASK_ID, +} from './check_non_persiseted_sessions'; +import { + SEARCH_SESSIONS_EXPIRE_TASK_TYPE, + SEARCH_SESSIONS_EXPIRE_TASK_ID, + checkPersistedCompletedSessionExpiration, +} from './expire_persisted_sessions'; export interface SearchSessionDependencies { savedObjectsClient: SavedObjectsClientContract; @@ -89,11 +104,35 @@ export class SearchSessionService } public setup(core: CoreSetup, deps: SetupDependencies) { - registerSearchSessionsTask(core, { + const taskDeps = { config: this.config, taskManager: deps.taskManager, logger: this.logger, - }); + }; + + registerSearchSessionsTask( + core, + taskDeps, + SEARCH_SESSIONS_TASK_TYPE, + 'persisted session progress', + checkPersistedSessionsProgress + ); + + registerSearchSessionsTask( + core, + taskDeps, + SEARCH_SESSIONS_CLEANUP_TASK_TYPE, + 'non persisted session cleanup', + checkNonPersistedSessions + ); + + registerSearchSessionsTask( + core, + taskDeps, + SEARCH_SESSIONS_EXPIRE_TASK_TYPE, + 'complete session expiration', + checkPersistedCompletedSessionExpiration + ); } public async start(core: CoreStart, deps: StartDependencies) { @@ -103,14 +142,37 @@ export class SearchSessionService public stop() {} private setupMonitoring = async (core: CoreStart, deps: StartDependencies) => { + const taskDeps = { + config: this.config, + taskManager: deps.taskManager, + logger: this.logger, + }; + if (this.sessionConfig.enabled) { - scheduleSearchSessionsTasks( - deps.taskManager, - this.logger, + scheduleSearchSessionsTask( + taskDeps, + SEARCH_SESSIONS_TASK_ID, + SEARCH_SESSIONS_TASK_TYPE, this.sessionConfig.trackingInterval ); + + scheduleSearchSessionsTask( + taskDeps, + SEARCH_SESSIONS_CLEANUP_TASK_ID, + SEARCH_SESSIONS_CLEANUP_TASK_TYPE, + this.sessionConfig.cleanupInterval + ); + + scheduleSearchSessionsTask( + taskDeps, + SEARCH_SESSIONS_EXPIRE_TASK_ID, + SEARCH_SESSIONS_EXPIRE_TASK_TYPE, + this.sessionConfig.expireInterval + ); } else { - unscheduleSearchSessionsTask(deps.taskManager, this.logger); + unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_TASK_ID); + unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_CLEANUP_TASK_ID); + unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_EXPIRE_TASK_ID); } }; diff --git a/x-pack/plugins/data_enhanced/server/search/session/setup_task.ts b/x-pack/plugins/data_enhanced/server/search/session/setup_task.ts new file mode 100644 index 000000000000..a4c9b6039ff6 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/setup_task.ts @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Duration } from 'moment'; +import { filter, takeUntil } from 'rxjs/operators'; +import { BehaviorSubject } from 'rxjs'; +import { RunContext, TaskRunCreatorFunction } from '../../../../task_manager/server'; +import { CoreSetup, SavedObjectsClient } from '../../../../../../src/core/server'; +import { SEARCH_SESSION_TYPE } from '../../../../../../src/plugins/data/common'; +import { DataEnhancedStartDependencies } from '../../type'; +import { + SearchSessionTaskSetupDeps, + SearchSessionTaskStartDeps, + SearchSessionTaskFn, +} from './types'; + +export function searchSessionTaskRunner( + core: CoreSetup, + deps: SearchSessionTaskSetupDeps, + title: string, + checkFn: SearchSessionTaskFn +): TaskRunCreatorFunction { + const { logger, config } = deps; + return ({ taskInstance }: RunContext) => { + const aborted$ = new BehaviorSubject(false); + return { + async run() { + try { + const sessionConfig = config.search.sessions; + const [coreStart] = await core.getStartServices(); + if (!sessionConfig.enabled) { + logger.debug(`Search sessions are disabled. Skipping task ${title}.`); + return; + } + if (aborted$.getValue()) return; + + const internalRepo = coreStart.savedObjects.createInternalRepository([ + SEARCH_SESSION_TYPE, + ]); + const internalSavedObjectsClient = new SavedObjectsClient(internalRepo); + await checkFn( + { + logger, + client: coreStart.elasticsearch.client.asInternalUser, + savedObjectsClient: internalSavedObjectsClient, + }, + sessionConfig + ) + .pipe(takeUntil(aborted$.pipe(filter((aborted) => aborted)))) + .toPromise(); + + return { + state: {}, + }; + } catch (e) { + logger.error(`An error occurred. Skipping task ${title}.`); + } + }, + cancel: async () => { + aborted$.next(true); + }, + }; + }; +} + +export function registerSearchSessionsTask( + core: CoreSetup, + deps: SearchSessionTaskSetupDeps, + taskType: string, + title: string, + checkFn: SearchSessionTaskFn +) { + deps.taskManager.registerTaskDefinitions({ + [taskType]: { + title, + createTaskRunner: searchSessionTaskRunner(core, deps, title, checkFn), + timeout: `${deps.config.search.sessions.monitoringTaskTimeout.asSeconds()}s`, + }, + }); +} + +export async function unscheduleSearchSessionsTask( + { taskManager, logger }: SearchSessionTaskStartDeps, + taskId: string +) { + try { + await taskManager.removeIfExists(taskId); + logger.debug(`${taskId} cleared`); + } catch (e) { + logger.error(`${taskId} Error clearing task ${e.message}`); + } +} + +export async function scheduleSearchSessionsTask( + { taskManager, logger }: SearchSessionTaskStartDeps, + taskId: string, + taskType: string, + interval: Duration +) { + await taskManager.removeIfExists(taskId); + + try { + await taskManager.ensureScheduled({ + id: taskId, + taskType, + schedule: { + interval: `${interval.asSeconds()}s`, + }, + state: {}, + params: {}, + }); + + logger.debug(`${taskId} scheduled to run`); + } catch (e) { + logger.error(`${taskId} Error scheduling task ${e.message}`); + } +} diff --git a/x-pack/plugins/data_enhanced/server/search/session/types.ts b/x-pack/plugins/data_enhanced/server/search/session/types.ts index 0fa384e55f7d..eadc3821c104 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/types.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/types.ts @@ -5,6 +5,18 @@ * 2.0. */ +import { + ElasticsearchClient, + Logger, + SavedObjectsClientContract, + SavedObjectsFindResponse, +} from 'kibana/server'; +import { Observable } from 'rxjs'; +import { KueryNode, SearchSessionSavedObjectAttributes } from 'src/plugins/data/common'; +import { + TaskManagerSetupContract, + TaskManagerStartContract, +} from '../../../../../../x-pack/plugins/task_manager/server'; import { ConfigSchema } from '../../../config'; export enum SearchStatus { @@ -14,3 +26,38 @@ export enum SearchStatus { } export type SearchSessionsConfig = ConfigSchema['search']['sessions']; + +export interface CheckSearchSessionsDeps { + savedObjectsClient: SavedObjectsClientContract; + client: ElasticsearchClient; + logger: Logger; +} + +export interface SearchSessionTaskSetupDeps { + taskManager: TaskManagerSetupContract; + logger: Logger; + config: ConfigSchema; +} + +export interface SearchSessionTaskStartDeps { + taskManager: TaskManagerStartContract; + logger: Logger; + config: ConfigSchema; +} + +export type SearchSessionTaskFn = ( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig +) => Observable; + +export type SearchSessionsResponse = SavedObjectsFindResponse< + SearchSessionSavedObjectAttributes, + unknown +>; + +export type CheckSearchSessionsFn = ( + deps: CheckSearchSessionsDeps, + config: SearchSessionsConfig, + filter: KueryNode, + page: number +) => Observable; diff --git a/x-pack/plugins/data_enhanced/server/search/session/update_session_status.test.ts b/x-pack/plugins/data_enhanced/server/search/session/update_session_status.test.ts new file mode 100644 index 000000000000..485a30fd5495 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/update_session_status.test.ts @@ -0,0 +1,323 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { bulkUpdateSessions, updateSessionStatus } from './update_session_status'; +import { + SearchSessionStatus, + SearchSessionSavedObjectAttributes, +} from '../../../../../../src/plugins/data/common'; +import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; +import { SearchStatus } from './types'; +import moment from 'moment'; +import { + SavedObjectsBulkUpdateObject, + SavedObjectsClientContract, + SavedObjectsFindResult, +} from '../../../../../../src/core/server'; + +describe('bulkUpdateSessions', () => { + let mockClient: any; + let savedObjectsClient: jest.Mocked; + const mockLogger: any = { + debug: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + beforeEach(() => { + savedObjectsClient = savedObjectsClientMock.create(); + mockClient = { + asyncSearch: { + status: jest.fn(), + delete: jest.fn(), + }, + eql: { + status: jest.fn(), + delete: jest.fn(), + }, + }; + }); + + describe('updateSessionStatus', () => { + test('updates expired session', async () => { + const so: SavedObjectsFindResult = { + id: '123', + attributes: { + persisted: false, + status: SearchSessionStatus.IN_PROGRESS, + expires: moment().subtract(moment.duration(5, 'd')), + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + + const updated = await updateSessionStatus( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + so + ); + + expect(updated).toBeTruthy(); + expect(so.attributes.status).toBe(SearchSessionStatus.EXPIRED); + }); + + test('does nothing if the search is still running', async () => { + const so = { + id: '123', + attributes: { + persisted: false, + status: SearchSessionStatus.IN_PROGRESS, + created: moment().subtract(moment.duration(3, 'm')), + touched: moment().subtract(moment.duration(10, 's')), + expires: moment().add(moment.duration(5, 'd')), + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + + mockClient.asyncSearch.status.mockResolvedValue({ + body: { + is_partial: true, + is_running: true, + }, + }); + + const updated = await updateSessionStatus( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + so + ); + + expect(updated).toBeFalsy(); + expect(so.attributes.status).toBe(SearchSessionStatus.IN_PROGRESS); + }); + + test("doesn't re-check completed or errored searches", async () => { + const so = { + id: '123', + attributes: { + expires: moment().add(moment.duration(5, 'd')), + status: SearchSessionStatus.ERROR, + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.COMPLETE, + }, + 'another-search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.ERROR, + }, + }, + }, + } as any; + + const updated = await updateSessionStatus( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + so + ); + + expect(updated).toBeFalsy(); + expect(mockClient.asyncSearch.status).not.toBeCalled(); + }); + + test('updates to complete if the search is done', async () => { + savedObjectsClient.bulkUpdate = jest.fn(); + const so = { + attributes: { + status: SearchSessionStatus.IN_PROGRESS, + touched: '123', + expires: moment().add(moment.duration(5, 'd')), + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + mockClient.asyncSearch.status.mockResolvedValue({ + body: { + is_partial: false, + is_running: false, + completion_status: 200, + }, + }); + + const updated = await updateSessionStatus( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + so + ); + + expect(updated).toBeTruthy(); + + expect(mockClient.asyncSearch.status).toBeCalledWith({ id: 'search-id' }); + expect(so.attributes.status).toBe(SearchSessionStatus.COMPLETE); + expect(so.attributes.status).toBe(SearchSessionStatus.COMPLETE); + expect(so.attributes.touched).not.toBe('123'); + expect(so.attributes.completed).not.toBeUndefined(); + expect(so.attributes.idMapping['search-hash'].status).toBe(SearchStatus.COMPLETE); + expect(so.attributes.idMapping['search-hash'].error).toBeUndefined(); + }); + + test('updates to error if the search is errored', async () => { + savedObjectsClient.bulkUpdate = jest.fn(); + const so = { + attributes: { + expires: moment().add(moment.duration(5, 'd')), + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + + mockClient.asyncSearch.status.mockResolvedValue({ + body: { + is_partial: false, + is_running: false, + completion_status: 500, + }, + }); + + const updated = await updateSessionStatus( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + so + ); + + expect(updated).toBeTruthy(); + expect(so.attributes.status).toBe(SearchSessionStatus.ERROR); + expect(so.attributes.touched).not.toBe('123'); + expect(so.attributes.idMapping['search-hash'].status).toBe(SearchStatus.ERROR); + expect(so.attributes.idMapping['search-hash'].error).toBe( + 'Search completed with a 500 status' + ); + }); + }); + + describe('bulkUpdateSessions', () => { + test('does nothing if there are no open sessions', async () => { + await bulkUpdateSessions( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + [] + ); + + expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); + expect(savedObjectsClient.delete).not.toBeCalled(); + }); + + test('updates in space', async () => { + const so = { + namespaces: ['awesome'], + attributes: { + expires: moment().add(moment.duration(5, 'd')), + status: SearchSessionStatus.IN_PROGRESS, + touched: '123', + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + + savedObjectsClient.bulkUpdate = jest.fn().mockResolvedValue({ + saved_objects: [so], + }); + + await bulkUpdateSessions( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + [so] + ); + + const [updateInput] = savedObjectsClient.bulkUpdate.mock.calls[0]; + const updatedAttributes = updateInput[0] as SavedObjectsBulkUpdateObject; + expect(updatedAttributes.namespace).toBe('awesome'); + }); + + test('logs failures', async () => { + const so = { + namespaces: ['awesome'], + attributes: { + expires: moment().add(moment.duration(5, 'd')), + status: SearchSessionStatus.IN_PROGRESS, + touched: '123', + idMapping: { + 'search-hash': { + id: 'search-id', + strategy: 'cool', + status: SearchStatus.IN_PROGRESS, + }, + }, + }, + } as any; + + savedObjectsClient.bulkUpdate = jest.fn().mockResolvedValue({ + saved_objects: [ + { + error: 'nope', + }, + ], + }); + + await bulkUpdateSessions( + { + savedObjectsClient, + client: mockClient, + logger: mockLogger, + }, + [so] + ); + + expect(savedObjectsClient.bulkUpdate).toBeCalledTimes(1); + expect(mockLogger.error).toBeCalledTimes(1); + }); + }); +}); diff --git a/x-pack/plugins/data_enhanced/server/search/session/update_session_status.ts b/x-pack/plugins/data_enhanced/server/search/session/update_session_status.ts new file mode 100644 index 000000000000..1c484467bef6 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/search/session/update_session_status.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsFindResult, SavedObjectsUpdateResponse } from 'kibana/server'; +import { + SearchSessionRequestInfo, + SearchSessionSavedObjectAttributes, + SearchSessionStatus, +} from '../../../../../../src/plugins/data/common'; +import { getSearchStatus } from './get_search_status'; +import { getSessionStatus } from './get_session_status'; +import { CheckSearchSessionsDeps, SearchSessionsResponse, SearchStatus } from './types'; +import { isSearchSessionExpired } from './utils'; + +export async function updateSessionStatus( + { logger, client }: CheckSearchSessionsDeps, + session: SavedObjectsFindResult +) { + let sessionUpdated = false; + const isExpired = isSearchSessionExpired(session); + + if (!isExpired) { + // Check statuses of all running searches + await Promise.all( + Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { + const updateSearchRequest = ( + currentStatus: Pick + ) => { + sessionUpdated = true; + session.attributes.idMapping[searchKey] = { + ...session.attributes.idMapping[searchKey], + ...currentStatus, + }; + }; + + const searchInfo = session.attributes.idMapping[searchKey]; + if (searchInfo.status === SearchStatus.IN_PROGRESS) { + try { + const currentStatus = await getSearchStatus(client, searchInfo.id); + + if (currentStatus.status !== searchInfo.status) { + logger.debug(`search ${searchInfo.id} | status changed to ${currentStatus.status}`); + updateSearchRequest(currentStatus); + } + } catch (e) { + logger.error(e); + updateSearchRequest({ + status: SearchStatus.ERROR, + error: e.message || e.meta.error?.caused_by?.reason, + }); + } + } + }) + ); + } + + // And only then derive the session's status + const sessionStatus = isExpired + ? SearchSessionStatus.EXPIRED + : getSessionStatus(session.attributes); + if (sessionStatus !== session.attributes.status) { + const now = new Date().toISOString(); + session.attributes.status = sessionStatus; + session.attributes.touched = now; + if (sessionStatus === SearchSessionStatus.COMPLETE) { + session.attributes.completed = now; + } else if (session.attributes.completed) { + session.attributes.completed = null; + } + sessionUpdated = true; + } + + return sessionUpdated; +} + +export async function getAllSessionsStatusUpdates( + deps: CheckSearchSessionsDeps, + searchSessions: SearchSessionsResponse +) { + const updatedSessions = new Array>(); + + await Promise.all( + searchSessions.saved_objects.map(async (session) => { + const updated = await updateSessionStatus(deps, session); + + if (updated) { + updatedSessions.push(session); + } + }) + ); + + return updatedSessions; +} + +export async function bulkUpdateSessions( + { logger, savedObjectsClient }: CheckSearchSessionsDeps, + updatedSessions: Array> +) { + if (updatedSessions.length) { + // If there's an error, we'll try again in the next iteration, so there's no need to check the output. + const updatedResponse = await savedObjectsClient.bulkUpdate( + updatedSessions.map((session) => ({ + ...session, + namespace: session.namespaces?.[0], + })) + ); + + const success: Array> = []; + const fail: Array> = []; + + updatedResponse.saved_objects.forEach((savedObjectResponse) => { + if ('error' in savedObjectResponse) { + fail.push(savedObjectResponse); + logger.error( + `Error while updating search session ${savedObjectResponse?.id}: ${savedObjectResponse.error?.message}` + ); + } else { + success.push(savedObjectResponse); + } + }); + + logger.debug(`Updating search sessions: success: ${success.length}, fail: ${fail.length}`); + } +} diff --git a/x-pack/plugins/data_enhanced/server/search/session/utils.ts b/x-pack/plugins/data_enhanced/server/search/session/utils.ts index 7b1f1a756462..55c875602694 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/utils.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/utils.ts @@ -7,6 +7,9 @@ import { createHash } from 'crypto'; import stringify from 'json-stable-stringify'; +import { SavedObjectsFindResult } from 'kibana/server'; +import moment from 'moment'; +import { SearchSessionSavedObjectAttributes } from 'src/plugins/data/common'; /** * Generate the hash for this request so that, in the future, this hash can be used to look up @@ -17,3 +20,9 @@ export function createRequestHash(keys: Record) { const { preference, ...params } = keys; return createHash(`sha256`).update(stringify(params)).digest('hex'); } + +export function isSearchSessionExpired( + session: SavedObjectsFindResult +) { + return moment(session.attributes.expires).isBefore(moment()); +} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/document_creation_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/document_creation_button.tsx index cded18094c5f..482ee282cf46 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/document_creation_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/components/document_creation_button.tsx @@ -21,7 +21,7 @@ export const DocumentCreationButton: React.FC = () => { <> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx index b5b6dd453c9d..7e1b2acc81d1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx @@ -22,7 +22,6 @@ import { Documents } from '.'; describe('Documents', () => { const values = { isMetaEngine: false, - engine: { document_count: 1 }, myRole: { canManageEngineDocuments: true }, }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx index 62c7759757bd..75044bfcc8fb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx @@ -21,7 +21,7 @@ import { DOCUMENTS_TITLE } from './constants'; import { SearchExperience } from './search_experience'; export const Documents: React.FC = () => { - const { isMetaEngine, engine } = useValues(EngineLogic); + const { isMetaEngine, isEngineEmpty } = useValues(EngineLogic); const { myRole } = useValues(AppLogic); return ( @@ -32,7 +32,7 @@ export const Documents: React.FC = () => { rightSideItems: myRole.canManageEngineDocuments && !isMetaEngine ? [] : [], }} - isEmptyState={!engine.document_count} + isEmptyState={isEngineEmpty} emptyState={} > {isMetaEngine && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx index 709dfc69905f..8416974ad7a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx @@ -18,7 +18,7 @@ import { i18n } from '@kbn/i18n'; import './search_experience.scss'; -import { externalUrl } from '../../../../shared/enterprise_search_url'; +import { HttpLogic } from '../../../../shared/http'; import { useLocalStorage } from '../../../../shared/use_local_storage'; import { EngineLogic } from '../../engine'; @@ -52,7 +52,8 @@ const DEFAULT_SORT_OPTIONS: SortOption[] = [ export const SearchExperience: React.FC = () => { const { engine } = useValues(EngineLogic); - const endpointBase = externalUrl.enterpriseSearchUrl; + const { http } = useValues(HttpLogic); + const endpointBase = http.basePath.prepend('/api/app_search/search-ui'); const [showCustomizationModal, setShowCustomizationModal] = useState(false); const openCustomizationModal = () => setShowCustomizationModal(true); @@ -72,7 +73,9 @@ export const SearchExperience: React.FC = () => { cacheResponses: false, endpointBase, engineName: engine.name, - searchKey: engine.apiKey, + additionalHeaders: { + 'kbn-xsrf': true, + }, }); const searchProviderConfig = buildSearchUIConfig(connector, engine.schema || {}, fields); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts new file mode 100644 index 000000000000..9102f706fdbe --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const POLLING_DURATION = 5000; + +export const POLLING_ERROR_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.pollingErrorMessage', + { defaultMessage: 'Could not fetch engine data' } +); + +export const POLLING_ERROR_TEXT = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.pollingErrorDescription', + { defaultMessage: 'Please check your connection or manually reload the page.' } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts index 2b60193d4f7d..0189edbbf871 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts @@ -5,10 +5,15 @@ * 2.0. */ -import { LogicMounter, mockHttpValues } from '../../../__mocks__/kea_logic'; +import { + LogicMounter, + mockHttpValues, + mockFlashMessageHelpers, +} from '../../../__mocks__/kea_logic'; import { nextTick } from '@kbn/test/jest'; +import { SchemaType } from '../../../shared/schema/types'; import { ApiTokenTypes } from '../credentials/constants'; import { EngineTypes } from './types'; @@ -16,8 +21,9 @@ import { EngineTypes } from './types'; import { EngineLogic } from './'; describe('EngineLogic', () => { - const { mount } = new LogicMounter(EngineLogic); + const { mount, unmount } = new LogicMounter(EngineLogic); const { http } = mockHttpValues; + const { flashErrorToast } = mockFlashMessageHelpers; const mockEngineData = { name: 'some-engine', @@ -34,7 +40,7 @@ describe('EngineLogic', () => { sample: false, isMeta: false, invalidBoosts: false, - schema: {}, + schema: { test: SchemaType.Text }, apiTokens: [], apiKey: 'some-key', }; @@ -43,6 +49,8 @@ describe('EngineLogic', () => { dataLoading: true, engine: {}, engineName: '', + isEngineEmpty: true, + isEngineSchemaEmpty: true, isMetaEngine: false, isSampleEngine: false, hasSchemaErrors: false, @@ -50,6 +58,14 @@ describe('EngineLogic', () => { hasUnconfirmedSchemaFields: false, engineNotFound: false, searchKey: '', + intervalId: null, + }; + + const DEFAULT_VALUES_WITH_ENGINE = { + ...DEFAULT_VALUES, + engine: mockEngineData, + isEngineEmpty: false, + isEngineSchemaEmpty: false, }; beforeEach(() => { @@ -69,7 +85,7 @@ describe('EngineLogic', () => { EngineLogic.actions.setEngineData(mockEngineData); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, + ...DEFAULT_VALUES_WITH_ENGINE, engine: mockEngineData, dataLoading: false, }); @@ -154,6 +170,34 @@ describe('EngineLogic', () => { }); }); }); + + describe('onPollStart', () => { + it('should set intervalId', () => { + mount({ intervalId: null }); + EngineLogic.actions.onPollStart(123); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES, + intervalId: 123, + }); + }); + + describe('onPollStop', () => { + // Note: This does have to be a separate action following stopPolling(), rather + // than using stopPolling: () => null as a reducer. If you do that, then the ID + // gets cleared before the actual poll interval does & the poll interval never clears :doh: + + it('should reset intervalId', () => { + mount({ intervalId: 123 }); + EngineLogic.actions.onPollStop(); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES, + intervalId: null, + }); + }); + }); + }); }); describe('listeners', () => { @@ -170,28 +214,156 @@ describe('EngineLogic', () => { expect(EngineLogic.actions.setEngineData).toHaveBeenCalledWith(mockEngineData); }); - it('handles errors', async () => { + it('handles 4xx errors', async () => { mount(); jest.spyOn(EngineLogic.actions, 'setEngineNotFound'); - http.get.mockReturnValue(Promise.reject('An error occured')); + http.get.mockReturnValue(Promise.reject({ response: { status: 404 } })); EngineLogic.actions.initializeEngine(); await nextTick(); expect(EngineLogic.actions.setEngineNotFound).toHaveBeenCalledWith(true); }); + + it('handles 5xx errors', async () => { + mount(); + http.get.mockReturnValue(Promise.reject('An error occured')); + + EngineLogic.actions.initializeEngine(); + await nextTick(); + + expect(flashErrorToast).toHaveBeenCalledWith('Could not fetch engine data', { + text: expect.stringContaining('Please check your connection'), + toastLifeTimeMs: 3750, + }); + }); + }); + + describe('pollEmptyEngine', () => { + beforeEach(() => jest.useFakeTimers()); + afterEach(() => jest.clearAllTimers()); + afterAll(() => jest.useRealTimers()); + + it('starts a poll', () => { + mount(); + jest.spyOn(global, 'setInterval'); + jest.spyOn(EngineLogic.actions, 'onPollStart'); + + EngineLogic.actions.pollEmptyEngine(); + + expect(global.setInterval).toHaveBeenCalled(); + expect(EngineLogic.actions.onPollStart).toHaveBeenCalled(); + }); + + it('polls for engine data if the current engine is empty', () => { + mount({ engine: {} }); + jest.spyOn(EngineLogic.actions, 'initializeEngine'); + + EngineLogic.actions.pollEmptyEngine(); + + jest.advanceTimersByTime(5000); + expect(EngineLogic.actions.initializeEngine).toHaveBeenCalledTimes(1); + jest.advanceTimersByTime(5000); + expect(EngineLogic.actions.initializeEngine).toHaveBeenCalledTimes(2); + }); + + it('cancels the poll if the current engine changed from empty to non-empty', () => { + mount({ engine: mockEngineData }); + jest.spyOn(EngineLogic.actions, 'stopPolling'); + jest.spyOn(EngineLogic.actions, 'initializeEngine'); + + EngineLogic.actions.pollEmptyEngine(); + + jest.advanceTimersByTime(5000); + expect(EngineLogic.actions.stopPolling).toHaveBeenCalled(); + expect(EngineLogic.actions.initializeEngine).not.toHaveBeenCalled(); + }); + + it('does not create new polls if one already exists', () => { + jest.spyOn(global, 'setInterval'); + mount({ intervalId: 123 }); + + EngineLogic.actions.pollEmptyEngine(); + + expect(global.setInterval).not.toHaveBeenCalled(); + }); + }); + + describe('stopPolling', () => { + it('clears the poll interval and unsets the intervalId', () => { + jest.spyOn(global, 'clearInterval'); + mount({ intervalId: 123 }); + + EngineLogic.actions.stopPolling(); + + expect(global.clearInterval).toHaveBeenCalledWith(123); + expect(EngineLogic.values.intervalId).toEqual(null); + }); + + it('does not clearInterval if a poll has not been started', () => { + jest.spyOn(global, 'clearInterval'); + mount({ intervalId: null }); + + EngineLogic.actions.stopPolling(); + + expect(global.clearInterval).not.toHaveBeenCalled(); + }); }); }); describe('selectors', () => { + describe('isEngineEmpty', () => { + it('returns true if the engine contains no documents', () => { + const engine = { ...mockEngineData, document_count: 0 }; + mount({ engine }); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES_WITH_ENGINE, + engine, + isEngineEmpty: true, + }); + }); + + it('returns true if the engine is not yet initialized', () => { + mount({ engine: {} }); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES, + isEngineEmpty: true, + }); + }); + }); + + describe('isEngineSchemaEmpty', () => { + it('returns true if the engine schema contains no fields', () => { + const engine = { ...mockEngineData, schema: {} }; + mount({ engine }); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES_WITH_ENGINE, + engine, + isEngineSchemaEmpty: true, + }); + }); + + it('returns true if the engine is not yet initialized', () => { + mount({ engine: {} }); + + expect(EngineLogic.values).toEqual({ + ...DEFAULT_VALUES, + isEngineSchemaEmpty: true, + }); + }); + }); + describe('isSampleEngine', () => { it('should be set based on engine.sample', () => { - const mockSampleEngine = { ...mockEngineData, sample: true }; - mount({ engine: mockSampleEngine }); + const engine = { ...mockEngineData, sample: true }; + mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, - engine: mockSampleEngine, + ...DEFAULT_VALUES_WITH_ENGINE, + engine, isSampleEngine: true, }); }); @@ -199,12 +371,12 @@ describe('EngineLogic', () => { describe('isMetaEngine', () => { it('should be set based on engine.type', () => { - const mockMetaEngine = { ...mockEngineData, type: EngineTypes.meta }; - mount({ engine: mockMetaEngine }); + const engine = { ...mockEngineData, type: EngineTypes.meta }; + mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, - engine: mockMetaEngine, + ...DEFAULT_VALUES_WITH_ENGINE, + engine, isMetaEngine: true, }); }); @@ -212,17 +384,17 @@ describe('EngineLogic', () => { describe('hasSchemaErrors', () => { it('should be set based on engine.activeReindexJob.numDocumentsWithErrors', () => { - const mockSchemaEngine = { + const engine = { ...mockEngineData, activeReindexJob: { numDocumentsWithErrors: 10, }, }; - mount({ engine: mockSchemaEngine }); + mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, - engine: mockSchemaEngine, + ...DEFAULT_VALUES_WITH_ENGINE, + engine, hasSchemaErrors: true, }); }); @@ -230,7 +402,7 @@ describe('EngineLogic', () => { describe('hasSchemaConflicts', () => { it('should be set based on engine.schemaConflicts', () => { - const mockSchemaEngine = { + const engine = { ...mockEngineData, schemaConflicts: { someSchemaField: { @@ -241,11 +413,11 @@ describe('EngineLogic', () => { }, }, }; - mount({ engine: mockSchemaEngine }); + mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, - engine: mockSchemaEngine, + ...DEFAULT_VALUES_WITH_ENGINE, + engine, hasSchemaConflicts: true, }); }); @@ -253,15 +425,15 @@ describe('EngineLogic', () => { describe('hasUnconfirmedSchemaFields', () => { it('should be set based on engine.unconfirmedFields', () => { - const mockUnconfirmedFieldsEngine = { + const engine = { ...mockEngineData, unconfirmedFields: ['new_field_1', 'new_field_2'], }; - mount({ engine: mockUnconfirmedFieldsEngine }); + mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, - engine: mockUnconfirmedFieldsEngine, + ...DEFAULT_VALUES_WITH_ENGINE, + engine, hasUnconfirmedSchemaFields: true, }); }); @@ -292,7 +464,7 @@ describe('EngineLogic', () => { mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, + ...DEFAULT_VALUES_WITH_ENGINE, engine, searchKey: 'search-123xyz', }); @@ -312,11 +484,22 @@ describe('EngineLogic', () => { mount({ engine }); expect(EngineLogic.values).toEqual({ - ...DEFAULT_VALUES, + ...DEFAULT_VALUES_WITH_ENGINE, engine, searchKey: '', }); }); }); }); + + describe('events', () => { + it('calls stopPolling before unmount', () => { + mount(); + // Has to be a const to check state after unmount + const stopPollingSpy = jest.spyOn(EngineLogic.actions, 'stopPolling'); + + unmount(); + expect(stopPollingSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts index 5cbe89b36485..bfa77450176f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts @@ -7,16 +7,20 @@ import { kea, MakeLogicType } from 'kea'; +import { flashErrorToast } from '../../../shared/flash_messages'; import { HttpLogic } from '../../../shared/http'; import { ApiTokenTypes } from '../credentials/constants'; import { ApiToken } from '../credentials/types'; +import { POLLING_DURATION, POLLING_ERROR_TITLE, POLLING_ERROR_TEXT } from './constants'; import { EngineDetails, EngineTypes } from './types'; interface EngineValues { dataLoading: boolean; engine: Partial; engineName: string; + isEngineEmpty: boolean; + isEngineSchemaEmpty: boolean; isMetaEngine: boolean; isSampleEngine: boolean; hasSchemaErrors: boolean; @@ -24,6 +28,7 @@ interface EngineValues { hasUnconfirmedSchemaFields: boolean; engineNotFound: boolean; searchKey: string; + intervalId: number | null; } interface EngineActions { @@ -32,6 +37,10 @@ interface EngineActions { setEngineNotFound(notFound: boolean): { notFound: boolean }; clearEngine(): void; initializeEngine(): void; + pollEmptyEngine(): void; + onPollStart(intervalId: number): { intervalId: number }; + stopPolling(): void; + onPollStop(): void; } export const EngineLogic = kea>({ @@ -42,6 +51,10 @@ export const EngineLogic = kea>({ setEngineNotFound: (notFound) => ({ notFound }), clearEngine: true, initializeEngine: true, + pollEmptyEngine: true, + onPollStart: (intervalId) => ({ intervalId }), + stopPolling: true, + onPollStop: true, }, reducers: { dataLoading: [ @@ -72,8 +85,20 @@ export const EngineLogic = kea>({ clearEngine: () => false, }, ], + intervalId: [ + null, + { + onPollStart: (_, { intervalId }) => intervalId, + onPollStop: () => null, + }, + ], }, selectors: ({ selectors }) => ({ + isEngineEmpty: [() => [selectors.engine], (engine) => !engine.document_count], + isEngineSchemaEmpty: [ + () => [selectors.engine], + (engine) => Object.keys(engine.schema || {}).length === 0, + ], isMetaEngine: [() => [selectors.engine], (engine) => engine?.type === EngineTypes.meta], isSampleEngine: [() => [selectors.engine], (engine) => !!engine?.sample], // Indexed engines @@ -100,7 +125,9 @@ export const EngineLogic = kea>({ ], }), listeners: ({ actions, values }) => ({ - initializeEngine: async () => { + initializeEngine: async (_, breakpoint) => { + breakpoint(); // Prevents errors if logic unmounts while fetching + const { engineName } = values; const { http } = HttpLogic.values; @@ -108,8 +135,39 @@ export const EngineLogic = kea>({ const response = await http.get(`/api/app_search/engines/${engineName}`); actions.setEngineData(response); } catch (error) { - actions.setEngineNotFound(true); + if (error?.response?.status >= 400 && error?.response?.status < 500) { + actions.setEngineNotFound(true); + } else { + flashErrorToast(POLLING_ERROR_TITLE, { + text: POLLING_ERROR_TEXT, + toastLifeTimeMs: POLLING_DURATION * 0.75, + }); + } } }, + pollEmptyEngine: () => { + if (values.intervalId) return; // Ensure we only have one poll at a time + + const id = window.setInterval(() => { + if (values.isEngineEmpty && values.isEngineSchemaEmpty) { + actions.initializeEngine(); // Re-fetch engine data when engine is empty + } else { + actions.stopPolling(); + } + }, POLLING_DURATION); + + actions.onPollStart(id); + }, + stopPolling: () => { + if (values.intervalId !== null) { + clearInterval(values.intervalId); + actions.onPollStop(); + } + }, + }), + events: ({ actions }) => ({ + beforeUnmount: () => { + actions.stopPolling(); + }, }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx index ee1c0578debf..ed35bfbe9784 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx @@ -41,7 +41,13 @@ describe('EngineRouter', () => { engineNotFound: false, myRole: {}, }; - const actions = { setEngineName: jest.fn(), initializeEngine: jest.fn(), clearEngine: jest.fn() }; + const actions = { + setEngineName: jest.fn(), + initializeEngine: jest.fn(), + pollEmptyEngine: jest.fn(), + stopPolling: jest.fn(), + clearEngine: jest.fn(), + }; beforeEach(() => { setMockValues(values); @@ -58,12 +64,14 @@ describe('EngineRouter', () => { expect(actions.setEngineName).toHaveBeenCalledWith('some-engine'); }); - it('initializes/fetches engine API data', () => { + it('initializes/fetches engine API data and starts a poll for empty engines', () => { expect(actions.initializeEngine).toHaveBeenCalled(); + expect(actions.pollEmptyEngine).toHaveBeenCalled(); }); - it('clears engine on unmount and on update', () => { + it('clears engine and stops polling on unmount / on engine change', () => { unmountHandler(); + expect(actions.stopPolling).toHaveBeenCalled(); expect(actions.clearEngine).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx index 0f42483f44e0..da8dd8467bb6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx @@ -66,12 +66,19 @@ export const EngineRouter: React.FC = () => { const { engineName: engineNameFromUrl } = useParams() as { engineName: string }; const { engineName, dataLoading, engineNotFound } = useValues(EngineLogic); - const { setEngineName, initializeEngine, clearEngine } = useActions(EngineLogic); + const { setEngineName, initializeEngine, pollEmptyEngine, stopPolling, clearEngine } = useActions( + EngineLogic + ); useEffect(() => { setEngineName(engineNameFromUrl); initializeEngine(); - return clearEngine; + pollEmptyEngine(); + + return () => { + stopPolling(); + clearEngine(); + }; }, [engineNameFromUrl]); if (engineNotFound) { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx index edacd74e046a..a2e0ba4fcd44 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import '../../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic'; +import { setMockValues } from '../../../__mocks__/kea_logic'; import React from 'react'; @@ -20,18 +19,14 @@ import { EngineOverview } from './'; describe('EngineOverview', () => { const values = { dataLoading: false, - documentCount: 0, myRole: {}, + isEngineEmpty: true, isMetaEngine: false, }; - const actions = { - pollForOverviewMetrics: jest.fn(), - }; beforeEach(() => { jest.clearAllMocks(); setMockValues(values); - setMockActions(actions); }); it('renders', () => { @@ -39,21 +34,10 @@ describe('EngineOverview', () => { expect(wrapper.find('[data-test-subj="EngineOverview"]')).toHaveLength(1); }); - it('initializes data on mount', () => { - shallow(); - expect(actions.pollForOverviewMetrics).toHaveBeenCalledTimes(1); - }); - - it('renders a loading page template if async data is still loading', () => { - setMockValues({ ...values, dataLoading: true }); - const wrapper = shallow(); - expect(wrapper.prop('isLoading')).toEqual(true); - }); - describe('EmptyEngineOverview', () => { it('renders when the engine has no documents & the user can add documents', () => { const myRole = { canManageEngineDocuments: true, canViewEngineCredentials: true }; - setMockValues({ ...values, myRole, documentCount: 0 }); + setMockValues({ ...values, myRole }); const wrapper = shallow(); expect(wrapper.find(EmptyEngineOverview)).toHaveLength(1); }); @@ -61,7 +45,7 @@ describe('EngineOverview', () => { describe('EngineOverviewMetrics', () => { it('renders when the engine has documents', () => { - setMockValues({ ...values, documentCount: 1 }); + setMockValues({ ...values, isEngineEmpty: false }); const wrapper = shallow(); expect(wrapper.find(EngineOverviewMetrics)).toHaveLength(1); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx index 4c15ffd8b7f9..a3f98d8c13e8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx @@ -5,38 +5,25 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; -import { useActions, useValues } from 'kea'; +import { useValues } from 'kea'; import { AppLogic } from '../../app_logic'; import { EngineLogic } from '../engine'; -import { AppSearchPageTemplate } from '../layout'; import { EmptyEngineOverview } from './engine_overview_empty'; import { EngineOverviewMetrics } from './engine_overview_metrics'; -import { EngineOverviewLogic } from './'; - export const EngineOverview: React.FC = () => { const { myRole: { canManageEngineDocuments, canViewEngineCredentials }, } = useValues(AppLogic); - const { isMetaEngine } = useValues(EngineLogic); - - const { pollForOverviewMetrics } = useActions(EngineOverviewLogic); - const { dataLoading, documentCount } = useValues(EngineOverviewLogic); - - useEffect(() => { - pollForOverviewMetrics(); - }, []); - - if (dataLoading) return ; + const { isEngineEmpty, isMetaEngine } = useValues(EngineLogic); - const engineHasDocuments = documentCount > 0; const canAddDocuments = canManageEngineDocuments && canViewEngineCredentials; - const showEngineOverview = engineHasDocuments || !canAddDocuments || isMetaEngine; + const showEngineOverview = !isEngineEmpty || !canAddDocuments || isMetaEngine; return (
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts index c9c1defd4603..cc677d264270 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts @@ -20,7 +20,7 @@ import { nextTick } from '@kbn/test/jest'; import { EngineOverviewLogic } from './'; describe('EngineOverviewLogic', () => { - const { mount, unmount } = new LogicMounter(EngineOverviewLogic); + const { mount } = new LogicMounter(EngineOverviewLogic); const { http } = mockHttpValues; const { flashAPIErrors } = mockFlashMessageHelpers; @@ -41,7 +41,6 @@ describe('EngineOverviewLogic', () => { queriesPerDay: [], totalClicks: 0, totalQueries: 0, - timeoutId: null, }; beforeEach(() => { @@ -54,10 +53,10 @@ describe('EngineOverviewLogic', () => { }); describe('actions', () => { - describe('setPolledData', () => { + describe('onOverviewMetricsLoad', () => { it('should set all received data as top-level values and set dataLoading to false', () => { mount(); - EngineOverviewLogic.actions.setPolledData(mockEngineMetrics); + EngineOverviewLogic.actions.onOverviewMetricsLoad(mockEngineMetrics); expect(EngineOverviewLogic.values).toEqual({ ...DEFAULT_VALUES, @@ -66,34 +65,20 @@ describe('EngineOverviewLogic', () => { }); }); }); - - describe('setTimeoutId', () => { - describe('timeoutId', () => { - it('should be set to the provided value', () => { - mount(); - EngineOverviewLogic.actions.setTimeoutId(123); - - expect(EngineOverviewLogic.values).toEqual({ - ...DEFAULT_VALUES, - timeoutId: 123, - }); - }); - }); - }); }); describe('listeners', () => { - describe('pollForOverviewMetrics', () => { - it('fetches data and calls onPollingSuccess', async () => { + describe('loadOverviewMetrics', () => { + it('fetches data and calls onOverviewMetricsLoad', async () => { mount(); - jest.spyOn(EngineOverviewLogic.actions, 'onPollingSuccess'); + jest.spyOn(EngineOverviewLogic.actions, 'onOverviewMetricsLoad'); http.get.mockReturnValueOnce(Promise.resolve(mockEngineMetrics)); - EngineOverviewLogic.actions.pollForOverviewMetrics(); + EngineOverviewLogic.actions.loadOverviewMetrics(); await nextTick(); expect(http.get).toHaveBeenCalledWith('/api/app_search/engines/some-engine/overview'); - expect(EngineOverviewLogic.actions.onPollingSuccess).toHaveBeenCalledWith( + expect(EngineOverviewLogic.actions.onOverviewMetricsLoad).toHaveBeenCalledWith( mockEngineMetrics ); }); @@ -102,47 +87,11 @@ describe('EngineOverviewLogic', () => { mount(); http.get.mockReturnValue(Promise.reject('An error occurred')); - EngineOverviewLogic.actions.pollForOverviewMetrics(); + EngineOverviewLogic.actions.loadOverviewMetrics(); await nextTick(); expect(flashAPIErrors).toHaveBeenCalledWith('An error occurred'); }); }); - - describe('onPollingSuccess', () => { - it('starts a polling timeout and sets data', async () => { - mount(); - jest.useFakeTimers(); - jest.spyOn(EngineOverviewLogic.actions, 'setTimeoutId'); - jest.spyOn(EngineOverviewLogic.actions, 'setPolledData'); - - EngineOverviewLogic.actions.onPollingSuccess(mockEngineMetrics); - - expect(setTimeout).toHaveBeenCalledWith( - EngineOverviewLogic.actions.pollForOverviewMetrics, - 5000 - ); - expect(EngineOverviewLogic.actions.setTimeoutId).toHaveBeenCalledWith(expect.any(Number)); - expect(EngineOverviewLogic.actions.setPolledData).toHaveBeenCalledWith(mockEngineMetrics); - }); - }); - }); - - describe('unmount', () => { - beforeEach(() => { - jest.useFakeTimers(); - mount(); - }); - - it('clears existing polling timeouts on unmount', () => { - EngineOverviewLogic.actions.setTimeoutId(123); - unmount(); - expect(clearTimeout).toHaveBeenCalled(); - }); - - it("does not clear timeout if one hasn't been set", () => { - unmount(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.ts index 78d5358fc490..3f9c2e43a332 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.ts @@ -11,8 +11,6 @@ import { flashAPIErrors } from '../../../shared/flash_messages'; import { HttpLogic } from '../../../shared/http'; import { EngineLogic } from '../engine'; -const POLLING_DURATION = 5000; - interface EngineOverviewApiData { documentCount: number; startDate: string; @@ -23,95 +21,74 @@ interface EngineOverviewApiData { } interface EngineOverviewValues extends EngineOverviewApiData { dataLoading: boolean; - timeoutId: number | null; } interface EngineOverviewActions { - setPolledData(engineMetrics: EngineOverviewApiData): EngineOverviewApiData; - setTimeoutId(timeoutId: number): { timeoutId: number }; - pollForOverviewMetrics(): void; - onPollingSuccess(engineMetrics: EngineOverviewApiData): EngineOverviewApiData; + loadOverviewMetrics(): void; + onOverviewMetricsLoad(response: EngineOverviewApiData): EngineOverviewApiData; } export const EngineOverviewLogic = kea>({ path: ['enterprise_search', 'app_search', 'engine_overview_logic'], actions: () => ({ - setPolledData: (engineMetrics) => engineMetrics, - setTimeoutId: (timeoutId) => ({ timeoutId }), - pollForOverviewMetrics: true, - onPollingSuccess: (engineMetrics) => engineMetrics, + loadOverviewMetrics: true, + onOverviewMetricsLoad: (engineMetrics) => engineMetrics, }), reducers: () => ({ dataLoading: [ true, { - setPolledData: () => false, + onOverviewMetricsLoad: () => false, }, ], startDate: [ '', { - setPolledData: (_, { startDate }) => startDate, + onOverviewMetricsLoad: (_, { startDate }) => startDate, }, ], queriesPerDay: [ [], { - setPolledData: (_, { queriesPerDay }) => queriesPerDay, + onOverviewMetricsLoad: (_, { queriesPerDay }) => queriesPerDay, }, ], operationsPerDay: [ [], { - setPolledData: (_, { operationsPerDay }) => operationsPerDay, + onOverviewMetricsLoad: (_, { operationsPerDay }) => operationsPerDay, }, ], totalQueries: [ 0, { - setPolledData: (_, { totalQueries }) => totalQueries, + onOverviewMetricsLoad: (_, { totalQueries }) => totalQueries, }, ], totalClicks: [ 0, { - setPolledData: (_, { totalClicks }) => totalClicks, + onOverviewMetricsLoad: (_, { totalClicks }) => totalClicks, }, ], documentCount: [ 0, { - setPolledData: (_, { documentCount }) => documentCount, - }, - ], - timeoutId: [ - null, - { - setTimeoutId: (_, { timeoutId }) => timeoutId, + onOverviewMetricsLoad: (_, { documentCount }) => documentCount, }, ], }), listeners: ({ actions }) => ({ - pollForOverviewMetrics: async () => { + loadOverviewMetrics: async () => { const { http } = HttpLogic.values; const { engineName } = EngineLogic.values; try { const response = await http.get(`/api/app_search/engines/${engineName}/overview`); - actions.onPollingSuccess(response); + actions.onOverviewMetricsLoad(response); } catch (e) { flashAPIErrors(e); } }, - onPollingSuccess: (engineMetrics) => { - const timeoutId = window.setTimeout(actions.pollForOverviewMetrics, POLLING_DURATION); - actions.setTimeoutId(timeoutId); - actions.setPolledData(engineMetrics); - }, - }), - events: ({ values }) => ({ - beforeUnmount() { - if (values.timeoutId !== null) clearTimeout(values.timeoutId); - }, }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx index 620d913c5f9a..14f182463d83 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic'; +import '../../../__mocks__/shallow_useeffect.mock'; import '../../__mocks__/engine_logic.mock'; import React from 'react'; @@ -17,6 +19,19 @@ import { TotalStats, TotalCharts, RecentApiLogs } from './components'; import { EngineOverviewMetrics } from './engine_overview_metrics'; describe('EngineOverviewMetrics', () => { + const values = { + dataLoading: false, + }; + const actions = { + loadOverviewMetrics: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(values); + setMockActions(actions); + }); + it('renders', () => { const wrapper = shallow(); @@ -25,4 +40,9 @@ describe('EngineOverviewMetrics', () => { expect(wrapper.find(TotalCharts)).toHaveLength(1); expect(wrapper.find(RecentApiLogs)).toHaveLength(1); }); + + it('initializes data on mount', () => { + shallow(); + expect(actions.loadOverviewMetrics).toHaveBeenCalledTimes(1); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx index b47ae21104ae..3cc713862373 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx @@ -5,7 +5,9 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -15,7 +17,16 @@ import { AppSearchPageTemplate } from '../layout'; import { TotalStats, TotalCharts, RecentApiLogs } from './components'; +import { EngineOverviewLogic } from './'; + export const EngineOverviewMetrics: React.FC = () => { + const { loadOverviewMetrics } = useActions(EngineOverviewLogic); + const { dataLoading } = useValues(EngineOverviewLogic); + + useEffect(() => { + loadOverviewMetrics(); + }, []); + return ( { defaultMessage: 'Engine overview', }), }} + isLoading={dataLoading} > diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx index 0ac59a33068b..9f84bf4bd3b7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui.tsx @@ -24,7 +24,7 @@ import { SearchUILogic } from './search_ui_logic'; export const SearchUI: React.FC = () => { const { loadFieldData } = useActions(SearchUILogic); - const { engine } = useValues(EngineLogic); + const { isEngineSchemaEmpty } = useValues(EngineLogic); useEffect(() => { loadFieldData(); @@ -34,7 +34,7 @@ export const SearchUI: React.FC = () => { } > diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx index 4ed242c6ed67..eb3e5f027a2d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiLoadingSpinner } from '@elastic/eui'; +import { EuiLoadingLogo, EuiLoadingSpinner } from '@elastic/eui'; import { Loading, LoadingOverlay } from './'; @@ -17,7 +17,7 @@ describe('Loading', () => { it('renders', () => { const wrapper = shallow(); expect(wrapper.hasClass('enterpriseSearchLoading')).toBe(true); - expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); + expect(wrapper.find(EuiLoadingLogo)).toHaveLength(1); }); }); @@ -25,6 +25,6 @@ describe('LoadingOverlay', () => { it('renders', () => { const wrapper = shallow(); expect(wrapper.hasClass('enterpriseSearchLoadingOverlay')).toBe(true); - expect(wrapper.find(Loading)).toHaveLength(1); + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx index 627d8386dc1c..477cc27f5c8e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx @@ -7,18 +7,20 @@ import React from 'react'; -import { EuiLoadingSpinner } from '@elastic/eui'; +import { EuiLoadingLogo, EuiLoadingSpinner } from '@elastic/eui'; import './loading.scss'; export const Loading: React.FC = () => (
- +
); export const LoadingOverlay: React.FC = () => (
- +
+ +
); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/search.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/search.ts index 016f71e7e65b..216bffc68326 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/search.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/search.ts @@ -14,6 +14,8 @@ import { schema } from '@kbn/config-schema'; +import { skipBodyValidation } from '../../lib/route_config_helpers'; + import { RouteDependencies } from '../../plugin'; export function registerSearchRoutes({ @@ -36,4 +38,25 @@ export function registerSearchRoutes({ path: '/api/as/v1/engines/:engineName/search.json', }) ); + + // For the Search UI routes below, Search UI always uses the full API path, like: + // "/api/as/v1/engines/{engineName}/search.json". We only have control over the base path + // in Search UI, so we created a common basepath of "/api/app_search/search-ui" here that + // Search UI can use. + // + // Search UI *also* uses the click tracking and query suggestion endpoints, however, since the + // App Search plugin doesn't use that portion of Search UI, we only set up a proxy for the search endpoint below. + router.post( + skipBodyValidation({ + path: '/api/app_search/search-ui/api/as/v1/engines/{engineName}/search.json', + validate: { + params: schema.object({ + engineName: schema.string(), + }), + }, + }), + enterpriseSearchRequestHandler.createRequest({ + path: '/api/as/v1/engines/:engineName/search.json', + }) + ); } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx index 15e8c323b130..5f6ace206941 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx @@ -156,6 +156,9 @@ type TestSubject = | 'separatorValueField.input' | 'quoteValueField.input' | 'emptyValueField.input' + | 'extractDeviceTypeSwitch.input' + | 'propertiesValueField' + | 'regexFileField.input' | 'valueFieldInput' | 'mediaTypeSelectorField' | 'ignoreEmptyField.input' diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx new file mode 100644 index 000000000000..fa1c24c9dfb3 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setup, SetupResult, getProcessorValue } from './processor.helpers'; + +// Default parameter values automatically added to the user agent processor when saved +const defaultUserAgentParameters = { + if: undefined, + regex_file: undefined, + properties: undefined, + description: undefined, + ignore_missing: undefined, + ignore_failure: undefined, + extract_device_type: undefined, +}; + +const USER_AGENT_TYPE = 'user_agent'; + +describe('Processor: User Agent', () => { + let onUpdate: jest.Mock; + let testBed: SetupResult; + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + beforeEach(async () => { + onUpdate = jest.fn(); + + await act(async () => { + testBed = await setup({ + value: { + processors: [], + }, + onFlyoutOpen: jest.fn(), + onUpdate, + }); + }); + + testBed.component.update(); + + // Open flyout to add new processor + testBed.actions.addProcessor(); + // Add type (the other fields are not visible until a type is selected) + await testBed.actions.addProcessorType(USER_AGENT_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the processor type defined + await saveNewProcessor(); + + // Expect form error as "field" is required parameter + expect(form.getErrorsMessages()).toEqual(['A field value is required.']); + }); + + test('saves with just the default parameter value', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Add "field" value (required) + form.setInputValue('fieldNameField.input', 'field_1'); + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, USER_AGENT_TYPE); + expect(processors[0][USER_AGENT_TYPE]).toEqual({ + ...defaultUserAgentParameters, + field: 'field_1', + }); + }); + + test('allows optional parameters to be set', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + component, + } = testBed; + + // Add "field" value (required) + form.setInputValue('fieldNameField.input', 'field_1'); + + // Set optional parameteres + form.setInputValue('targetField.input', 'target_field'); + form.setInputValue('regexFileField.input', 'hello*'); + form.toggleEuiSwitch('ignoreMissingSwitch.input'); + form.toggleEuiSwitch('ignoreFailureSwitch.input'); + form.toggleEuiSwitch('extractDeviceTypeSwitch.input'); + await act(async () => { + find('propertiesValueField').simulate('change', [{ label: 'os' }]); + }); + component.update(); + + // Save the field with new changes + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, USER_AGENT_TYPE); + expect(processors[0][USER_AGENT_TYPE]).toEqual({ + ...defaultUserAgentParameters, + field: 'field_1', + target_field: 'target_field', + properties: ['os'], + regex_file: 'hello*', + extract_device_type: true, + ignore_missing: true, + ignore_failure: true, + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/common_fields/properties_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/common_fields/properties_field.tsx index dd52375a1943..c8a50cf64484 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/common_fields/properties_field.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/common_fields/properties_field.tsx @@ -6,9 +6,9 @@ */ import React, { FunctionComponent } from 'react'; +import { EuiComboBoxProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { EuiComboBoxOptionOption } from '@elastic/eui'; import { ComboBoxField, FIELD_TYPES, UseField } from '../../../../../../../shared_imports'; import { FieldsConfig, to } from '../shared'; @@ -29,10 +29,10 @@ const fieldsConfig: FieldsConfig = { interface Props { helpText?: React.ReactNode; - propertyOptions?: EuiComboBoxOptionOption[]; + euiFieldProps?: EuiComboBoxProps; } -export const PropertiesField: FunctionComponent = ({ helpText, propertyOptions }) => { +export const PropertiesField: FunctionComponent = ({ helpText, euiFieldProps }) => { return ( = ({ helpText, propertyOp }} component={ComboBoxField} path="fields.properties" - componentProps={{ - euiFieldProps: { - options: propertyOptions || [], - noSuggestions: !propertyOptions, - }, - }} + componentProps={{ euiFieldProps }} /> ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx index 893e52bcc007..2b5a68f799b7 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx @@ -6,20 +6,20 @@ */ import React, { FunctionComponent } from 'react'; -import { EuiCode } from '@elastic/eui'; +import { EuiCode, EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { EuiComboBoxOptionOption } from '@elastic/eui'; -import { FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports'; +import { FIELD_TYPES, ToggleField, UseField, Field } from '../../../../../../shared_imports'; -import { FieldsConfig, from } from './shared'; +import { FieldsConfig, from, to } from './shared'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; import { FieldNameField } from './common_fields/field_name_field'; import { TargetField } from './common_fields/target_field'; import { PropertiesField } from './common_fields/properties_field'; -const propertyOptions: EuiComboBoxOptionOption[] = [ +const propertyOptions: Array> = [ { label: 'name' }, { label: 'os' }, { label: 'device' }, @@ -47,6 +47,18 @@ const fieldsConfig: FieldsConfig = { } ), }, + extract_device_type: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + deserializer: to.booleanOrUndef, + serializer: from.undefinedIfValue(false), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.userAgentForm.extractDeviceTypeFieldHelpText', + { + defaultMessage: 'Extracts device type from the user agent string.', + } + ), + }, }; export const UserAgent: FunctionComponent = () => { @@ -59,7 +71,12 @@ export const UserAgent: FunctionComponent = () => { )} /> - + { 'xpack.ingestPipelines.pipelineEditor.userAgentForm.propertiesFieldHelpText', { defaultMessage: 'Properties added to the target field.' } )} - propertyOptions={propertyOptions} + euiFieldProps={{ + options: propertyOptions, + noSuggestions: false, + 'data-test-subj': 'propertiesValueField', + }} + /> + + + + + + + + +
+ ), + }} /> diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts index 0d44ae3aa6de..8615ed653631 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts @@ -15,8 +15,6 @@ import type { LensToggleAction, } from './types'; import { ColumnConfig } from './table_basic'; - -import { desanitizeFilterContext } from '../../utils'; import { getOriginalId } from '../transpose_helpers'; export const createGridResizeHandler = ( @@ -92,7 +90,7 @@ export const createGridFilterHandler = ( timeFieldName, }; - onClickValue(desanitizeFilterContext(data)); + onClickValue(data); }; export const createTransposeColumnFilterHandler = ( @@ -125,7 +123,7 @@ export const createTransposeColumnFilterHandler = ( timeFieldName, }; - onClickValue(desanitizeFilterContext(data)); + onClickValue(data); }; export const createGridSortingConfig = ( diff --git a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx index 3048f3b3db58..8214d5ba129d 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx @@ -21,7 +21,6 @@ import { VisualizationContainer } from '../visualization_container'; import { HeatmapRenderProps } from './types'; import './index.scss'; import { LensBrushEvent, LensFilterEvent } from '../types'; -import { desanitizeFilterContext } from '../utils'; import { EmptyPlaceholder } from '../shared_components'; import { LensIconChartHeatmap } from '../assets/chart_heatmap'; @@ -117,7 +116,7 @@ export const HeatmapComponent: FC = ({ })), timeFieldName, }; - onClickValue(desanitizeFilterContext(context)); + onClickValue(context); }) as ElementClickListener; const onBrushEnd = (e: HeatmapBrushEvent) => { @@ -164,7 +163,7 @@ export const HeatmapComponent: FC = ({ })), timeFieldName, }; - onClickValue(desanitizeFilterContext(context)); + onClickValue(context); } }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index b35986c42054..05100567c1b0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -117,21 +117,14 @@ export function DimensionEditor(props: DimensionEditorProps) { const setStateWrapper = ( setter: IndexPatternLayer | ((prevLayer: IndexPatternLayer) => IndexPatternLayer) ) => { - const prevOperationType = - operationDefinitionMap[state.layers[layerId].columns[columnId]?.operationType]?.input; - const hypotheticalLayer = typeof setter === 'function' ? setter(state.layers[layerId]) : setter; - const hasIncompleteColumns = Boolean(hypotheticalLayer.incompleteColumns?.[columnId]); setState( (prevState) => { const layer = typeof setter === 'function' ? setter(prevState.layers[layerId]) : setter; return mergeLayer({ state: prevState, layerId, newLayer: layer }); }, { - isDimensionComplete: - prevOperationType === 'fullReference' - ? !hasIncompleteColumns - : Boolean(hypotheticalLayer.columns[columnId]), + isDimensionComplete: Boolean(hypotheticalLayer.columns[columnId]), } ); }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index afcecdf5be9b..d757d8573f25 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -908,20 +908,21 @@ describe('IndexPatternDimensionEditorPanel', () => { }); }); - it('should clean up when transitioning from incomplete reference-based operations to field operation', () => { + it('should keep current state and write incomplete column when transitioning from incomplete reference-based operations to field operation', () => { + const baseState = getStateWithColumns({ + ...defaultProps.state.layers.first.columns, + col2: { + label: 'Counter rate', + dataType: 'number', + isBucketed: false, + operationType: 'counter_rate', + references: ['ref'], + }, + }); wrapper = mount( ); @@ -932,15 +933,12 @@ describe('IndexPatternDimensionEditorPanel', () => { .simulate('click'); // Now check that the dimension gets cleaned up on state update - expect(setState.mock.calls[0]).toEqual([ - expect.any(Function), - { isDimensionComplete: false }, - ]); + expect(setState.mock.calls[0]).toEqual([expect.any(Function), { isDimensionComplete: true }]); expect(setState.mock.calls[0][0](state)).toEqual({ - ...state, + ...baseState, layers: { first: { - ...state.layers.first, + ...baseState.layers.first, incompleteColumns: { col2: { operationType: 'average' }, }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts index 7de1318cbac6..9eedae6d82d4 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts @@ -1917,6 +1917,54 @@ describe('state_helpers', () => { }) ); }); + + it('should keep state and set incomplete column on incompatible switch', () => { + const layer: IndexPatternLayer = { + indexPatternId: '1', + columnOrder: ['metric', 'ref'], + columns: { + metric: { + dataType: 'number' as const, + isBucketed: false, + sourceField: 'source', + operationType: 'unique_count' as const, + filter: { language: 'kuery', query: 'bytes > 4000' }, + timeShift: '3h', + label: 'Cardinality', + customLabel: true, + }, + ref: { + label: 'Reference', + dataType: 'number', + isBucketed: false, + operationType: 'differences', + references: ['metric'], + filter: { language: 'kuery', query: 'bytes > 4000' }, + timeShift: '3h', + }, + }, + }; + const result = replaceColumn({ + layer, + indexPattern, + columnId: 'ref', + op: 'sum', + visualizationGroups: [], + }); + expect(result.columnOrder).toEqual(layer.columnOrder); + expect(result.columns).toEqual(layer.columns); + expect(result.incompleteColumns).toEqual({ + ref: { + operationType: 'sum', + filter: { + language: 'kuery', + query: 'bytes > 4000', + }, + timeScale: undefined, + timeShift: '3h', + }, + }); + }); }); it('should allow making a replacement on an operation that is being referenced, even if it ends up invalid', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index fd3df9f97cec..b5b1960b7b76 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -19,6 +19,7 @@ import { OperationType, IndexPatternColumn, RequiredReference, + OperationDefinition, GenericOperationDefinition, } from './definitions'; import type { @@ -532,20 +533,15 @@ export function replaceColumn({ ); } - // This logic comes after the transitions because they need to look at previous columns - if (previousDefinition.input === 'fullReference') { - (previousColumn as ReferenceBasedIndexPatternColumn).references.forEach((id: string) => { - tempLayer = deleteColumn({ - layer: tempLayer, - columnId: id, - indexPattern, - }); - }); - } - if (operationDefinition.input === 'none') { let newColumn = operationDefinition.buildColumn({ ...baseOptions, layer: tempLayer }); newColumn = copyCustomLabel(newColumn, previousColumn); + tempLayer = removeOrphanedColumns( + previousDefinition, + previousColumn, + tempLayer, + indexPattern + ); const newLayer = { ...tempLayer, columns: { ...tempLayer.columns, [columnId]: newColumn } }; return updateDefaultLabels( @@ -564,7 +560,6 @@ export function replaceColumn({ } & ColumnAdvancedParams = { operationType: op }; // if no field is available perform a full clean of the column from the layer if (previousDefinition.input === 'fullReference') { - tempLayer = deleteColumn({ layer: tempLayer, columnId, indexPattern }); const previousReferenceId = (previousColumn as ReferenceBasedIndexPatternColumn) .references[0]; const referenceColumn = layer.columns[previousReferenceId]; @@ -598,6 +593,8 @@ export function replaceColumn({ }; } + tempLayer = removeOrphanedColumns(previousDefinition, previousColumn, tempLayer, indexPattern); + let newColumn = operationDefinition.buildColumn({ ...baseOptions, layer: tempLayer, field }); if (!shouldResetLabel) { newColumn = copyCustomLabel(newColumn, previousColumn); @@ -637,6 +634,27 @@ export function replaceColumn({ } } +function removeOrphanedColumns( + previousDefinition: + | OperationDefinition + | OperationDefinition + | OperationDefinition, + previousColumn: IndexPatternColumn, + tempLayer: IndexPatternLayer, + indexPattern: IndexPattern +) { + if (previousDefinition.input === 'fullReference') { + (previousColumn as ReferenceBasedIndexPatternColumn).references.forEach((id: string) => { + tempLayer = deleteColumn({ + layer: tempLayer, + columnId: id, + indexPattern, + }); + }); + } + return tempLayer; +} + export function canTransition({ layer, columnId, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.test.ts index 0750b99db5f6..5654a599c5e2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.test.ts @@ -83,29 +83,6 @@ describe('rename_columns', () => { `); }); - it('should replace "" with a visible value', () => { - const input: Datatable = { - type: 'datatable', - columns: [{ id: 'a', name: 'A', meta: { type: 'string' } }], - rows: [{ a: '' }], - }; - - const idMap = { - a: { - id: 'a', - label: 'Austrailia', - }, - }; - - const result = renameColumns.fn( - input, - { idMap: JSON.stringify(idMap) }, - createMockExecutionContext() - ); - - expect(result.rows[0].a).toEqual('(empty)'); - }); - it('should keep columns which are not mapped', () => { const input: Datatable = { type: 'datatable', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.ts b/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.ts index 89c63880248d..a16756126c03 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/rename_columns.ts @@ -49,9 +49,9 @@ export const renameColumns: ExpressionFunctionDefinition< Object.entries(row).forEach(([id, value]) => { if (id in idMap) { - mappedRow[idMap[id].id] = sanitizeValue(value); + mappedRow[idMap[id].id] = value; } else { - mappedRow[id] = sanitizeValue(value); + mappedRow[id] = value; } }); @@ -86,13 +86,3 @@ function getColumnName(originalColumn: OriginalColumn, newColumn: DatatableColum return originalColumn.label; } - -function sanitizeValue(value: unknown) { - if (value === '') { - return i18n.translate('xpack.lens.indexpattern.emptyTextColumnValue', { - defaultMessage: '(empty)', - }); - } - - return value; -} diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index f329cfe1bb8b..2e5a06b4f705 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -31,7 +31,6 @@ import { PieExpressionProps } from './types'; import { getSliceValue, getFilterContext } from './render_helpers'; import { EmptyPlaceholder } from '../shared_components'; import './visualization.scss'; -import { desanitizeFilterContext } from '../utils'; import { ChartsPluginSetup, PaletteRegistry, @@ -254,7 +253,7 @@ export function PieComponent( const onElementClickHandler: ElementClickListener = (args) => { const context = getFilterContext(args[0][0] as LayerValue[], groups, firstTable); - onClickValue(desanitizeFilterContext(context)); + onClickValue(context); }; return ( diff --git a/x-pack/plugins/lens/public/shared_components/legend_action_popover.tsx b/x-pack/plugins/lens/public/shared_components/legend_action_popover.tsx index e344cb5289f5..5027629ef6ae 100644 --- a/x-pack/plugins/lens/public/shared_components/legend_action_popover.tsx +++ b/x-pack/plugins/lens/public/shared_components/legend_action_popover.tsx @@ -9,7 +9,6 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiContextMenuPanelDescriptor, EuiIcon, EuiPopover, EuiContextMenu } from '@elastic/eui'; import type { LensFilterEvent } from '../types'; -import { desanitizeFilterContext } from '../utils'; export interface LegendActionPopoverProps { /** @@ -45,7 +44,7 @@ export const LegendActionPopover: React.FunctionComponent, onClick: () => { setPopoverOpen(false); - onFilter(desanitizeFilterContext(context)); + onFilter(context); }, }, { @@ -56,7 +55,7 @@ export const LegendActionPopover: React.FunctionComponent, onClick: () => { setPopoverOpen(false); - onFilter(desanitizeFilterContext({ ...context, negate: true })); + onFilter({ ...context, negate: true }); }, }, ], diff --git a/x-pack/plugins/lens/public/utils.test.ts b/x-pack/plugins/lens/public/utils.test.ts deleted file mode 100644 index 76597870b3be..000000000000 --- a/x-pack/plugins/lens/public/utils.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { LensFilterEvent } from './types'; -import { desanitizeFilterContext } from './utils'; -import { Datatable } from '../../../../src/plugins/expressions/common'; - -describe('desanitizeFilterContext', () => { - it(`When filtered value equals '(empty)' replaces it with '' in table and in value.`, () => { - const table: Datatable = { - type: 'datatable', - rows: [ - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414640000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '(empty)', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414670000, - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 0, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414880000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '123123123', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414910000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '(empty)', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - ], - columns: [ - { - id: 'f903668f-1175-4705-a5bd-713259d10326', - name: 'order_date per 30 seconds', - meta: { type: 'date' }, - }, - { - id: '5d5446b2-72e8-4f86-91e0-88380f0fa14c', - name: 'Top values of customer_phone', - meta: { type: 'string' }, - }, - { - id: '9f0b6f88-c399-43a0-a993-0ad943c9af25', - name: 'Count of records', - meta: { type: 'number' }, - }, - ], - }; - - const contextWithEmptyValue: LensFilterEvent['data'] = { - data: [ - { - row: 3, - column: 0, - value: 1589414910000, - table, - }, - { - row: 0, - column: 1, - value: '(empty)', - table, - }, - ], - timeFieldName: 'order_date', - }; - - const desanitizedFilterContext = desanitizeFilterContext(contextWithEmptyValue); - - expect(desanitizedFilterContext).toEqual({ - data: [ - { - row: 3, - column: 0, - value: 1589414910000, - table, - }, - { - value: '', - row: 0, - column: 1, - table: { - rows: [ - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414640000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414670000, - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 0, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414880000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '123123123', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - { - 'f903668f-1175-4705-a5bd-713259d10326': 1589414910000, - '5d5446b2-72e8-4f86-91e0-88380f0fa14c': '(empty)', - 'col-1-9f0b6f88-c399-43a0-a993-0ad943c9af25': 1, - }, - ], - columns: table.columns, - type: 'datatable', - }, - }, - ], - timeFieldName: 'order_date', - }); - }); -}); diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 2706fe977c68..1c4b2c67f96f 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -9,42 +9,6 @@ import { i18n } from '@kbn/i18n'; import { IndexPattern, IndexPatternsContract, TimefilterContract } from 'src/plugins/data/public'; import { IUiSettingsClient } from 'kibana/public'; import moment from 'moment-timezone'; -import { LensFilterEvent } from './types'; - -/** replaces the value `(empty) to empty string for proper filtering` */ -export const desanitizeFilterContext = ( - context: LensFilterEvent['data'] -): LensFilterEvent['data'] => { - const emptyTextValue = i18n.translate('xpack.lens.indexpattern.emptyTextColumnValue', { - defaultMessage: '(empty)', - }); - const result: LensFilterEvent['data'] = { - ...context, - data: context.data.map((point) => - point.value === emptyTextValue - ? { - ...point, - value: '', - table: { - ...point.table, - rows: point.table.rows.map((row, index) => - index === point.row - ? { - ...row, - [point.table.columns[point.column].id]: '', - } - : row - ), - }, - } - : point - ), - }; - if (context.timeFieldName) { - result.timeFieldName = context.timeFieldName; - } - return result; -}; export function getVisualizeGeoFieldMessage(fieldType: string) { return i18n.translate('xpack.lens.visualizeGeoFieldMessage', { diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 1de5cf6b3053..3fe98282a18b 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -53,7 +53,6 @@ import { SeriesLayer, } from '../../../../../src/plugins/charts/public'; import { EmptyPlaceholder } from '../shared_components'; -import { desanitizeFilterContext } from '../utils'; import { fittingFunctionDefinitions, getFitOptions } from './fitting_functions'; import { getAxesConfiguration, GroupsConfiguration, validateExtent } from './axes_configuration'; import { getColorAssignments } from './color_assignment'; @@ -575,7 +574,7 @@ export function XYChart({ })), timeFieldName: xDomain && isDateField ? xAxisFieldName : undefined, }; - onClickValue(desanitizeFilterContext(context)); + onClickValue(context); }; const brushHandler: BrushEndListener = ({ x }) => { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts index 73739b7db12e..eb8af4f26c01 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts @@ -272,7 +272,7 @@ export const CARRIER_LOCATION = i18n.translate( export const RESPONSE_LATENCY = i18n.translate( 'xpack.observability.expView.fieldLabels.responseLatency', { - defaultMessage: 'Response latency', + defaultMessage: 'Latency', } ); @@ -294,7 +294,7 @@ export const CPU_USAGE = i18n.translate('xpack.observability.expView.fieldLabels export const TRANSACTIONS_PER_MINUTE = i18n.translate( 'xpack.observability.expView.fieldLabels.transactionPerMinute', { - defaultMessage: 'Transactions per minute', + defaultMessage: 'Throughput', } ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/mobile/kpi_over_time_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/mobile/kpi_over_time_config.ts index 2ed4d95760db..9a2e86a8f796 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/mobile/kpi_over_time_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/mobile/kpi_over_time_config.ts @@ -71,18 +71,6 @@ export function getMobileKPIConfig({ indexPattern }: ConfigProps): DataSeries { id: TRANSACTION_DURATION, columnType: OPERATION_COLUMN, }, - { - label: MEMORY_USAGE, - field: METRIC_SYSTEM_MEMORY_USAGE, - id: METRIC_SYSTEM_MEMORY_USAGE, - columnType: OPERATION_COLUMN, - }, - { - label: CPU_USAGE, - field: METRIC_SYSTEM_CPU_USAGE, - id: METRIC_SYSTEM_CPU_USAGE, - columnType: OPERATION_COLUMN, - }, { field: RECORDS_FIELD, id: RECORDS_FIELD, @@ -95,6 +83,18 @@ export function getMobileKPIConfig({ indexPattern }: ConfigProps): DataSeries { ], timeScale: 'm', }, + { + label: MEMORY_USAGE, + field: METRIC_SYSTEM_MEMORY_USAGE, + id: METRIC_SYSTEM_MEMORY_USAGE, + columnType: OPERATION_COLUMN, + }, + { + label: CPU_USAGE, + field: METRIC_SYSTEM_CPU_USAGE, + id: METRIC_SYSTEM_CPU_USAGE, + columnType: OPERATION_COLUMN, + }, ], }, ], diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index d4936783a029..9219f29e4d9f 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -10,7 +10,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import { ScopedHistory } from 'kibana/public'; -import { EuiErrorBoundary } from '@elastic/eui'; +import { EuiErrorBoundary, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -35,7 +35,7 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => { title={ } error={apiError} @@ -44,21 +44,23 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => { } return ( -
- - - - - - - -
+ + + + + + + + + + + ); }; diff --git a/x-pack/plugins/transform/public/app/components/section_error.tsx b/x-pack/plugins/transform/public/app/components/section_error.tsx index 2af0c19fb881..964c13d775d4 100644 --- a/x-pack/plugins/transform/public/app/components/section_error.tsx +++ b/x-pack/plugins/transform/public/app/components/section_error.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiCallOut } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiPageContent } from '@elastic/eui'; import React from 'react'; interface Props { @@ -23,9 +23,17 @@ export const SectionError: React.FunctionComponent = ({ const errorMessage = error?.message ?? JSON.stringify(error, null, 2); return ( - -
{errorMessage}
- {actions ? actions : null} -
+ + {title}} + body={ +

+

{errorMessage}
+ {actions ? actions : null} +

+ } + /> +
); }; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx index ef009e6a125e..cdf4407b4233 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx @@ -7,7 +7,7 @@ import React, { useContext, FC } from 'react'; -import { EuiPageContent } from '@elastic/eui'; +import { EuiFlexItem, EuiFlexGroup, EuiPageContent } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -74,27 +74,31 @@ const MissingClusterPrivileges: FC = ({ missingPrivileges, privilegesCount, }) => ( - - - } - message={ - + + + + } + message={ + + } /> - } - /> - + +
+
); export const PrivilegesWrapper: FC<{ privileges: string | string[] }> = ({ diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index e4ecc0418d78..8aecf403186c 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -15,12 +15,9 @@ import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiPageContent, EuiPageContentBody, + EuiPageHeader, EuiSpacer, - EuiTitle, } from '@elastic/eui'; import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; @@ -105,37 +102,38 @@ export const CloneTransformSection: FC = ({ match, location }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const docsLink = ( + + + + ); + return ( - - - - -

- -

-
- - - - - -
-
- - - {typeof errorMessage !== 'undefined' && ( + + } + rightSideItems={[docsLink]} + bottomBorder + /> + + + + + {typeof errorMessage !== 'undefined' && ( + <> = ({ match, location }) => { >
{JSON.stringify(errorMessage)}
- )} - {searchItems !== undefined && isInitialized === true && transformConfig !== undefined && ( - - )} -
-
+ + + )} + {searchItems !== undefined && isInitialized === true && transformConfig !== undefined && ( + + )} +
); }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx index b88eb8ce4860..d736bd60f2df 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx @@ -13,12 +13,9 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiPageContent, EuiPageContentBody, + EuiPageHeader, EuiSpacer, - EuiTitle, } from '@elastic/eui'; import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; @@ -42,42 +39,44 @@ export const CreateTransformSection: FC = ({ match }) => { const { error: searchItemsError, searchItems } = useSearchItems(match.params.savedObjectId); + const docsLink = ( + + + + ); + return ( - - - - -

- -

-
- - - - - -
-
- - - {searchItemsError !== undefined && ( + + } + rightSideItems={[docsLink]} + bottomBorder + /> + + + + + {searchItemsError !== undefined && ( + <> - )} - {searchItems !== undefined && } - -
+ + + )} + {searchItems !== undefined && } +
); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap index e2de4c0ea1f6..cf8042171135 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap @@ -1,23 +1,42 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Transform List Minimal initialization 1`] = ` - - Create your first transform - , - ] - } - data-test-subj="transformNoTransformsFound" - title={ -

- No transforms found -

- } -/> + + + + + + Create your first transform + , + ] + } + data-test-subj="transformNoTransformsFound" + title={ +

+ No transforms found +

+ } + /> +
+
+
`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index bacf8f9decca..ab30f4793a31 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -10,12 +10,15 @@ import React, { MouseEventHandler, FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { + EuiButton, EuiButtonEmpty, EuiButtonIcon, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, + EuiPageContent, EuiPopover, + EuiSpacer, EuiTitle, EuiInMemoryTable, EuiSearchBarProps, @@ -135,27 +138,36 @@ export const TransformList: FC = ({ if (transforms.length === 0) { return ( - - {i18n.translate('xpack.transform.list.emptyPromptTitle', { - defaultMessage: 'No transforms found', - })} - - } - actions={[ - - {i18n.translate('xpack.transform.list.emptyPromptButtonText', { - defaultMessage: 'Create your first transform', - })} - , - ]} - data-test-subj="transformNoTransformsFound" - /> + + + + + + {i18n.translate('xpack.transform.list.emptyPromptTitle', { + defaultMessage: 'No transforms found', + })} + + } + actions={[ + + {i18n.translate('xpack.transform.list.emptyPromptButtonText', { + defaultMessage: 'Create your first transform', + })} + , + ]} + data-test-subj="transformNoTransformsFound" + /> + + + ); } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index cc4c502f21eb..2479d34f1579 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -5,23 +5,21 @@ * 2.0. */ -import React, { FC, Fragment, useEffect, useState } from 'react'; +import React, { FC, useEffect, useState } from 'react'; -import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, - EuiCallOut, + EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiLoadingContent, EuiModal, EuiPageContent, EuiPageContentBody, + EuiPageHeader, EuiSpacer, - EuiText, - EuiTitle, } from '@elastic/eui'; import { APP_GET_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; @@ -77,73 +75,91 @@ export const TransformManagement: FC = () => { setSavedObjectId(id); }; + const docsLink = ( + + + + ); + return ( - - - - - -

- -

-
- - - - - -
-
- - - + <> + - - - - - {!isInitialized && } - {isInitialized && ( - <> - - - {typeof errorMessage !== 'undefined' && ( - -
{JSON.stringify(errorMessage)}
-
- )} - {typeof errorMessage === 'undefined' && ( - - )} - - )} -
-
+ + } + description={ + + } + rightSideItems={[docsLink]} + bottomBorder + /> + + + + + {!isInitialized && } + {isInitialized && ( + <> + + + {typeof errorMessage !== 'undefined' && ( + + + + + + + + } + body={ +

+

{JSON.stringify(errorMessage)}
+

+ } + actions={[]} + /> +
+
+
+ )} + {typeof errorMessage === 'undefined' && ( + + )} + + )} +
+ {isSearchSelectionVisible && ( { )} -
+ ); }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 17c31b8cd115..837716ec9dd5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4941,8 +4941,6 @@ "visTypePie.editors.pie.showLabelsLabel": "ラベルを表示", "visTypePie.editors.pie.showTopLevelOnlyLabel": "トップレベルのみ表示", "visTypePie.editors.pie.showValuesLabel": "値を表示", - "visualizations.advancedSettings.visualization.legacyChartsLibrary.description": "Visualizeでエリア、折れ線、棒グラフのレガシーグラフライブラリを有効にします。", - "visualizations.advancedSettings.visualization.legacyChartsLibrary.name": "レガシーグラフライブラリ", "visualizations.advancedSettings.visualizeEnableLabsText": "ユーザーが実験的なビジュアライゼーションを作成、表示、編集できるようになります。無効の場合、\n ユーザーは本番準備が整ったビジュアライゼーションのみを利用できます。", "visualizations.advancedSettings.visualizeEnableLabsTitle": "実験的なビジュアライゼーションを有効にする", "visualizations.disabledLabVisualizationLink": "ドキュメンテーションを表示", @@ -5057,7 +5055,6 @@ "visTypeXy.editors.pointSeries.thresholdLine.valueLabel": "しきい値", "visTypeXy.editors.pointSeries.thresholdLine.widthLabel": "線の幅", "visTypeXy.editors.pointSeries.thresholdLineSettingsTitle": "しきい線", - "visTypeXy.emptyTextColumnValue": " (空) ", "visTypeXy.fittingFunctionsTitle.carry": "最後 (ギャップを最後の値で埋める) ", "visTypeXy.fittingFunctionsTitle.linear": "線形 (ギャップを線で埋める) ", "visTypeXy.fittingFunctionsTitle.lookahead": "次 (ギャップを次の値で埋める) ", @@ -5976,9 +5973,6 @@ "xpack.banners.settings.textColor.description": "バナーテキストの色を設定します。{subscriptionLink}", "xpack.banners.settings.textColor.title": "バナーテキスト色", "xpack.banners.settings.textContent.title": "バナーテキスト", - "xpack.canvas.app.loadErrorMessage": "メッセージ:{error}", - "xpack.canvas.app.loadErrorTitle": "Canvas の読み込みに失敗", - "xpack.canvas.app.loadingMessage": "Canvas を読み込み中", "xpack.canvas.appDescription": "データを完璧に美しく表現します。", "xpack.canvas.argAddPopover.addAriaLabel": "引数を追加", "xpack.canvas.argFormAdvancedFailure.applyButtonLabel": "適用", @@ -5996,8 +5990,6 @@ "xpack.canvas.asset.deleteAssetTooltip": "削除", "xpack.canvas.asset.downloadAssetTooltip": "ダウンロード", "xpack.canvas.asset.thumbnailAltText": "アセットのサムネイル", - "xpack.canvas.assetManager.manageButtonLabel": "アセットの管理", - "xpack.canvas.assetModal.copyAssetMessage": "「{id}」をクリップボードにコピーしました", "xpack.canvas.assetModal.emptyAssetsDescription": "アセットをインポートして開始します", "xpack.canvas.assetModal.filePickerPromptText": "画像を選択するかドラッグ &amp; ドロップしてください", "xpack.canvas.assetModal.loadingText": "画像をアップロード中", @@ -6020,7 +6012,6 @@ "xpack.canvas.customElementModal.nameInputLabel": "名前", "xpack.canvas.customElementModal.remainingCharactersDescription": "残り {numberOfRemainingCharacter} 文字", "xpack.canvas.customElementModal.saveButtonLabel": "保存", - "xpack.canvas.datasourceDatasourceComponent.changeButtonLabel": "要素データソースの変更", "xpack.canvas.datasourceDatasourceComponent.expressionArgDescription": "データソースの引数は式で制御されます。式エディターを使用して、データソースを修正します。", "xpack.canvas.datasourceDatasourceComponent.previewButtonLabel": "データをプレビュー", "xpack.canvas.datasourceDatasourceComponent.saveButtonLabel": "保存", @@ -6449,8 +6440,6 @@ "xpack.canvas.groupSettings.saveGroupDescription": "ワークパッド全体で再利用できるように、このグループを新規エレメントとして保存します。", "xpack.canvas.groupSettings.ungroupDescription": "個々のエレメントの設定を編集できるように、 ({uKey}) のグループを解除します。", "xpack.canvas.helpMenu.appName": "Canvas", - "xpack.canvas.helpMenu.description": "{CANVAS} に関する情報", - "xpack.canvas.helpMenu.documentationLinkLabel": "{CANVAS} ドキュメント", "xpack.canvas.helpMenu.keyboardShortcutsLinkLabel": "キーボードショートカット", "xpack.canvas.home.myWorkpadsTabLabel": "マイワークパッド", "xpack.canvas.home.workpadTemplatesTabLabel": "テンプレート", @@ -6517,7 +6506,6 @@ "xpack.canvas.lib.palettes.yellowBlueLabel": "黄、青", "xpack.canvas.lib.palettes.yellowGreenLabel": "黄、緑", "xpack.canvas.lib.palettes.yellowRedLabel": "黄、赤", - "xpack.canvas.link.errorMessage": "リンクエラー:{message}", "xpack.canvas.pageConfig.backgroundColorDescription": "HEX、RGB、また HTML 色名が使用できます", "xpack.canvas.pageConfig.backgroundColorLabel": "背景", "xpack.canvas.pageConfig.title": "ページ設定", @@ -6527,7 +6515,6 @@ "xpack.canvas.pageManager.addPageTooltip": "新しいページをこのワークパッドに追加", "xpack.canvas.pageManager.confirmRemoveDescription": "このページを削除してよろしいですか?", "xpack.canvas.pageManager.confirmRemoveTitle": "ページを削除", - "xpack.canvas.pageManager.pageNumberAriaLabel": "ページ番号 {pageNumber} を読み込む", "xpack.canvas.pageManager.removeButtonLabel": "削除", "xpack.canvas.pagePreviewPageControls.clonePageAriaLabel": "ページのクローンを作成", "xpack.canvas.pagePreviewPageControls.clonePageTooltip": "クローンを作成", @@ -6579,10 +6566,8 @@ "xpack.canvas.savedElementsModal.deleteElementDescription": "このエレメントを削除してよろしいですか?", "xpack.canvas.savedElementsModal.deleteElementTitle": "要素'{elementName}'を削除しますか?", "xpack.canvas.savedElementsModal.editElementTitle": "エレメントを編集", - "xpack.canvas.savedElementsModal.elementsTitle": "エレメント", "xpack.canvas.savedElementsModal.findElementPlaceholder": "エレメントを検索", "xpack.canvas.savedElementsModal.modalTitle": "マイエレメント", - "xpack.canvas.savedElementsModal.myElementsTitle": "マイエレメント", "xpack.canvas.shareWebsiteFlyout.description": "外部 Web サイトでこのワークパッドの不動バージョンを共有するには、これらの手順に従ってください。現在のワークパッドのビジュアルスナップショットになり、ライブデータにはアクセスできません。", "xpack.canvas.shareWebsiteFlyout.flyoutCalloutDescription": "共有するには、このワークパッド、{CANVAS} シェアラブルワークパッドランタイム、サンプル {HTML} ファイルを含む {link} を使用します。", "xpack.canvas.shareWebsiteFlyout.flyoutTitle": "Webサイトで共有", @@ -6637,13 +6622,10 @@ "xpack.canvas.textStylePicker.styleItalicOption": "斜体", "xpack.canvas.textStylePicker.styleOptionsControl": "スタイルオプション", "xpack.canvas.textStylePicker.styleUnderlineOption": "下線", - "xpack.canvas.timePicker.applyButtonLabel": "適用", "xpack.canvas.toolbar.editorButtonLabel": "表現エディター", - "xpack.canvas.toolbar.errorMessage": "ツールバーエラー:{message}", "xpack.canvas.toolbar.nextPageAriaLabel": "次のページ", "xpack.canvas.toolbar.pageButtonLabel": "{pageNum}{rest} ページ", "xpack.canvas.toolbar.previousPageAriaLabel": "前のページ", - "xpack.canvas.toolbar.workpadManagerCloseButtonLabel": "閉じる", "xpack.canvas.toolbarTray.closeTrayAriaLabel": "トレイのクローンを作成", "xpack.canvas.transitions.fade.displayName": "フェード", "xpack.canvas.transitions.fade.help": "ページからページへフェードします", @@ -6905,20 +6887,8 @@ "xpack.canvas.units.quickRange.today": "今日", "xpack.canvas.units.quickRange.yesterday": "昨日", "xpack.canvas.useCloneWorkpad.clonedWorkpadName": "{workpadName} のコピー", - "xpack.canvas.varConfig.addButtonLabel": "変数の追加", - "xpack.canvas.varConfig.addTooltipLabel": "変数の追加", - "xpack.canvas.varConfig.copyActionButtonLabel": "スニペットをコピー", - "xpack.canvas.varConfig.copyActionTooltipLabel": "変数構文をクリップボードにコピー", "xpack.canvas.varConfig.copyNotificationDescription": "変数構文がクリップボードにコピーされました", - "xpack.canvas.varConfig.deleteActionButtonLabel": "変数の削除", "xpack.canvas.varConfig.deleteNotificationDescription": "変数の削除が正常に完了しました", - "xpack.canvas.varConfig.editActionButtonLabel": "変数の編集", - "xpack.canvas.varConfig.emptyDescription": "このワークパッドには現在変数がありません。変数を追加して、共通の値を格納したり、編集したりすることができます。これらの変数は、要素または式エディターで使用できます。", - "xpack.canvas.varConfig.tableNameLabel": "名前", - "xpack.canvas.varConfig.tableTypeLabel": "型", - "xpack.canvas.varConfig.tableValueLabel": "値", - "xpack.canvas.varConfig.titleLabel": "変数", - "xpack.canvas.varConfig.titleTooltip": "変数を追加して、共通の値を格納したり、編集したりします", "xpack.canvas.varConfigDeleteVar.cancelButtonLabel": "キャンセル", "xpack.canvas.varConfigDeleteVar.deleteButtonLabel": "変数の削除", "xpack.canvas.varConfigDeleteVar.titleLabel": "変数を削除しますか?", @@ -6952,7 +6922,6 @@ "xpack.canvas.workpadConfig.USLetterButtonLabel": "US レター", "xpack.canvas.workpadConfig.widthLabel": "幅", "xpack.canvas.workpadCreate.createButtonLabel": "ワークパッドを作成", - "xpack.canvas.workpadHeader.addElementButtonLabel": "エレメントを追加", "xpack.canvas.workpadHeader.addElementModalCloseButtonLabel": "閉じる", "xpack.canvas.workpadHeader.fullscreenButtonAriaLabel": "全画面表示", "xpack.canvas.workpadHeader.fullscreenTooltip": "全画面モードを開始します", @@ -6999,10 +6968,8 @@ "xpack.canvas.workpadHeaderElementMenu.textMenuItemLabel": "テキスト", "xpack.canvas.workpadHeaderKioskControl.controlTitle": "全画面ページのサイクル", "xpack.canvas.workpadHeaderKioskControl.cycleFormLabel": "サイクル間隔を変更", - "xpack.canvas.workpadHeaderKioskControl.cycleToggleSwitch": "スライドを自動的にサイクル", "xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel": "エレメントを更新", "xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip": "データを更新", - "xpack.canvas.workpadHeaderShareMenu.copyPDFMessage": "{PDF}生成{URL}がクリップボードにコピーされました。", "xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage": "共有マークアップがクリップボードにコピーされました", "xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle": "{JSON} をダウンロード", "xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle": "{PDF}レポート", @@ -7012,8 +6979,6 @@ "xpack.canvas.workpadHeaderShareMenu.shareWorkpadMessage": "このワークパッドを共有", "xpack.canvas.workpadHeaderShareMenu.unknownExportErrorMessage": "不明なエクスポートタイプ:{type}", "xpack.canvas.workpadHeaderShareMenu.unsupportedRendererWarning": "このワークパッドには、{CANVAS}シェアラブルワークパッドランタイムがサポートしていないレンダリング関数が含まれています。これらのエレメントはレンダリングされません:", - "xpack.canvas.workpadHeaderViewMenu.autoplayOffMenuItemLabel": "自動再生をオフにする", - "xpack.canvas.workpadHeaderViewMenu.autoplayOnMenuItemLabel": "自動再生をオンにする", "xpack.canvas.workpadHeaderViewMenu.autoplaySettingsMenuItemLabel": "自動再生設定", "xpack.canvas.workpadHeaderViewMenu.fullscreenMenuLabel": "全画面モードを開始します", "xpack.canvas.workpadHeaderViewMenu.hideEditModeLabel": "編集コントロールを非表示にします", @@ -7022,13 +6987,10 @@ "xpack.canvas.workpadHeaderViewMenu.showEditModeLabel": "編集コントロールを表示します", "xpack.canvas.workpadHeaderViewMenu.viewMenuButtonLabel": "表示", "xpack.canvas.workpadHeaderViewMenu.viewMenuLabel": "表示オプション", - "xpack.canvas.workpadHeaderViewMenu.zoomControlsAriaLabel": "ズームコントロール", - "xpack.canvas.workpadHeaderViewMenu.zoomControlsTooltip": "ズームコントロール", "xpack.canvas.workpadHeaderViewMenu.zoomFitToWindowText": "ウィンドウに合わせる", "xpack.canvas.workpadHeaderViewMenu.zoomInText": "ズームイン", "xpack.canvas.workpadHeaderViewMenu.zoomMenuItemLabel": "ズーム", "xpack.canvas.workpadHeaderViewMenu.zoomOutText": "ズームアウト", - "xpack.canvas.workpadHeaderViewMenu.zoomPanelTitle": "ズーム", "xpack.canvas.workpadHeaderViewMenu.zoomPrecentageValue": "リセット", "xpack.canvas.workpadHeaderViewMenu.zoomResetText": "{scalePercentage}%", "xpack.canvas.workpadImport.filePickerPlaceholder": "ワークパッド {JSON} ファイルをインポート", @@ -12611,7 +12573,6 @@ "xpack.lens.indexPattern.emptyDimensionButton": "空のディメンション", "xpack.lens.indexPattern.emptyFieldsLabel": "空のフィールド", "xpack.lens.indexPattern.emptyFieldsLabelHelp": "空のフィールドには、フィルターに基づく最初の 500 件のドキュメントの値が含まれていませんでした。", - "xpack.lens.indexpattern.emptyTextColumnValue": " (空) ", "xpack.lens.indexPattern.existenceErrorAriaLabel": "存在の取り込みに失敗しました", "xpack.lens.indexPattern.existenceErrorLabel": "フィールド情報を読み込めません", "xpack.lens.indexPattern.existenceTimeoutAriaLabel": "存在の取り込みがタイムアウトしました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 055ccbdde6ae..0192566db073 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4968,8 +4968,6 @@ "visTypePie.editors.pie.showLabelsLabel": "显示标签", "visTypePie.editors.pie.showTopLevelOnlyLabel": "仅显示顶级", "visTypePie.editors.pie.showValuesLabel": "显示值", - "visualizations.advancedSettings.visualization.legacyChartsLibrary.description": "在 Visualize 中启用面积图、折线图和条形图的旧版图表库。", - "visualizations.advancedSettings.visualization.legacyChartsLibrary.name": "旧版图表库", "visualizations.advancedSettings.visualizeEnableLabsText": "允许用户创建、查看和编辑实验性可视化。如果禁用,\n 仅被视为生产就绪的可视化可供用户使用。", "visualizations.advancedSettings.visualizeEnableLabsTitle": "启用实验性可视化", "visualizations.disabledLabVisualizationLink": "阅读文档", @@ -5085,7 +5083,6 @@ "visTypeXy.editors.pointSeries.thresholdLine.valueLabel": "阈值", "visTypeXy.editors.pointSeries.thresholdLine.widthLabel": "线条宽度", "visTypeXy.editors.pointSeries.thresholdLineSettingsTitle": "阈值线条", - "visTypeXy.emptyTextColumnValue": " (空) ", "visTypeXy.fittingFunctionsTitle.carry": "最后一个 (使用最后一个值填充缺口) ", "visTypeXy.fittingFunctionsTitle.linear": "线 (使用线填充缺口) ", "visTypeXy.fittingFunctionsTitle.lookahead": "下一个 (使用下一个值填充缺口) ", @@ -6015,9 +6012,6 @@ "xpack.banners.settings.textColor.description": "设置横幅广告文本的颜色。{subscriptionLink}", "xpack.banners.settings.textColor.title": "横幅广告文本颜色", "xpack.banners.settings.textContent.title": "横幅广告文本", - "xpack.canvas.app.loadErrorMessage": "消息:{error}", - "xpack.canvas.app.loadErrorTitle": "Canvas 加载失败", - "xpack.canvas.app.loadingMessage": "Canvas 正在加载", "xpack.canvas.appDescription": "以最佳像素展示您的数据。", "xpack.canvas.argAddPopover.addAriaLabel": "添加参数", "xpack.canvas.argFormAdvancedFailure.applyButtonLabel": "应用", @@ -6035,8 +6029,6 @@ "xpack.canvas.asset.deleteAssetTooltip": "删除", "xpack.canvas.asset.downloadAssetTooltip": "下载", "xpack.canvas.asset.thumbnailAltText": "资产缩略图", - "xpack.canvas.assetManager.manageButtonLabel": "管理资产", - "xpack.canvas.assetModal.copyAssetMessage": "已将“{id}”复制到剪贴板", "xpack.canvas.assetModal.emptyAssetsDescription": "导入您的资产以开始", "xpack.canvas.assetModal.filePickerPromptText": "选择或拖放图像", "xpack.canvas.assetModal.loadingText": "正在上传图像", @@ -6059,7 +6051,6 @@ "xpack.canvas.customElementModal.nameInputLabel": "名称", "xpack.canvas.customElementModal.remainingCharactersDescription": "还剩 {numberOfRemainingCharacter} 个字符", "xpack.canvas.customElementModal.saveButtonLabel": "保存", - "xpack.canvas.datasourceDatasourceComponent.changeButtonLabel": "更改元素数据源", "xpack.canvas.datasourceDatasourceComponent.expressionArgDescription": "数据源包含由表达式控制的参数。使用表达式编辑器可修改数据源。", "xpack.canvas.datasourceDatasourceComponent.previewButtonLabel": "预览数据", "xpack.canvas.datasourceDatasourceComponent.saveButtonLabel": "保存", @@ -6489,8 +6480,6 @@ "xpack.canvas.groupSettings.saveGroupDescription": "将此组另存为新元素,以在整个 Workpad 重复使用。", "xpack.canvas.groupSettings.ungroupDescription": "取消分组 ({uKey}) 以编辑各个元素设置。", "xpack.canvas.helpMenu.appName": "Canvas", - "xpack.canvas.helpMenu.description": "有关 {CANVAS} 特定信息", - "xpack.canvas.helpMenu.documentationLinkLabel": "{CANVAS} 文档", "xpack.canvas.helpMenu.keyboardShortcutsLinkLabel": "快捷键", "xpack.canvas.home.myWorkpadsTabLabel": "我的 Workpad", "xpack.canvas.home.workpadTemplatesTabLabel": "模板", @@ -6557,7 +6546,6 @@ "xpack.canvas.lib.palettes.yellowBlueLabel": "黄、蓝", "xpack.canvas.lib.palettes.yellowGreenLabel": "黄、绿", "xpack.canvas.lib.palettes.yellowRedLabel": "黄、红", - "xpack.canvas.link.errorMessage": "链接错误:{message}", "xpack.canvas.pageConfig.backgroundColorDescription": "接受 HEX、RGB 或 HTML 颜色名称", "xpack.canvas.pageConfig.backgroundColorLabel": "背景", "xpack.canvas.pageConfig.title": "页面设置", @@ -6567,7 +6555,6 @@ "xpack.canvas.pageManager.addPageTooltip": "将新页面添加到此 Workpad", "xpack.canvas.pageManager.confirmRemoveDescription": "确定要移除此页面?", "xpack.canvas.pageManager.confirmRemoveTitle": "移除页面", - "xpack.canvas.pageManager.pageNumberAriaLabel": "加载页码 {pageNumber}", "xpack.canvas.pageManager.removeButtonLabel": "移除", "xpack.canvas.pagePreviewPageControls.clonePageAriaLabel": "克隆页面", "xpack.canvas.pagePreviewPageControls.clonePageTooltip": "克隆", @@ -6619,10 +6606,8 @@ "xpack.canvas.savedElementsModal.deleteElementDescription": "确定要删除此元素?", "xpack.canvas.savedElementsModal.deleteElementTitle": "删除元素“{elementName}”?", "xpack.canvas.savedElementsModal.editElementTitle": "编辑元素", - "xpack.canvas.savedElementsModal.elementsTitle": "元素", "xpack.canvas.savedElementsModal.findElementPlaceholder": "查找元素", "xpack.canvas.savedElementsModal.modalTitle": "我的元素", - "xpack.canvas.savedElementsModal.myElementsTitle": "我的元素", "xpack.canvas.shareWebsiteFlyout.description": "按照以下步骤在外部网站上共享此 Workpad 的静态版本。其将是当前 Workpad 的可视化快照,对实时数据没有访问权限。", "xpack.canvas.shareWebsiteFlyout.flyoutCalloutDescription": "要尝试共享,可以{link},其包含此 Workpad、{CANVAS} Shareable Workpad Runtime 及示例 {HTML} 文件。", "xpack.canvas.shareWebsiteFlyout.flyoutTitle": "在网站上共享", @@ -6677,13 +6662,10 @@ "xpack.canvas.textStylePicker.styleItalicOption": "斜体", "xpack.canvas.textStylePicker.styleOptionsControl": "样式选项", "xpack.canvas.textStylePicker.styleUnderlineOption": "下划线", - "xpack.canvas.timePicker.applyButtonLabel": "应用", "xpack.canvas.toolbar.editorButtonLabel": "表达式编辑器", - "xpack.canvas.toolbar.errorMessage": "工具栏错误:{message}", "xpack.canvas.toolbar.nextPageAriaLabel": "下一页", "xpack.canvas.toolbar.pageButtonLabel": "第 {pageNum}{rest} 页", "xpack.canvas.toolbar.previousPageAriaLabel": "上一页", - "xpack.canvas.toolbar.workpadManagerCloseButtonLabel": "关闭", "xpack.canvas.toolbarTray.closeTrayAriaLabel": "关闭托盘", "xpack.canvas.transitions.fade.displayName": "淡化", "xpack.canvas.transitions.fade.help": "从一页淡入到下一页", @@ -6949,20 +6931,8 @@ "xpack.canvas.units.time.minutes": "{minutes, plural, other {# 分钟}}", "xpack.canvas.units.time.seconds": "{seconds, plural, other {# 秒}}", "xpack.canvas.useCloneWorkpad.clonedWorkpadName": "{workpadName} 副本", - "xpack.canvas.varConfig.addButtonLabel": "添加变量", - "xpack.canvas.varConfig.addTooltipLabel": "添加变量", - "xpack.canvas.varConfig.copyActionButtonLabel": "复制代码片段", - "xpack.canvas.varConfig.copyActionTooltipLabel": "将变量语法复制到剪贴板", "xpack.canvas.varConfig.copyNotificationDescription": "变量语法已复制到剪贴板", - "xpack.canvas.varConfig.deleteActionButtonLabel": "删除变量", "xpack.canvas.varConfig.deleteNotificationDescription": "变量已成功删除", - "xpack.canvas.varConfig.editActionButtonLabel": "编辑变量", - "xpack.canvas.varConfig.emptyDescription": "此 Workpad 当前没有变量。您可以添加变量以存储和编辑公用值。这样,便可以在元素中或表达式编辑器中使用这些变量。", - "xpack.canvas.varConfig.tableNameLabel": "名称", - "xpack.canvas.varConfig.tableTypeLabel": "类型", - "xpack.canvas.varConfig.tableValueLabel": "值", - "xpack.canvas.varConfig.titleLabel": "变量", - "xpack.canvas.varConfig.titleTooltip": "添加变量以存储和编辑公用值", "xpack.canvas.varConfigDeleteVar.cancelButtonLabel": "取消", "xpack.canvas.varConfigDeleteVar.deleteButtonLabel": "删除变量", "xpack.canvas.varConfigDeleteVar.titleLabel": "删除变量?", @@ -6996,7 +6966,6 @@ "xpack.canvas.workpadConfig.USLetterButtonLabel": "美国信函", "xpack.canvas.workpadConfig.widthLabel": "宽", "xpack.canvas.workpadCreate.createButtonLabel": "创建 Workpad", - "xpack.canvas.workpadHeader.addElementButtonLabel": "添加元素", "xpack.canvas.workpadHeader.addElementModalCloseButtonLabel": "关闭", "xpack.canvas.workpadHeader.cycleIntervalDaysText": "每 {days} {days, plural, other {天}}", "xpack.canvas.workpadHeader.cycleIntervalHoursText": "每 {hours} {hours, plural, other {小时}}", @@ -7047,10 +7016,8 @@ "xpack.canvas.workpadHeaderElementMenu.textMenuItemLabel": "文本", "xpack.canvas.workpadHeaderKioskControl.controlTitle": "循环播放全屏页面", "xpack.canvas.workpadHeaderKioskControl.cycleFormLabel": "更改循环播放时间间隔", - "xpack.canvas.workpadHeaderKioskControl.cycleToggleSwitch": "自动循环播放幻灯片", "xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel": "刷新元素", "xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip": "刷新数据", - "xpack.canvas.workpadHeaderShareMenu.copyPDFMessage": "{PDF} 生成 {URL} 已复制到您的剪贴板。", "xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage": "已将共享标记复制到剪贴板", "xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle": "下载为 {JSON}", "xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle": "{PDF} 报告", @@ -7060,8 +7027,6 @@ "xpack.canvas.workpadHeaderShareMenu.shareWorkpadMessage": "共享此 Workpad", "xpack.canvas.workpadHeaderShareMenu.unknownExportErrorMessage": "未知导出类型:{type}", "xpack.canvas.workpadHeaderShareMenu.unsupportedRendererWarning": "此 Workpad 包含 {CANVAS} Shareable Workpad Runtime 不支持的呈现函数。将不会呈现以下元素:", - "xpack.canvas.workpadHeaderViewMenu.autoplayOffMenuItemLabel": "关闭自动播放", - "xpack.canvas.workpadHeaderViewMenu.autoplayOnMenuItemLabel": "打开自动播放", "xpack.canvas.workpadHeaderViewMenu.autoplaySettingsMenuItemLabel": "自动播放设置", "xpack.canvas.workpadHeaderViewMenu.fullscreenMenuLabel": "进入全屏模式", "xpack.canvas.workpadHeaderViewMenu.hideEditModeLabel": "隐藏编辑控件", @@ -7070,13 +7035,10 @@ "xpack.canvas.workpadHeaderViewMenu.showEditModeLabel": "显示编辑控制", "xpack.canvas.workpadHeaderViewMenu.viewMenuButtonLabel": "查看", "xpack.canvas.workpadHeaderViewMenu.viewMenuLabel": "查看选项", - "xpack.canvas.workpadHeaderViewMenu.zoomControlsAriaLabel": "缩放控制", - "xpack.canvas.workpadHeaderViewMenu.zoomControlsTooltip": "缩放控制", "xpack.canvas.workpadHeaderViewMenu.zoomFitToWindowText": "适应窗口大小", "xpack.canvas.workpadHeaderViewMenu.zoomInText": "放大", "xpack.canvas.workpadHeaderViewMenu.zoomMenuItemLabel": "缩放", "xpack.canvas.workpadHeaderViewMenu.zoomOutText": "缩小", - "xpack.canvas.workpadHeaderViewMenu.zoomPanelTitle": "缩放", "xpack.canvas.workpadHeaderViewMenu.zoomPrecentageValue": "重置", "xpack.canvas.workpadHeaderViewMenu.zoomResetText": "{scalePercentage}%", "xpack.canvas.workpadImport.filePickerPlaceholder": "导入 Workpad {JSON} 文件", @@ -12781,7 +12743,6 @@ "xpack.lens.indexPattern.emptyDimensionButton": "空维度", "xpack.lens.indexPattern.emptyFieldsLabel": "空字段", "xpack.lens.indexPattern.emptyFieldsLabelHelp": "空字段在基于您的筛选的前 500 个文档中不包含任何值。", - "xpack.lens.indexpattern.emptyTextColumnValue": " (空) ", "xpack.lens.indexPattern.existenceErrorAriaLabel": "现有内容提取失败", "xpack.lens.indexPattern.existenceErrorLabel": "无法加载字段信息", "xpack.lens.indexPattern.existenceTimeoutAriaLabel": "现有内容提取超时", diff --git a/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts b/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts index 4c639d3a166c..40485205f9fb 100644 --- a/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts +++ b/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts @@ -20,68 +20,6 @@ export default ({ getService }: FtrProviderContext) => { const testSetupJobConfigs = [SINGLE_METRIC_JOB_CONFIG, MULTI_METRIC_JOB_CONFIG]; - const testDataList = [ - { - testTitle: 'as ML Poweruser', - user: USER.ML_POWERUSER, - requestBody: { - jobIds: [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id], - }, - expected: { - responseCode: 200, - responseBody: { - [SINGLE_METRIC_JOB_CONFIG.job_id]: { closed: true }, - [MULTI_METRIC_JOB_CONFIG.job_id]: { closed: true }, - }, - }, - }, - ]; - - const testDataListFailed = [ - { - testTitle: 'as ML Poweruser', - user: USER.ML_POWERUSER, - requestBody: { - jobIds: [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id], - }, - expected: { - responseCode: 200, - - responseBody: { - [SINGLE_METRIC_JOB_CONFIG.job_id]: { closed: false, error: { status: 409 } }, - [MULTI_METRIC_JOB_CONFIG.job_id]: { closed: false, error: { status: 409 } }, - }, - }, - }, - ]; - - const testDataListUnauthorized = [ - { - testTitle: 'as ML Unauthorized user', - user: USER.ML_UNAUTHORIZED, - requestBody: { - jobIds: [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id], - }, - // Note that the jobs and datafeeds are loaded async so the actual error message is not deterministic. - expected: { - responseCode: 403, - error: 'Forbidden', - }, - }, - { - testTitle: 'as ML Viewer', - user: USER.ML_VIEWER, - requestBody: { - jobIds: [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id], - }, - // Note that the jobs and datafeeds are loaded async so the actual error message is not deterministic. - expected: { - responseCode: 403, - error: 'Forbidden', - }, - }, - ]; - async function runCloseJobsRequest( user: USER, requestBody: object, @@ -97,19 +35,22 @@ export default ({ getService }: FtrProviderContext) => { return body; } - // failing ES snapshot promotion after backend change, see https://github.com/elastic/kibana/issues/103023 - describe.skip('close_jobs', function () { + async function startDatafeedsInRealtime() { + for (const job of testSetupJobConfigs) { + const datafeedId = `datafeed-${job.job_id}`; + await ml.api.startDatafeed(datafeedId, { start: '0' }); + await ml.api.waitForDatafeedState(datafeedId, DATAFEED_STATE.STARTED); + } + } + + describe('close_jobs', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); }); - after(async () => { - await ml.api.cleanMlIndices(); - }); - - it('sets up jobs', async () => { + beforeEach(async () => { for (const job of testSetupJobConfigs) { const datafeedId = `datafeed-${job.job_id}`; await ml.api.createAnomalyDetectionJob(job); @@ -119,98 +60,132 @@ export default ({ getService }: FtrProviderContext) => { datafeed_id: datafeedId, job_id: job.job_id, }); - await ml.api.startDatafeed(datafeedId, { start: '0' }); - await ml.api.waitForDatafeedState(datafeedId, DATAFEED_STATE.STARTED); } }); - describe('rejects request', function () { - for (const testData of testDataListUnauthorized) { - describe('fails to close job ID supplied', function () { - it(`${testData.testTitle}`, async () => { - const body = await runCloseJobsRequest( - testData.user, - testData.requestBody, - testData.expected.responseCode - ); - - expect(body).to.have.property('error').eql(testData.expected.error); - - // ensure jobs are still open - for (const id of testData.requestBody.jobIds) { - await ml.api.waitForJobState(id, JOB_STATE.OPENED); - } - }); - }); + afterEach(async () => { + for (const job of testSetupJobConfigs) { + await ml.api.deleteAnomalyDetectionJobES(job.job_id); } + await ml.api.cleanMlIndices(); }); - describe('close jobs fail because they are running', function () { - for (const testData of testDataListFailed) { - it(`${testData.testTitle}`, async () => { - const body = await runCloseJobsRequest( - testData.user, - testData.requestBody, - testData.expected.responseCode - ); - const expectedResponse = testData.expected.responseBody; - const expectedRspJobIds = Object.keys(expectedResponse).sort((a, b) => - a.localeCompare(b) - ); - const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); - - expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); - expect(actualRspJobIds).to.eql(expectedRspJobIds); - - expectedRspJobIds.forEach((id) => { - expect(body[id].closed).to.eql(testData.expected.responseBody[id].closed); - expect(body[id].error.status).to.eql(testData.expected.responseBody[id].error.status); - }); - - // ensure jobs are still open - for (const id of testData.requestBody.jobIds) { - await ml.api.waitForJobState(id, JOB_STATE.OPENED); - } - }); + it('rejects request for ML Unauthorized user', async () => { + await startDatafeedsInRealtime(); + + const jobIds = [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id]; + const body = await runCloseJobsRequest(USER.ML_UNAUTHORIZED, { jobIds }, 403); + + expect(body).to.have.property('error').eql('Forbidden'); + + // ensure jobs are still open + for (const id of jobIds) { + await ml.api.waitForJobState(id, JOB_STATE.OPENED); + } + }); + + it('rejects request for ML Viewer user', async () => { + await startDatafeedsInRealtime(); + + const jobIds = [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id]; + const body = await runCloseJobsRequest(USER.ML_VIEWER, { jobIds }, 403); + + expect(body).to.have.property('error').eql('Forbidden'); + + // ensure jobs are still open + for (const id of jobIds) { + await ml.api.waitForJobState(id, JOB_STATE.OPENED); + } + }); + + it('succeeds for ML Poweruser with datafeed started', async () => { + await startDatafeedsInRealtime(); + + const jobIds = [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id]; + const body = await runCloseJobsRequest(USER.ML_POWERUSER, { jobIds }, 200); + + const expectedRspBody = { + [SINGLE_METRIC_JOB_CONFIG.job_id]: { closed: true }, + [MULTI_METRIC_JOB_CONFIG.job_id]: { closed: true }, + }; + const expectedRspJobIds = Object.keys(expectedRspBody).sort((a, b) => a.localeCompare(b)); + const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); + + expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); + expect(actualRspJobIds).to.eql(expectedRspJobIds); + + expectedRspJobIds.forEach((id) => { + expect(body[id].closed).to.eql(expectedRspBody[id].closed); + }); + + // datafeeds should be stopped automatically + for (const id of jobIds) { + await ml.api.waitForDatafeedState(`datafeed-${id}`, DATAFEED_STATE.STOPPED); + } + + // ensure jobs are actually closed + for (const id of jobIds) { + await ml.api.waitForJobState(id, JOB_STATE.CLOSED); } }); - describe('stops datafeeds', function () { - it('stops datafeeds', async () => { - for (const job of testSetupJobConfigs) { - const datafeedId = `datafeed-${job.job_id}`; - await ml.api.stopDatafeed(datafeedId); - await ml.api.waitForDatafeedState(datafeedId, DATAFEED_STATE.STOPPED); - } + it('succeeds for ML Poweruser with datafeed stopped', async () => { + const jobIds = [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id]; + const body = await runCloseJobsRequest(USER.ML_POWERUSER, { jobIds }, 200); + + const expectedRspBody = { + [SINGLE_METRIC_JOB_CONFIG.job_id]: { closed: true }, + [MULTI_METRIC_JOB_CONFIG.job_id]: { closed: true }, + }; + const expectedRspJobIds = Object.keys(expectedRspBody).sort((a, b) => a.localeCompare(b)); + const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); + + expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); + expect(actualRspJobIds).to.eql(expectedRspJobIds); + + expectedRspJobIds.forEach((id) => { + expect(body[id].closed).to.eql(expectedRspBody[id].closed); }); + + // datafeeds should still be stopped + for (const id of jobIds) { + await ml.api.waitForDatafeedState(`datafeed-${id}`, DATAFEED_STATE.STOPPED); + } + + // ensure jobs are actually closed + for (const id of jobIds) { + await ml.api.waitForJobState(id, JOB_STATE.CLOSED); + } }); - describe('close jobs succeed', function () { - for (const testData of testDataList) { - it(`${testData.testTitle}`, async () => { - const body = await runCloseJobsRequest( - testData.user, - testData.requestBody, - testData.expected.responseCode - ); - const expectedResponse = testData.expected.responseBody; - const expectedRspJobIds = Object.keys(expectedResponse).sort((a, b) => - a.localeCompare(b) - ); - const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); - - expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); - expect(actualRspJobIds).to.eql(expectedRspJobIds); - - expectedRspJobIds.forEach((id) => { - expect(body[id].closed).to.eql(testData.expected.responseBody[id].closed); - }); - - // ensure jobs are now closed - for (const id of testData.requestBody.jobIds) { - await ml.api.waitForJobState(id, JOB_STATE.CLOSED); - } - }); + it('succeeds for ML Poweruser with job already closed', async () => { + const jobIds = [SINGLE_METRIC_JOB_CONFIG.job_id, MULTI_METRIC_JOB_CONFIG.job_id]; + await runCloseJobsRequest(USER.ML_POWERUSER, { jobIds }, 200); + + const body = await runCloseJobsRequest(USER.ML_POWERUSER, { jobIds }, 200); + + const expectedRspBody = { + [SINGLE_METRIC_JOB_CONFIG.job_id]: { closed: true }, + [MULTI_METRIC_JOB_CONFIG.job_id]: { closed: true }, + }; + const expectedRspJobIds = Object.keys(expectedRspBody).sort((a, b) => a.localeCompare(b)); + const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); + + expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); + expect(actualRspJobIds).to.eql(expectedRspJobIds); + + expectedRspJobIds.forEach((id) => { + expect(body[id].closed).to.eql(expectedRspBody[id].closed); + }); + + // datafeeds should still be stopped + for (const id of jobIds) { + await ml.api.waitForDatafeedState(`datafeed-${id}`, DATAFEED_STATE.STOPPED); + } + + // jobs should still be closed + for (const id of jobIds) { + await ml.api.waitForJobState(id, JOB_STATE.CLOSED); } }); }); diff --git a/x-pack/test/api_integration/config.ts b/x-pack/test/api_integration/config.ts index 6708a6d55f40..550148531e2e 100644 --- a/x-pack/test/api_integration/config.ts +++ b/x-pack/test/api_integration/config.ts @@ -33,6 +33,7 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi '--xpack.data_enhanced.search.sessions.enabled=true', // enable WIP send to background UI '--xpack.data_enhanced.search.sessions.notTouchedTimeout=15s', // shorten notTouchedTimeout for quicker testing '--xpack.data_enhanced.search.sessions.trackingInterval=5s', // shorten trackingInterval for quicker testing + '--xpack.data_enhanced.search.sessions.cleanupInterval=5s', // shorten cleanupInterval for quicker testing ], }, esTestCluster: { diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index baa49cb6f9d8..c7666bf00dd5 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -65,7 +65,7 @@ exports[`discover Discover CSV Export Generate CSV: archived search generates a exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` "\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,,Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ \\"\\"coordinates\\"\\": [ 54.4, 24.5 @@ -77,7 +77,7 @@ exports[`discover Discover CSV Export Generate CSV: new search generates a repor exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` "\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,,Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ \\"\\"coordinates\\"\\": [ 54.4, 24.5 diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index ec32d7620fcf..78900e6fabca 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -604,7 +604,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); - it('should not leave an incomplete column in the visualization config with reference-based operations', async () => { + it('should revert to previous configuration and not leave an incomplete column in the visualization config with reference-based operations', async () => { await PageObjects.visualize.navigateToNewVisualization(); await PageObjects.visualize.clickVisType('lens'); await PageObjects.lens.goToTimeRange(); @@ -636,7 +636,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.closeDimensionEditor(); expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_yDimensionPanel')).to.eql( - undefined + 'Moving average of Count of records' ); }); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index cf05bd6e1589..2c3a3c93e2a0 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -103,6 +103,7 @@ export default async function ({ readConfigFile }) { 'accessibility:disableAnimations': true, 'dateFormat:tz': 'UTC', 'visualization:visualize:legacyChartsLibrary': true, + 'visualization:visualize:legacyPieChartsLibrary': true, }, }, // the apps section defines the urls that diff --git a/yarn.lock b/yarn.lock index 64e01ac0475d..448c97ff8246 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1147,7 +1147,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.5.tgz#665450911c6031af38f81db530f387ec04cd9a98" integrity sha512-121rumjddw9c3NCQ55KGkyE1h/nzWhU/owjhw0l4mQrkzz4x9SGS1X8gFLraHwX7td3Yo4QTL+qj0NcIzN87BA== @@ -1352,10 +1352,10 @@ dependencies: "@elastic/apm-rum-core" "^5.11.0" -"@elastic/app-search-javascript@^7.3.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@elastic/app-search-javascript/-/app-search-javascript-7.8.0.tgz#cbc7af6bcdd224518f7f595145d6ec744e0b165d" - integrity sha512-EsAa/E/dQwBO72nrQ9YrXudP9KVY0sVUOvqPKZ3hBj9Mr3+MtWMyIKcyMf09bzdayk4qE+moetYDe5ahVbiA+Q== +"@elastic/app-search-javascript@^7.13.1": + version "7.13.1" + resolved "https://registry.yarnpkg.com/@elastic/app-search-javascript/-/app-search-javascript-7.13.1.tgz#07d84daa27e856ad14f3f840683288eab06577f4" + integrity sha512-ShzZtGWykLQ0+wXzfk6lJztv68fRcGa8rsLDxJLH/O/2CGY+PJDnj8Qu5lJPmsAPZlZgaB8u7l26YGVPOoaqSA== dependencies: object-hash "^1.3.0" @@ -1539,22 +1539,22 @@ resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.5.1.tgz#96acf39c3d599950646ef8ccfd24a3f057cf4932" integrity sha512-Tby6TKjixRFY+atVNeYUdGr9m0iaOq8230KTwn8BbUhkh7LwozfgKq0U98HRX7n63ZL62szl+cDKTYzh5WPCFQ== -"@elastic/react-search-ui-views@1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@elastic/react-search-ui-views/-/react-search-ui-views-1.5.1.tgz#766cd6b6049f7aa8ab711a6a3a4a060ee5fdd0ce" - integrity sha512-x4X2xc/69996IEId3VVBTwPICnx/sschnfQ6YmuU3+myRa+VUPkkAWIK/cBcyBW8TNsLtZHWZrjQYi24+H7YWA== +"@elastic/react-search-ui-views@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@elastic/react-search-ui-views/-/react-search-ui-views-1.6.0.tgz#7211d47c29ef0636c853721491b9905ac7ae58da" + integrity sha512-VADJ18p8HoSPtxKEWFODzId08j0ahyHmHjXv1vP6O/PvtA+ECvi0gDSh/WgdRF792G0e+4d2Dke8LIhxaEvE+w== dependencies: downshift "^3.2.10" rc-pagination "^1.20.1" react-select "^2.4.4" -"@elastic/react-search-ui@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@elastic/react-search-ui/-/react-search-ui-1.5.1.tgz#2c261226d2eda3834b4779fbeea5693958169ff2" - integrity sha512-SI7uOF+jI+Z2D+2otym+4eLBYnocmxa+NA6VPSBrADZXyn8oUEzA4MBtJtxHLtcj64Tj8Riv0tw3t9q3b8iF+w== +"@elastic/react-search-ui@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@elastic/react-search-ui/-/react-search-ui-1.6.0.tgz#8d547d5e1f0a8eebe94798b29966f51643aa886f" + integrity sha512-bwSKuCQTQiBWr6QufQtZZGu6rcVYfoiUnyZbwZMS6ojedd5XY7FtMcE+QnR6/IIo0M2IUrxD74XtVNqkUhoCRg== dependencies: - "@elastic/react-search-ui-views" "1.5.1" - "@elastic/search-ui" "1.5.1" + "@elastic/react-search-ui-views" "1.6.0" + "@elastic/search-ui" "1.6.0" "@elastic/request-crypto@1.1.4": version "1.1.4" @@ -1569,18 +1569,17 @@ version "0.0.0" uid "" -"@elastic/search-ui-app-search-connector@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@elastic/search-ui-app-search-connector/-/search-ui-app-search-connector-1.5.0.tgz#d379132c5015775acfaee5322ec019e9c0559ccc" - integrity sha512-lHuXBjaMaN1fsm1taQMR/7gfpAg4XOsvZOi8u1AoufUw9kGr6Xc00Gznj1qTyH0Qebi2aSmY0NBN6pdIEGvvGQ== +"@elastic/search-ui-app-search-connector@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@elastic/search-ui-app-search-connector/-/search-ui-app-search-connector-1.6.0.tgz#faf1c4a384285648ef7b5ef9cd0e65de0341d2b0" + integrity sha512-6oNvqzo4nuutmCM0zEzYrV6VwG8j0ML43SkaG6UrFzLUd6DeWUVGNN+SLNAlfQDWBUjc2m5EGvgdk/0GOWDZeA== dependencies: - "@babel/runtime" "^7.5.4" - "@elastic/app-search-javascript" "^7.3.0" + "@elastic/app-search-javascript" "^7.13.1" -"@elastic/search-ui@1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@elastic/search-ui/-/search-ui-1.5.1.tgz#14c66a66f5e937ef5e24d6266620b49d986fb3ed" - integrity sha512-ssfvX1q76X1UwqYASWtBni4PZ+3SYk1PvHmOjpVf9BYai1OqZLGVaj8Sw+cE1ia56zl5In7viCfciC+CP31ovA== +"@elastic/search-ui@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@elastic/search-ui/-/search-ui-1.6.0.tgz#8b2286cacff44735be96605b2929ca9b469c78de" + integrity sha512-i7htjET9uE4xngyzS8kX3DkSD5XNcr+3FS0Jjx3xRpKVc/dFst4bJyiSeRrQcq+2oBb4mEJJOCFaIrLZg3mdSA== dependencies: date-fns "^1.30.1" deep-equal "^1.0.1" @@ -2617,7 +2616,7 @@ version "0.0.0" uid "" -"@kbn/cli-dev-mode@link:packages/kbn-cli-dev-mode": +"@kbn/cli-dev-mode@link:bazel-bin/packages/kbn-cli-dev-mode": version "0.0.0" uid "" @@ -2701,7 +2700,7 @@ version "0.0.0" uid "" -"@kbn/plugin-helpers@link:packages/kbn-plugin-helpers": +"@kbn/plugin-helpers@link:bazel-bin/packages/kbn-plugin-helpers": version "0.0.0" uid ""