diff --git a/.eslintrc.js b/.eslintrc.js index 2a4fbe7db3723..b12dc63066370 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -304,8 +304,8 @@ module.exports = { */ { files: [ - 'packages/elastic-datemath/**/*.{js,mjs,ts,tsx}', 'packages/elastic-eslint-config-kibana/**/*.{js,mjs,ts,tsx}', + 'packages/kbn-datemath/**/*.{js,mjs,ts,tsx}', ], rules: { '@kbn/eslint/require-license-header': [ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 50341621557fa..3c991e6a61d53 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -55,7 +55,7 @@ /examples/field_formats_example/ @elastic/kibana-app-services /examples/partial_results_example/ @elastic/kibana-app-services /examples/search_examples/ @elastic/kibana-app-services -/packages/elastic-datemath/ @elastic/kibana-app-services +/packages/kbn-datemath/ @elastic/kibana-app-services /packages/kbn-interpreter/ @elastic/kibana-app-services /packages/kbn-react-field/ @elastic/kibana-app-services /packages/kbn-es-query/ @elastic/kibana-app-services @@ -324,6 +324,7 @@ /src/plugins/interactive_setup/ @elastic/kibana-security /test/interactive_setup_api_integration/ @elastic/kibana-security /test/interactive_setup_functional/ @elastic/kibana-security +/test/plugin_functional/test_suites/core_plugins/rendering.ts @elastic/kibana-security /x-pack/plugins/spaces/ @elastic/kibana-security /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 4a2e6ddf76b17..ff9014214d4c0 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -10,15 +10,16 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch Node.js rules http_archive( name = "build_bazel_rules_nodejs", - sha256 = "8a7c981217239085f78acc9898a1f7ba99af887c1996ceb3b4504655383a2c3c", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/4.0.0/rules_nodejs-4.0.0.tar.gz"], + sha256 = "523da2d6b50bc00eaf14b00ed28b1a366b3ab456e14131e9812558b26599125c", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.3.1/rules_nodejs-5.3.1.tar.gz"], ) -# Now that we have the rules let's import from them to complete the work -load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install") +# Build Node.js rules dependencies +load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies") +build_bazel_rules_nodejs_dependencies() -# Assure we have at least a given rules_nodejs version -check_rules_nodejs_version(minimum_version_string = "4.0.0") +# Now that we have the rules let's import from them to complete the work +load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install") # Setup the Node.js toolchain for the architectures we want to support # @@ -38,14 +39,13 @@ node_repositories( node_urls = [ "https://nodejs.org/dist/v{version}/{filename}", ], - yarn_repositories = { + yarn_releases = { "1.21.1": ("yarn-v1.21.1.tar.gz", "yarn-v1.21.1", "d1d9f4a0f16f5ed484e814afeb98f39b82d4728c6c8beaafb5abc99c02db6674"), }, yarn_version = "1.21.1", yarn_urls = [ "https://github.com/yarnpkg/yarn/releases/download/v{version}/{filename}", ], - package_json = ["//:package.json"], ) # Run yarn_install rule to take care of dependencies diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index e8e792f13c0dd..0216d26023a78 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -51,7 +51,6 @@ yarn kbn watch [discrete] === List of Already Migrated Packages to Bazel -- @elastic/datemath - @elastic/eslint-config-kibana - @elastic/safer-lodash-set - @kbn/ace @@ -64,6 +63,7 @@ yarn kbn watch - @kbn/config - @kbn/config-schema - @kbn/crypto +- @kbn/datemath - @kbn/dev-utils - @kbn/docs-utils - @kbn/es diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 5906f2dd5008f..a702c7d607e55 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -478,13 +478,6 @@ The default index when using the `.es()` query. [[timelion-estimefield]]`timelion:es.timefield`:: The default field containing a timestamp when using the `.es()` query. -[[timelion-graphite-url]]`timelion:graphite.url`:: -experimental:[] -Used with graphite queries, this is the URL of your graphite host -in the form https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite. This URL can -be selected from an allow-list configured in the `kibana.yml` under -`timelion.graphiteUrls`. - [[timelion-maxbuckets]]`timelion:max_buckets`:: The maximum number of buckets a single data source can return. This value is used for calculating automatic intervals in visualizations. @@ -492,11 +485,6 @@ used for calculating automatic intervals in visualizations. [[timelion-mininterval]]`timelion:min_interval`:: The smallest interval to calculate when using "auto". -[[timelion-quandlkey]]`timelion:quandl.key`:: -experimental:[] -Used with quandl queries, this is your API key from -https://www.quandl.com/[www.quandl.com]. - [[timelion-targetbuckets]]`timelion:target_buckets`:: Used for calculating automatic intervals in visualizations, this is the number of buckets to try to represent. diff --git a/package.json b/package.json index 05dcd0f6691dd..76948decf33a7 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@elastic/apm-rum-react": "^1.3.4", "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", "@elastic/charts": "45.1.1", - "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", + "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.2.0-canary.2", "@elastic/ems-client": "8.2.0", "@elastic/eui": "53.0.1", @@ -140,6 +140,7 @@ "@kbn/config": "link:bazel-bin/packages/kbn-config", "@kbn/config-schema": "link:bazel-bin/packages/kbn-config-schema", "@kbn/crypto": "link:bazel-bin/packages/kbn-crypto", + "@kbn/datemath": "link:bazel-bin/packages/kbn-datemath", "@kbn/doc-links": "link:bazel-bin/packages/kbn-doc-links", "@kbn/es-query": "link:bazel-bin/packages/kbn-es-query", "@kbn/eslint-plugin-imports": "link:bazel-bin/packages/kbn-eslint-plugin-imports", @@ -310,7 +311,7 @@ "mime-types": "^2.1.27", "mini-css-extract-plugin": "1.1.0", "minimatch": "^3.1.2", - "moment": "^2.24.0", + "moment": "^2.29.2", "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.27", "monaco-editor": "^0.22.3", @@ -455,7 +456,7 @@ "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0", "@bazel/ibazel": "^0.16.2", - "@bazel/typescript": "4.0.0", + "@bazel/typescript": "5.3.1", "@cypress/code-coverage": "^3.9.12", "@cypress/snapshot": "^2.1.7", "@cypress/webpack-preprocessor": "^5.6.0", @@ -545,7 +546,6 @@ "@types/delete-empty": "^2.0.0", "@types/ejs": "^3.0.6", "@types/elastic__apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace/npm_module_types", - "@types/elastic__datemath": "link:bazel-bin/packages/elastic-datemath/npm_module_types", "@types/enzyme": "^3.10.8", "@types/eslint": "^7.28.0", "@types/express": "^4.17.13", @@ -595,6 +595,7 @@ "@types/kbn__config": "link:bazel-bin/packages/kbn-config/npm_module_types", "@types/kbn__config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module_types", "@types/kbn__crypto": "link:bazel-bin/packages/kbn-crypto/npm_module_types", + "@types/kbn__datemath": "link:bazel-bin/packages/kbn-datemath/npm_module_types", "@types/kbn__dev-utils": "link:bazel-bin/packages/kbn-dev-utils/npm_module_types", "@types/kbn__doc-links": "link:bazel-bin/packages/kbn-doc-links/npm_module_types", "@types/kbn__docs-utils": "link:bazel-bin/packages/kbn-docs-utils/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index ad239f6a180cd..61104d1afcac0 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -11,7 +11,6 @@ filegroup( srcs = [ "//packages/elastic-analytics:build", "//packages/elastic-apm-synthtrace:build", - "//packages/elastic-datemath:build", "//packages/elastic-eslint-config-kibana:build", "//packages/elastic-safer-lodash-set:build", "//packages/kbn-ace:build", @@ -30,6 +29,7 @@ filegroup( "//packages/kbn-config-schema:build", "//packages/kbn-config:build", "//packages/kbn-crypto:build", + "//packages/kbn-datemath:build", "//packages/kbn-dev-utils:build", "//packages/kbn-doc-links:build", "//packages/kbn-docs-utils:build", @@ -102,7 +102,6 @@ filegroup( srcs = [ "//packages/elastic-analytics:build_types", "//packages/elastic-apm-synthtrace:build_types", - "//packages/elastic-datemath:build_types", "//packages/elastic-safer-lodash-set:build_types", "//packages/kbn-ace:build_types", "//packages/kbn-alerts:build_types", @@ -116,6 +115,7 @@ filegroup( "//packages/kbn-config-schema:build_types", "//packages/kbn-config:build_types", "//packages/kbn-crypto:build_types", + "//packages/kbn-datemath:build_types", "//packages/kbn-dev-utils:build_types", "//packages/kbn-doc-links:build_types", "//packages/kbn-docs-utils:build_types", diff --git a/packages/elastic-apm-synthtrace/BUILD.bazel b/packages/elastic-apm-synthtrace/BUILD.bazel index 646b94891f7c2..334d2a0b9e7be 100644 --- a/packages/elastic-apm-synthtrace/BUILD.bazel +++ b/packages/elastic-apm-synthtrace/BUILD.bazel @@ -25,7 +25,7 @@ NPM_MODULE_EXTRA_FILES = [ ] RUNTIME_DEPS = [ - "//packages/elastic-datemath", + "//packages/kbn-datemath", "@npm//@elastic/elasticsearch", "@npm//lodash", "@npm//moment", @@ -36,7 +36,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/elastic-datemath:npm_module_types", + "//packages/kbn-datemath:npm_module_types", "@npm//@elastic/elasticsearch", "@npm//@types/jest", "@npm//@types/lodash", diff --git a/packages/elastic-apm-synthtrace/src/scripts/run.ts b/packages/elastic-apm-synthtrace/src/scripts/run.ts index 36b3974c12161..ac351eb99ee65 100644 --- a/packages/elastic-apm-synthtrace/src/scripts/run.ts +++ b/packages/elastic-apm-synthtrace/src/scripts/run.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import yargs from 'yargs/yargs'; import { Argv } from 'yargs'; import { intervalToMs } from './utils/interval_to_ms'; diff --git a/packages/kbn-config-schema/src/index.ts b/packages/kbn-config-schema/src/index.ts index f9db84f255ec6..af545ac5eb9e6 100644 --- a/packages/kbn-config-schema/src/index.ts +++ b/packages/kbn-config-schema/src/index.ts @@ -38,6 +38,7 @@ import { NullableProps, RecordOfOptions, RecordOfType, + SchemaStructureEntry, StringOptions, StringType, Type, @@ -49,7 +50,7 @@ import { StreamType, } from './types'; -export type { AnyType, ConditionalType, TypeOf, Props, NullableProps }; +export type { AnyType, ConditionalType, TypeOf, Props, SchemaStructureEntry, NullableProps }; export { ObjectType, Type }; export { ByteSizeValue } from './byte_size_value'; export { SchemaTypeError, ValidationError } from './errors'; diff --git a/packages/kbn-config-schema/src/types/index.ts b/packages/kbn-config-schema/src/types/index.ts index 5152137985ff3..23b114fd824df 100644 --- a/packages/kbn-config-schema/src/types/index.ts +++ b/packages/kbn-config-schema/src/types/index.ts @@ -7,6 +7,7 @@ */ export type { TypeOptions } from './type'; +export type { SchemaStructureEntry } from './type'; export { Type } from './type'; export { AnyType } from './any_type'; export type { ArrayOptions } from './array_type'; diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts index 67f0963fefdda..6548e808395b9 100644 --- a/packages/kbn-config-schema/src/types/object_type.test.ts +++ b/packages/kbn-config-schema/src/types/object_type.test.ts @@ -490,3 +490,76 @@ describe('#extends', () => { expect(extended.validate(undefined)).toEqual({ initial: 'bar', added: 42 }); }); }); + +test('returns schema structure', () => { + // This test covers different schema types that may or may not be nested + const objSchema = schema.object({ + any: schema.any(), + array: schema.arrayOf(schema.string()), + boolean: schema.boolean(), + buffer: schema.buffer(), + byteSize: schema.byteSize(), + conditional: schema.conditional( + schema.contextRef('context_value_1'), + schema.contextRef('context_value_2'), + schema.string(), + schema.string() + ), + duration: schema.duration(), + ip: schema.ip(), + literal: schema.literal('foo'), + map: schema.mapOf(schema.string(), schema.string()), + maybe: schema.maybe(schema.string()), + never: schema.never(), + nullable: schema.nullable(schema.string()), + number: schema.number(), + record: schema.recordOf(schema.string(), schema.string()), + stream: schema.stream(), + string: schema.string(), + union: schema.oneOf([schema.string()]), + uri: schema.uri(), + }); + const type = objSchema.extends({ + nested: objSchema, + }); + expect(type.getSchemaStructure()).toEqual([ + { path: ['any'], type: 'any' }, + { path: ['array'], type: 'array' }, + { path: ['boolean'], type: 'boolean' }, + { path: ['buffer'], type: 'binary' }, + { path: ['byteSize'], type: 'bytes' }, + { path: ['conditional'], type: 'any' }, + { path: ['duration'], type: 'duration' }, + { path: ['ip'], type: 'string' }, + { path: ['literal'], type: 'any' }, + { path: ['map'], type: 'map' }, + { path: ['maybe'], type: 'string' }, + { path: ['never'], type: 'any' }, + { path: ['nullable'], type: 'alternatives' }, + { path: ['number'], type: 'number' }, + { path: ['record'], type: 'record' }, + { path: ['stream'], type: 'stream' }, + { path: ['string'], type: 'string' }, + { path: ['union'], type: 'alternatives' }, + { path: ['uri'], type: 'string' }, + { path: ['nested', 'any'], type: 'any' }, + { path: ['nested', 'array'], type: 'array' }, + { path: ['nested', 'boolean'], type: 'boolean' }, + { path: ['nested', 'buffer'], type: 'binary' }, + { path: ['nested', 'byteSize'], type: 'bytes' }, + { path: ['nested', 'conditional'], type: 'any' }, + { path: ['nested', 'duration'], type: 'duration' }, + { path: ['nested', 'ip'], type: 'string' }, + { path: ['nested', 'literal'], type: 'any' }, + { path: ['nested', 'map'], type: 'map' }, + { path: ['nested', 'maybe'], type: 'string' }, + { path: ['nested', 'never'], type: 'any' }, + { path: ['nested', 'nullable'], type: 'alternatives' }, + { path: ['nested', 'number'], type: 'number' }, + { path: ['nested', 'record'], type: 'record' }, + { path: ['nested', 'stream'], type: 'stream' }, + { path: ['nested', 'string'], type: 'string' }, + { path: ['nested', 'union'], type: 'alternatives' }, + { path: ['nested', 'uri'], type: 'string' }, + ]); +}); diff --git a/packages/kbn-config-schema/src/types/string_type.ts b/packages/kbn-config-schema/src/types/string_type.ts index 1442c5b9b4efb..f2792e4031e0a 100644 --- a/packages/kbn-config-schema/src/types/string_type.ts +++ b/packages/kbn-config-schema/src/types/string_type.ts @@ -53,6 +53,7 @@ export class StringType extends Type { ); } + schema.type = 'string'; super(schema, options); } diff --git a/packages/kbn-config-schema/src/types/type.ts b/packages/kbn-config-schema/src/types/type.ts index 696101fb2c223..d3bab0106e5c4 100644 --- a/packages/kbn-config-schema/src/types/type.ts +++ b/packages/kbn-config-schema/src/types/type.ts @@ -15,6 +15,11 @@ export interface TypeOptions { validate?: (value: T) => string | void; } +export interface SchemaStructureEntry { + path: string[]; + type: string; +} + export const convertValidationFunction = ( validate: (value: T) => string | void ): CustomValidator => { @@ -98,6 +103,10 @@ export abstract class Type { return this.internalSchema; } + public getSchemaStructure() { + return recursiveGetSchemaStructure(this.internalSchema); + } + protected handleError( type: string, context: Record, @@ -141,3 +150,17 @@ export abstract class Type { return new SchemaTypeError(message || code, convertedPath); } } + +function recursiveGetSchemaStructure(internalSchema: AnySchema, path: string[] = []) { + const array: SchemaStructureEntry[] = []; + // Note: we are relying on Joi internals to obtain the schema structure (recursive keys). + // This is not ideal, but it works for now and we only need it for some integration test assertions. + // If it breaks in the future, we'll need to update our tests. + for (const [key, val] of (internalSchema as any)._ids._byKey.entries()) { + array.push(...recursiveGetSchemaStructure(val.schema, [...path, key])); + } + if (!array.length) { + array.push({ path, type: internalSchema.type ?? 'unknown' }); + } + return array; +} diff --git a/packages/elastic-datemath/.npmignore b/packages/kbn-datemath/.npmignore similarity index 100% rename from packages/elastic-datemath/.npmignore rename to packages/kbn-datemath/.npmignore diff --git a/packages/elastic-datemath/BUILD.bazel b/packages/kbn-datemath/BUILD.bazel similarity index 95% rename from packages/elastic-datemath/BUILD.bazel rename to packages/kbn-datemath/BUILD.bazel index 1ee7f8582cb7e..74fbe712eca0e 100644 --- a/packages/elastic-datemath/BUILD.bazel +++ b/packages/kbn-datemath/BUILD.bazel @@ -2,8 +2,8 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "ts_project", "pkg_npm", "pkg_npm_types") -PKG_BASE_NAME = "elastic-datemath" -PKG_REQUIRE_NAME = "@elastic/datemath" +PKG_BASE_NAME = "kbn-datemath" +PKG_REQUIRE_NAME = "@kbn/datemath" SOURCE_FILES = glob([ "src/index.ts", diff --git a/packages/elastic-datemath/README.md b/packages/kbn-datemath/README.md similarity index 61% rename from packages/elastic-datemath/README.md rename to packages/kbn-datemath/README.md index a8dcd9f6721cb..3f824c8297d28 100644 --- a/packages/elastic-datemath/README.md +++ b/packages/kbn-datemath/README.md @@ -1,5 +1,5 @@ # datemath -Datemath string parser used in Kibana. This is published to NPM for use in a limited number of locations outside of Kibana, but is not regularly updated and may get seriously out of date. +Datemath string parser used in Kibana. This is published to NPM under (@elastic/datemath) for use in a limited number of locations outside of Kibana, but is not regularly updated and may get seriously out of date. If you file an issue in elastic/kibana we can probably update it for you if needed, though you probably shouldn't depend on this package for anything important. diff --git a/packages/elastic-datemath/jest.config.js b/packages/kbn-datemath/jest.config.js similarity index 94% rename from packages/elastic-datemath/jest.config.js rename to packages/kbn-datemath/jest.config.js index 6a0bd891f1c58..9f3d7546a6fc4 100644 --- a/packages/elastic-datemath/jest.config.js +++ b/packages/kbn-datemath/jest.config.js @@ -20,6 +20,6 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/elastic-datemath'], + roots: ['/packages/kbn-datemath'], testEnvironment: 'jsdom', }; diff --git a/packages/elastic-datemath/package.json b/packages/kbn-datemath/package.json similarity index 77% rename from packages/elastic-datemath/package.json rename to packages/kbn-datemath/package.json index af958e3730c3d..0bd726afb721e 100644 --- a/packages/elastic-datemath/package.json +++ b/packages/kbn-datemath/package.json @@ -1,6 +1,6 @@ { - "name": "@elastic/datemath", - "version": "5.0.3", + "name": "@kbn/datemath", + "version": "5.0.4", "description": "elasticsearch datemath parser, used in kibana", "license": "Apache-2.0", "main": "./target_node/index.js", diff --git a/packages/elastic-datemath/src/index.test.js b/packages/kbn-datemath/src/index.test.js similarity index 100% rename from packages/elastic-datemath/src/index.test.js rename to packages/kbn-datemath/src/index.test.js diff --git a/packages/elastic-datemath/src/index.ts b/packages/kbn-datemath/src/index.ts similarity index 100% rename from packages/elastic-datemath/src/index.ts rename to packages/kbn-datemath/src/index.ts diff --git a/packages/elastic-datemath/tsconfig.json b/packages/kbn-datemath/tsconfig.json similarity index 100% rename from packages/elastic-datemath/tsconfig.json rename to packages/kbn-datemath/tsconfig.json diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 97392cc3d593e..690765f3d0c4d 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -162,6 +162,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { }, logstash: { base: `${ELASTIC_WEBSITE_URL}guide/en/logstash/${DOC_LINK_VERSION}`, + inputElasticAgent: `${ELASTIC_WEBSITE_URL}guide/en/logstash/${DOC_LINK_VERSION}/plugins-inputs-elastic_agent.html`, }, functionbeat: { base: `${ELASTIC_WEBSITE_URL}guide/en/beats/functionbeat/${DOC_LINK_VERSION}`, @@ -582,7 +583,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { guide: `${FLEET_DOCS}index.html`, fleetServer: `${FLEET_DOCS}fleet-server.html`, fleetServerAddFleetServer: `${FLEET_DOCS}add-a-fleet-server.html`, - settings: `${FLEET_DOCS}fleet-settings.html#fleet-server-hosts-setting`, + settings: `${FLEET_DOCS}fleet-settings.html`, settingsFleetServerHostSettings: `${FLEET_DOCS}fleet-settings.html#fleet-server-hosts-setting`, settingsFleetServerProxySettings: `${KIBANA_DOCS}fleet-settings-kb.html#fleet-data-visualizer-settings`, troubleshooting: `${FLEET_DOCS}fleet-troubleshooting.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 9a4ff1a58cf13..5e85d01c22ce2 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -141,6 +141,7 @@ export interface DocLinks { }; readonly logstash: { readonly base: string; + readonly inputElasticAgent: string; }; readonly functionbeat: { readonly base: string; diff --git a/packages/kbn-docs-utils/src/api_docs/utils.test.ts b/packages/kbn-docs-utils/src/api_docs/utils.test.ts index 488a115554e80..0cfa0331fd202 100644 --- a/packages/kbn-docs-utils/src/api_docs/utils.test.ts +++ b/packages/kbn-docs-utils/src/api_docs/utils.test.ts @@ -21,7 +21,7 @@ const log = new ToolingLog({ }); it('getFileName', () => { - expect(getFileName('@elastic/datemath')).toBe('elastic_datemath'); + expect(getFileName('@kbn/datemath')).toBe('kbn_datemath'); }); it('test getPluginForPath', () => { diff --git a/packages/kbn-eslint-plugin-imports/src/integration_tests/resolve_kibana_import.test.ts b/packages/kbn-eslint-plugin-imports/src/integration_tests/resolve_kibana_import.test.ts index 5610f5b667b75..21b1ea7b30409 100644 --- a/packages/kbn-eslint-plugin-imports/src/integration_tests/resolve_kibana_import.test.ts +++ b/packages/kbn-eslint-plugin-imports/src/integration_tests/resolve_kibana_import.test.ts @@ -63,15 +63,6 @@ describe('standard import formats', () => { }); it('resolves @elastic/ imports', () => { - expect(resolveKibanaImport('@elastic/datemath', pkg('kbn-dev-utils/src'))) - .toMatchInlineSnapshot(` - Object { - "absolute": /node_modules/@elastic/datemath/target_node/index.js, - "nodeModule": "@elastic/datemath", - "type": "file", - } - `); - expect(resolveKibanaImport('@elastic/eui', pkg('kbn-dev-utils/src'))).toMatchInlineSnapshot(` Object { "absolute": /node_modules/@elastic/eui/lib/index.js, diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index a17990291d4d7..0d731fd936507 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -8949,7 +8949,7 @@ const BootstrapCommand = { await time('force install dependencies', async () => { await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["removeYarnIntegrityFileIfExists"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kibanaProjectPath, 'node_modules')); await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['clean']); - await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['run', '@nodejs//:yarn'], runOffline, { + await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['run', '@yarn//:yarn'], runOffline, { env: { SASS_BINARY_SITE: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-sass', RE2_DOWNLOAD_MIRROR: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2' diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts index 51577df6c3b87..691265935b94f 100644 --- a/packages/kbn-pm/src/commands/bootstrap.ts +++ b/packages/kbn-pm/src/commands/bootstrap.ts @@ -72,7 +72,7 @@ export const BootstrapCommand: ICommand = { await time('force install dependencies', async () => { await removeYarnIntegrityFileIfExists(resolve(kibanaProjectPath, 'node_modules')); await runBazel(['clean']); - await runBazel(['run', '@nodejs//:yarn'], runOffline, { + await runBazel(['run', '@yarn//:yarn'], runOffline, { env: { SASS_BINARY_SITE: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-sass', diff --git a/packages/kbn-securitysolution-autocomplete/BUILD.bazel b/packages/kbn-securitysolution-autocomplete/BUILD.bazel index 16aa28e79b45b..d8de5ce23ea97 100644 --- a/packages/kbn-securitysolution-autocomplete/BUILD.bazel +++ b/packages/kbn-securitysolution-autocomplete/BUILD.bazel @@ -30,7 +30,7 @@ NPM_MODULE_EXTRA_FILES = [ ] RUNTIME_DEPS = [ - "//packages/elastic-datemath", + "//packages/kbn-datemath", "//packages/kbn-es-query", "//packages/kbn-i18n", "//packages/kbn-securitysolution-io-ts-list-types", @@ -46,7 +46,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/elastic-datemath:npm_module_types", + "//packages/kbn-datemath:npm_module_types", "//packages/kbn-es-query:npm_module_types", "//packages/kbn-i18n:npm_module_types", "//packages/kbn-securitysolution-io-ts-list-types:npm_module_types", diff --git a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts b/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts index 016d4f9308e2b..4d9aa734a1841 100644 --- a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts +++ b/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { DataViewFieldBase } from '@kbn/es-query'; import { checkEmptyValue } from '../check_empty_value'; diff --git a/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel b/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel index 0229acdb474e4..ce8c3efe8f782 100644 --- a/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel @@ -28,7 +28,7 @@ NPM_MODULE_EXTRA_FILES = [ ] RUNTIME_DEPS = [ - "//packages/elastic-datemath", + "//packages/kbn-datemath", "@npm//fp-ts", "@npm//io-ts", "@npm//lodash", @@ -37,7 +37,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/elastic-datemath:npm_module_types", + "//packages/kbn-datemath:npm_module_types", "@npm//fp-ts", "@npm//io-ts", "@npm//moment", diff --git a/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts b/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts index d6a99b5fbf880..9d7ef7a74302f 100644 --- a/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts +++ b/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts @@ -7,7 +7,7 @@ */ import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; export const parseScheduleDates = (time: string): moment.Moment | null => { const isValidDateString = !isNaN(Date.parse(time)); diff --git a/packages/kbn-shared-ux-components/src/index.ts b/packages/kbn-shared-ux-components/src/index.ts index 557ac980a14c6..a022d2d0c755d 100644 --- a/packages/kbn-shared-ux-components/src/index.ts +++ b/packages/kbn-shared-ux-components/src/index.ts @@ -10,7 +10,7 @@ import React from 'react'; import { withSuspense } from '@kbn/shared-ux-utility'; /** - * The Lazily-loaded `ExitFullScreenButton` component. Consumers should use `React.Suspennse` or the + * The Lazily-loaded `ExitFullScreenButton` component. Consumers should use `React.Suspense` or the * `withSuspense` HOC to load this component. */ export const LazyExitFullScreenButton = React.lazy(() => @@ -42,12 +42,12 @@ export const ExitFullScreenButton = withSuspense(LazyExitFullScreenButton); export const ToolbarButton = withSuspense(LazyToolbarButton); /** - * An example of the solution toolbar button + * An example of the toolbar button and popover */ -export { AddFromLibraryButton } from './toolbar'; +export { AddFromLibraryButton, ToolbarPopover } from './toolbar'; /** - * The Lazily-loaded `NoDataViews` component. Consumers should use `React.Suspennse` or the + * The Lazily-loaded `NoDataViews` component. Consumers should use `React.Suspense` or the * `withSuspense` HOC to load this component. */ export const LazyNoDataViews = React.lazy(() => @@ -64,7 +64,7 @@ export const LazyNoDataViews = React.lazy(() => export const NoDataViews = withSuspense(LazyNoDataViews); /** - * A pure `NoDataViews` component, with no services hooks. Consumers should use `React.Suspennse` or the + * A pure `NoDataViews` component, with no services hooks. Consumers should use `React.Suspense` or the * `withSuspense` HOC to load this component. */ export const LazyNoDataViewsComponent = React.lazy(() => @@ -81,7 +81,7 @@ export const LazyNoDataViewsComponent = React.lazy(() => export const NoDataViewsComponent = withSuspense(LazyNoDataViewsComponent); /** - * The Lazily-loaded `IconButtonGroup` component. Consumers should use `React.Suspennse` or the + * The Lazily-loaded `IconButtonGroup` component. Consumers should use `React.Suspense` or the * `withSuspense` HOC to load this component. */ export const LazyIconButtonGroup = React.lazy(() => diff --git a/packages/kbn-shared-ux-components/src/toolbar/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap b/packages/kbn-shared-ux-components/src/toolbar/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap index 4cdc858c7e50c..520184f0f96dc 100644 --- a/packages/kbn-shared-ux-components/src/toolbar/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap +++ b/packages/kbn-shared-ux-components/src/toolbar/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap @@ -9,6 +9,7 @@ exports[` is rendered 1`] = ` @@ -18,6 +19,7 @@ exports[` is rendered 1`] = ` disabled={false} element="button" fill={true} + iconSide="left" iconType="folderOpen" isDisabled={false} size="m" diff --git a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/__snapshots__/primary.test.tsx.snap b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/__snapshots__/primary.test.tsx.snap index 8e447f7a0ee5c..7f50690aba8a6 100644 --- a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/__snapshots__/primary.test.tsx.snap +++ b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/__snapshots__/primary.test.tsx.snap @@ -43,6 +43,7 @@ exports[` is rendered 1`] = ` is rendered 1`] = ` disabled={false} element="button" fill={true} + iconSide="left" isDisabled={false} size="m" type="button" diff --git a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.mdx b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.mdx index c1fa431f39bdc..5b72eb92360be 100644 --- a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.mdx +++ b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.mdx @@ -1,12 +1,12 @@ --- id: sharedUX/Components/ToolbarButton slug: /shared-ux/components/toolbar/buttons/primary -title: Solution Toolbar Button +title: Toolbar Button summary: An opinionated implementation of the toolbar extracted to just the button. tags: ['shared-ux', 'component'] -date: 2022-02-17 +date: 2022-03-30 --- > This documentation is in-progress. -This button is a part of the solution toolbar component. This button has primary styling and requires a label. OnClick handlers and icon types are supported as an extension of EuiButtonProps. Icons are always on the left of any labels within the button. +This button is a part of the solution toolbar component. This button has primary styling and requires a label. OnClick handlers, icon side, and icon types are supported as an extension of EuiButtonProps. Icons by default are left of any labels within the button but can also be set to right. diff --git a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.tsx b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.tsx index 48677d965fa6c..f935a08fe8434 100644 --- a/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.tsx +++ b/packages/kbn-shared-ux-components/src/toolbar/buttons/primary/primary.tsx @@ -10,13 +10,13 @@ import React from 'react'; import { EuiButton } from '@elastic/eui'; import { EuiButtonPropsForButton } from '@elastic/eui/src/components/button/button'; -export interface Props extends Pick { +export interface Props extends Pick { label: string; } -export const ToolbarButton = ({ label, ...rest }: Props) => { +export const ToolbarButton = ({ label, iconSide = 'left', ...rest }: Props) => { return ( - + {label} ); diff --git a/packages/kbn-shared-ux-components/src/toolbar/index.ts b/packages/kbn-shared-ux-components/src/toolbar/index.ts index 513f81c1ddfc7..f3e74ace3e5ff 100644 --- a/packages/kbn-shared-ux-components/src/toolbar/index.ts +++ b/packages/kbn-shared-ux-components/src/toolbar/index.ts @@ -8,3 +8,4 @@ export { ToolbarButton } from './buttons/primary/primary'; export { IconButtonGroup } from './buttons/icon_button_group/icon_button_group'; export { AddFromLibraryButton } from './buttons/add_from_library/add_from_library'; +export { ToolbarPopover } from './popovers/popover'; diff --git a/packages/kbn-shared-ux-components/src/toolbar/popovers/__snapshots__/popover.test.tsx.snap b/packages/kbn-shared-ux-components/src/toolbar/popovers/__snapshots__/popover.test.tsx.snap new file mode 100644 index 0000000000000..c38d0b8e4cd7c --- /dev/null +++ b/packages/kbn-shared-ux-components/src/toolbar/popovers/__snapshots__/popover.test.tsx.snap @@ -0,0 +1,89 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` is rendered 1`] = ` + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + > +
+
+ + + + + + + +
+
+
+
+`; diff --git a/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.mdx b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.mdx new file mode 100644 index 0000000000000..d1ade51485ae4 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.mdx @@ -0,0 +1,11 @@ +--- +id: sharedUX/Components/Popover +slug: /shared-ux/components/toolbar/popovers/popover +title: Toolbar Popover +summary: A popover component that can be placed within a toolbar button. +tags: ['shared-ux', 'component'] +date: 2022-03-28 +--- + +This component is a thing wrapper around `EuiPopover` that handles open and close state. Its open and close state is controlled by a `ToolbarButton` button component. +This popover requires a label and children. \ No newline at end of file diff --git a/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.stories.tsx b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.stories.tsx new file mode 100644 index 0000000000000..f429cebd7071b --- /dev/null +++ b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.stories.tsx @@ -0,0 +1,70 @@ +/* + * 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 { EuiContextMenu } from '@elastic/eui'; +import { ButtonContentIconSide } from '@elastic/eui/src/components/button/button_content'; +import { Story } from '@storybook/react'; +import React from 'react'; +import { ToolbarPopover } from './popover'; +import mdx from './popover.mdx'; + +export default { + title: 'Toolbar/Popover', + description: 'A popover that is a part of a toolbar.', + parameters: { + docs: { + page: mdx, + }, + }, + argTypes: { + iconSide: { + control: { + type: 'radio', + options: ['left', 'right', 'undefined'], + }, + }, + }, +}; + +export const Component: Story<{ + iconSide: ButtonContentIconSide | undefined; +}> = ({ iconSide }) => { + return ( + + {() => ( + + )} + + ); +}; + +Component.args = { + iconSide: 'left', +}; diff --git a/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.test.tsx b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.test.tsx new file mode 100644 index 0000000000000..fcbf3d3542a16 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.test.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { mount as enzymeMount } from 'enzyme'; +import React from 'react'; +import { ToolbarPopover } from './popover'; + +describe('', () => { + test('is rendered', () => { + const isOpen = true; + const component = enzymeMount( !isOpen} />); + + expect(component).toMatchSnapshot(); + }); + + test('accepts an onClick handler', () => { + const isOpen = true; + const mockHandler = jest.fn(); + const component = enzymeMount( + !isOpen} onClick={mockHandler} /> + ); + component.simulate('click'); + expect(mockHandler).toHaveBeenCalled(); + }); +}); diff --git a/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.tsx b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.tsx new file mode 100644 index 0000000000000..ceae588b61941 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/toolbar/popovers/popover.tsx @@ -0,0 +1,41 @@ +/* + * 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 React, { useState } from 'react'; +import { EuiPopover } from '@elastic/eui'; +import { Props as EuiPopoverProps } from '@elastic/eui/src/components/popover/popover'; + +import { ToolbarButton, Props as ButtonProps } from '../buttons/primary/primary'; + +type AllowedButtonProps = Omit; +type AllowedPopoverProps = Omit< + EuiPopoverProps, + 'button' | 'isOpen' | 'closePopover' | 'anchorPosition' +>; + +export type Props = AllowedButtonProps & + AllowedPopoverProps & { + children: (arg: { closePopover: () => void }) => React.ReactNode; + }; + +export const ToolbarPopover = ({ label, iconType, children, iconSide, ...popover }: Props) => { + const [isOpen, setIsOpen] = useState(false); + + const onButtonClick = () => setIsOpen((status) => !status); + const closePopover = () => setIsOpen(false); + + const button = ; + + return ( + // the following ts-ignore is needed until typings/* directory is exposed for consumption to packages + // @ts-ignore Types of property css are incompatible Type 'InterpolationWithTheme' is not assignable to type 'Interpolation'. + + {children({ closePopover })} + + ); +}; diff --git a/packages/kbn-type-summarizer/BUILD.bazel b/packages/kbn-type-summarizer/BUILD.bazel index ec0df11bc3762..4399e62f11a77 100644 --- a/packages/kbn-type-summarizer/BUILD.bazel +++ b/packages/kbn-type-summarizer/BUILD.bazel @@ -1,8 +1,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("@rules_nodejs//nodejs:directory_file_path.bzl", "directory_file_path") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "nodejs_binary") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_binary") -load("@build_bazel_rules_nodejs//:index.bzl", "directory_file_path") PKG_BASE_NAME = "kbn-type-summarizer" PKG_REQUIRE_NAME = "@kbn/type-summarizer" diff --git a/packages/kbn-ui-shared-deps-npm/BUILD.bazel b/packages/kbn-ui-shared-deps-npm/BUILD.bazel index 17bbb09bd36e3..ec27891f2592e 100644 --- a/packages/kbn-ui-shared-deps-npm/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-npm/BUILD.bazel @@ -28,7 +28,6 @@ NPM_MODULE_EXTRA_FILES = [ ] RUNTIME_DEPS = [ - "//packages/elastic-datemath", "@npm//@babel/runtime", "@npm//@elastic/charts", "@npm//@elastic/eui", diff --git a/packages/kbn-ui-shared-deps-src/BUILD.bazel b/packages/kbn-ui-shared-deps-src/BUILD.bazel index 295f6fa0594ed..72b02f0f0b160 100644 --- a/packages/kbn-ui-shared-deps-src/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-src/BUILD.bazel @@ -28,10 +28,10 @@ NPM_MODULE_EXTRA_FILES = [ ] RUNTIME_DEPS = [ - "//packages/elastic-datemath", "//packages/elastic-safer-lodash-set", "//packages/kbn-analytics", "//packages/kbn-babel-preset", + "//packages/kbn-datemath", "//packages/kbn-flot-charts", "//packages/kbn-i18n", "//packages/kbn-i18n-react", @@ -42,9 +42,9 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/elastic-datemath:npm_module_types", "//packages/elastic-safer-lodash-set:npm_module_types", "//packages/kbn-analytics:npm_module_types", + "//packages/kbn-datemath:npm_module_types", "//packages/kbn-i18n:npm_module_types", "//packages/kbn-i18n-react:npm_module_types", "//packages/kbn-monaco:npm_module_types", diff --git a/packages/kbn-ui-shared-deps-src/src/definitions.js b/packages/kbn-ui-shared-deps-src/src/definitions.js index ce859ca4b977f..ea2bb15c29524 100644 --- a/packages/kbn-ui-shared-deps-src/src/definitions.js +++ b/packages/kbn-ui-shared-deps-src/src/definitions.js @@ -56,6 +56,7 @@ const externals = { numeral: '__kbnSharedDeps__.ElasticNumeral', '@elastic/numeral': '__kbnSharedDeps__.ElasticNumeral', '@elastic/charts': '__kbnSharedDeps__.ElasticCharts', + '@kbn/datemath': '__kbnSharedDeps__.KbnDatemath', '@elastic/eui': '__kbnSharedDeps__.ElasticEui', '@elastic/eui/lib/services': '__kbnSharedDeps__.ElasticEuiLibServices', '@elastic/eui/lib/services/format': '__kbnSharedDeps__.ElasticEuiLibServicesFormat', diff --git a/packages/kbn-ui-shared-deps-src/src/entry.js b/packages/kbn-ui-shared-deps-src/src/entry.js index a52dcc1440efb..d88de271519bd 100644 --- a/packages/kbn-ui-shared-deps-src/src/entry.js +++ b/packages/kbn-ui-shared-deps-src/src/entry.js @@ -41,7 +41,7 @@ export const ElasticEui = require('@elastic/eui'); export const ElasticEuiLibServices = require('@elastic/eui/lib/services'); export const ElasticEuiLibServicesFormat = require('@elastic/eui/lib/services/format'); export const ElasticEuiChartsTheme = require('@elastic/eui/dist/eui_charts_theme'); -export const ElasticDatemath = require('@elastic/datemath'); +export const KbnDatemath = require('@kbn/datemath'); export const ReactBeautifulDnD = require('react-beautiful-dnd'); export const Lodash = require('lodash'); diff --git a/src/core/server/elasticsearch/client/client_config.test.ts b/src/core/server/elasticsearch/client/client_config.test.ts index fb5f83c2a6bc0..dcc6d25c565bf 100644 --- a/src/core/server/elasticsearch/client/client_config.test.ts +++ b/src/core/server/elasticsearch/client/client_config.test.ts @@ -269,9 +269,9 @@ describe('parseClientOptions', () => { ) ).toEqual( expect.objectContaining({ - headers: expect.objectContaining({ - authorization: `Bearer ABC123`, - }), + auth: { + bearer: `ABC123`, + }, }) ); }); diff --git a/src/core/server/elasticsearch/client/client_config.ts b/src/core/server/elasticsearch/client/client_config.ts index 9a0b72a36c3db..63b9555a420ab 100644 --- a/src/core/server/elasticsearch/client/client_config.ts +++ b/src/core/server/elasticsearch/client/client_config.ts @@ -88,8 +88,9 @@ export function parseClientOptions( password: config.password, }; } else if (config.serviceAccountToken) { - // TODO: change once ES client has native support for service account tokens: https://github.com/elastic/elasticsearch-js/issues/1477 - clientOptions.headers!.authorization = `Bearer ${config.serviceAccountToken}`; + clientOptions.auth = { + bearer: config.serviceAccountToken, + }; } } diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 4ab59d12942e7..07462a52ef220 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -8,7 +8,6 @@ import { Observable, Subject } from 'rxjs'; import { first, map, shareReplay, takeUntil } from 'rxjs/operators'; -import { merge } from '@kbn/std'; import { CoreService } from '../../types'; import { CoreContext } from '../core_context'; @@ -29,6 +28,7 @@ import { calculateStatus$ } from './status'; import { isValidConnection } from './is_valid_connection'; import { isInlineScriptingEnabled } from './is_scripting_enabled'; import type { UnauthorizedErrorHandler } from './client/retry_unauthorized'; +import { mergeConfig } from './merge_config'; export interface SetupDeps { http: InternalHttpServiceSetup; @@ -154,10 +154,10 @@ export class ElasticsearchService private createClusterClient( type: string, - baseConfig: ElasticsearchConfig, - clientConfig?: Partial + baseConfig: ElasticsearchClientConfig, + clientConfig: Partial = {} ) { - const config = clientConfig ? merge({}, baseConfig, clientConfig) : baseConfig; + const config = mergeConfig(baseConfig, clientConfig); return new ClusterClient({ config, logger: this.coreContext.logger.get('elasticsearch'), diff --git a/src/core/server/elasticsearch/merge_config.test.ts b/src/core/server/elasticsearch/merge_config.test.ts new file mode 100644 index 0000000000000..c89a759435284 --- /dev/null +++ b/src/core/server/elasticsearch/merge_config.test.ts @@ -0,0 +1,136 @@ +/* + * 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 { mergeConfig } from './merge_config'; +import type { ElasticsearchClientConfig } from './client'; +import { configSchema, ElasticsearchConfig } from './elasticsearch_config'; + +const partialToConfig = (parts: Partial): ElasticsearchClientConfig => { + return parts as ElasticsearchClientConfig; +}; + +describe('mergeConfig', () => { + it('merges the base config and the overrides', () => { + const base = partialToConfig({ + hosts: ['localhost'], + compression: true, + }); + const overrides: Partial = { + maxSockets: 42, + }; + + expect(mergeConfig(base, overrides)).toEqual({ + hosts: ['localhost'], + compression: true, + maxSockets: 42, + }); + }); + + it('properly override values that are present in both the base config and the overrides', () => { + const base = partialToConfig({ + hosts: ['localhost'], + compression: true, + }); + const overrides: Partial = { + compression: false, + maxSockets: 42, + }; + + expect(mergeConfig(base, overrides)).toEqual({ + hosts: ['localhost'], + compression: false, + maxSockets: 42, + }); + }); + + it('fully override arrays instead of aggregating them', () => { + const base = partialToConfig({ + hosts: ['localhost'], + }); + const overrides: Partial = { + hosts: ['another-host'], + }; + + expect(mergeConfig(base, overrides)).toEqual({ + hosts: ['another-host'], + }); + }); + + it('ignores the `username` and `password` fields from the base config if overrides defines `serviceAccountToken`', () => { + const base = partialToConfig({ + hosts: ['localhost'], + username: 'foo', + password: 'bar', + }); + const overrides: Partial = { + hosts: ['another-host'], + serviceAccountToken: 'token', + }; + + expect(mergeConfig(base, overrides)).toEqual({ + hosts: ['another-host'], + serviceAccountToken: 'token', + }); + }); + + it('ignores the `serviceAccountToken` field from the base config if overrides defines `username` and `password`', () => { + const base = partialToConfig({ + hosts: ['localhost'], + serviceAccountToken: 'token', + }); + const overrides: Partial = { + hosts: ['another-host'], + username: 'foo', + password: 'bar', + }; + + expect(mergeConfig(base, overrides)).toEqual({ + hosts: ['another-host'], + username: 'foo', + password: 'bar', + }); + }); + + it('does not mutate the base config', () => { + const base = partialToConfig({ + hosts: ['localhost'], + maxSockets: 42, + }); + const overrides: Partial = { + hosts: ['another-host'], + maxSockets: 9000, + compression: true, + }; + + mergeConfig(base, overrides); + + expect(base).toEqual({ + hosts: ['localhost'], + maxSockets: 42, + }); + }); + + it('works with a real instance of ElasticsearchConfig', () => { + const rawConfig = configSchema.validate({ + username: 'foo', + password: 'bar', + }); + + const baseConfig = new ElasticsearchConfig(rawConfig); + + const overrides: Partial = { + serviceAccountToken: 'token', + }; + + const output = mergeConfig(baseConfig, overrides); + + expect(output.serviceAccountToken).toEqual('token'); + expect(output.username).toBeUndefined(); + expect(output.password).toBeUndefined(); + }); +}); diff --git a/src/core/server/elasticsearch/merge_config.ts b/src/core/server/elasticsearch/merge_config.ts new file mode 100644 index 0000000000000..373bf6fc6cbe0 --- /dev/null +++ b/src/core/server/elasticsearch/merge_config.ts @@ -0,0 +1,31 @@ +/* + * 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 { merge } from '@kbn/std'; +import { Writable } from '@kbn/utility-types'; +import type { ElasticsearchClientConfig } from './client'; + +type WritableConfig = Writable; + +export const mergeConfig = ( + baseConfig: ElasticsearchClientConfig, + configOverrides: Partial +): ElasticsearchClientConfig => { + // note: spreading the source is sufficient because we're only removing keys + // if we were to perform more complex operations, a deep copy would be required here + const writableBaseConfig = { ...baseConfig } as WritableConfig; + + if (configOverrides.serviceAccountToken) { + delete writableBaseConfig.username; + delete writableBaseConfig.password; + } else if (configOverrides.username && configOverrides.password) { + delete writableBaseConfig.serviceAccountToken; + } + + return merge(writableBaseConfig, configOverrides); +}; diff --git a/src/core/server/http_resources/http_resources_service.ts b/src/core/server/http_resources/http_resources_service.ts index 25467152ce4fe..95610d36d4230 100644 --- a/src/core/server/http_resources/http_resources_service.ts +++ b/src/core/server/http_resources/http_resources_service.ts @@ -98,6 +98,7 @@ export class HttpResourcesService implements CoreService { it('picks nothing by default', () => { + const configSchema = schema.object({ + notExposed1: schema.string(), + nested: schema.object({ + notExposed2: schema.boolean(), + notExposed3: schema.maybe(schema.number()), + }), + }); const config = { - foo: 'bar', + notExposed1: '1', nested: { - str: 'string', - num: 42, + notExposed2: true, + notExposed3: 3, }, }; - const descriptor: ExposedToBrowserDescriptor = {}; - - const browserConfig = createBrowserConfig(config, descriptor); + const descriptor: PluginConfigDescriptor> = { + schema: configSchema, + }; - expect(browserConfig).toEqual({}); + const result = createBrowserConfig(config, descriptor); + expect(result).toEqual({ browserConfig: {}, exposedConfigKeys: {} }); }); it('picks all the nested properties when using `true`', () => { - const config = { - foo: 'bar', - nested: { - str: 'string', - num: 42, - }, - }; - - const descriptor: ExposedToBrowserDescriptor = { - foo: true, - nested: true, - }; - - const browserConfig = createBrowserConfig(config, descriptor); - - expect(browserConfig).toEqual({ - foo: 'bar', - nested: { - str: 'string', - num: 42, - }, + const configSchema = schema.object({ + exposed1: schema.string(), + nested: schema.object({ + exposed2: schema.boolean(), + exposed3: schema.maybe(schema.number()), + }), + notExposed4: schema.string(), }); - }); - - it('picks specific nested properties when using a nested declaration', () => { const config = { - foo: 'bar', + exposed1: '1', nested: { - str: 'string', - num: 42, + exposed2: true, + exposed3: 3, }, + notExposed4: '4', }; - - const descriptor: ExposedToBrowserDescriptor = { - foo: true, - nested: { - str: true, - num: false, + const descriptor: PluginConfigDescriptor> = { + schema: configSchema, + exposeToBrowser: { + exposed1: true, + nested: true, }, }; - const browserConfig = createBrowserConfig(config, descriptor); - - expect(browserConfig).toEqual({ - foo: 'bar', - nested: { - str: 'string', + const result = createBrowserConfig(config, descriptor); + expect(result).toEqual({ + browserConfig: { + exposed1: '1', + nested: { exposed2: true, exposed3: 3 }, + // notExposed4 is not present + }, + exposedConfigKeys: { + exposed1: 'string', + 'nested.exposed2': 'boolean', + 'nested.exposed3': 'number', + // notExposed4 is not present }, }); }); - it('accepts deeply nested structures', () => { + it('picks specific nested properties, omitting those which are not specified', () => { + const configSchema = schema.object({ + exposed1: schema.string(), + nested: schema.object({ + exposed2: schema.boolean(), + notExposed3: schema.maybe(schema.number()), + }), + notExposed4: schema.string(), + }); const config = { - foo: 'bar', - deeply: { - str: 'string', - nested: { - hello: 'dolly', - structure: { - propA: 'propA', - propB: 'propB', - }, - }, + exposed1: '1', + nested: { + exposed2: true, + notExposed3: 3, }, + notExposed4: '4', }; - - const descriptor: ExposedToBrowserDescriptor = { - foo: false, - deeply: { - str: false, - nested: { - hello: true, - structure: { - propA: true, - propB: false, - }, - }, + const descriptor: PluginConfigDescriptor> = { + schema: configSchema, + exposeToBrowser: { + exposed1: true, + nested: { exposed2: true }, }, }; - const browserConfig = createBrowserConfig(config, descriptor); - - expect(browserConfig).toEqual({ - deeply: { - nested: { - hello: 'dolly', - structure: { - propA: 'propA', - }, - }, + const result = createBrowserConfig(config, descriptor); + expect(result).toEqual({ + browserConfig: { + exposed1: '1', + nested: { exposed2: true }, + // notExposed3 and notExposed4 are not present + }, + exposedConfigKeys: { + exposed1: 'string', + 'nested.exposed2': 'boolean', + // notExposed3 and notExposed4 are not present }, }); }); - it('only includes leaf properties that are `true` when in nested structures', () => { + it('picks specific deeply nested properties, omitting those which are not specified', () => { + const configSchema = schema.object({ + exposed1: schema.string(), + deeply: schema.object({ + exposed2: schema.boolean(), + nested: schema.object({ + exposed3: schema.maybe(schema.number()), + structure: schema.object({ + exposed4: schema.string(), + notExposed5: schema.string(), + }), + notExposed6: schema.string(), + }), + notExposed7: schema.string(), + }), + notExposed8: schema.string(), + }); const config = { - foo: 'bar', + exposed1: '1', deeply: { - str: 'string', + exposed2: true, nested: { - hello: 'dolly', + exposed3: 3, structure: { - propA: 'propA', - propB: 'propB', + exposed4: '4', + notExposed5: '5', }, + notExposed6: '6', }, + notExposed7: '7', }, + notExposed8: '8', }; - - const descriptor: ExposedToBrowserDescriptor = { - deeply: { - nested: { - hello: true, - structure: { - propA: true, + const descriptor: PluginConfigDescriptor> = { + schema: configSchema, + exposeToBrowser: { + exposed1: true, + deeply: { + exposed2: true, + nested: { + exposed3: true, + structure: { + exposed4: true, + }, }, }, }, }; - const browserConfig = createBrowserConfig(config, descriptor); - - expect(browserConfig).toEqual({ - deeply: { - nested: { - hello: 'dolly', - structure: { - propA: 'propA', + const result = createBrowserConfig(config, descriptor); + expect(result).toEqual({ + browserConfig: { + exposed1: '1', + deeply: { + exposed2: true, + nested: { + exposed3: 3, + structure: { + exposed4: '4', + }, }, }, + // notExposed5, notExposed6, notExposed7, and notExposed8 are not present + }, + exposedConfigKeys: { + exposed1: 'string', + 'deeply.exposed2': 'boolean', + 'deeply.nested.exposed3': 'number', + 'deeply.nested.structure.exposed4': 'string', + // notExposed5, notExposed6, notExposed7, and notExposed8 are not present }, }); }); diff --git a/src/core/server/plugins/create_browser_config.ts b/src/core/server/plugins/create_browser_config.ts index 95c8de7f4c8cd..0bf812d2e5cce 100644 --- a/src/core/server/plugins/create_browser_config.ts +++ b/src/core/server/plugins/create_browser_config.ts @@ -6,19 +6,25 @@ * Side Public License, v 1. */ -import { ExposedToBrowserDescriptor } from './types'; +import { ExposedToBrowserDescriptor, PluginConfigDescriptor } from './types'; export const createBrowserConfig = ( config: T, - descriptor: ExposedToBrowserDescriptor -): unknown => { - return recursiveCreateConfig(config, descriptor); + descriptor: PluginConfigDescriptor +) => { + if (!descriptor.exposeToBrowser) { + return { browserConfig: {}, exposedConfigKeys: {} }; + } + return { + browserConfig: recursiveCreateConfig(config, descriptor.exposeToBrowser), + exposedConfigKeys: getExposedConfigKeys(descriptor), + }; }; const recursiveCreateConfig = ( config: T, descriptor: ExposedToBrowserDescriptor = {} -): unknown => { +) => { return Object.entries(config || {}).reduce((browserConfig, [key, value]) => { const exposedConfig = descriptor[key as keyof ExposedToBrowserDescriptor]; if (exposedConfig && typeof exposedConfig === 'object') { @@ -30,3 +36,39 @@ const recursiveCreateConfig = ( return browserConfig; }, {} as Record); }; + +/** + * Given a plugin descriptor, this function returns an object that contains a flattened list of exposed config keys. This is used for a CI + * check to ensure that consumers don't accidentally expose more config settings to the browser than intended. + */ +function getExposedConfigKeys(descriptor: PluginConfigDescriptor) { + const schemaStructure = descriptor.schema.getSchemaStructure(); + const flattenedConfigSchema: Record = {}; + for (const { path, type } of schemaStructure) { + if (checkIsPathExposed(path, descriptor.exposeToBrowser!)) { + flattenedConfigSchema[path.join('.')] = type; + } + } + return flattenedConfigSchema; +} + +function checkIsPathExposed( + path: string[], + descriptor: ExposedToBrowserDescriptor +) { + let isExposed = false; + for (const key of path) { + // Traverse the path to see if it is exposed or not + const exposedConfig = descriptor[key as keyof ExposedToBrowserDescriptor]; + if (exposedConfig && typeof exposedConfig === 'object') { + // @ts-expect-error Type 'undefined' is not assignable to type 'ExposedToBrowserDescriptor' + descriptor = exposedConfig; + continue; + } + if (exposedConfig === true) { + isExposed = true; + } + break; + } + return isExposed; +} diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index 65ef756b39e17..7c6938bdde224 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -1012,14 +1012,16 @@ describe('PluginsService', () => { const prebootUIConfig$ = preboot.uiPlugins.browserConfigs.get('plugin-with-expose-preboot')!; await expect(prebootUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({ - sharedProp: 'sharedProp default value plugin-with-expose-preboot', + browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-preboot' }, + exposedConfigKeys: { sharedProp: 'string' }, }); const standardUIConfig$ = standard.uiPlugins.browserConfigs.get( 'plugin-with-expose-standard' )!; await expect(standardUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({ - sharedProp: 'sharedProp default value plugin-with-expose-standard', + browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-standard' }, + exposedConfigKeys: { sharedProp: 'string' }, }); }); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index f202f09735d45..2c1ba26b96ebb 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -231,9 +231,7 @@ export class PluginsService implements CoreService createBrowserConfig(config, configDescriptor.exposeToBrowser!)) - ), + .pipe(map((config: any) => createBrowserConfig(config, configDescriptor))), ]; }) ); diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index 9d15c7df15715..73746a8f202ff 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -80,7 +80,7 @@ export class RenderingService { { http, uiPlugins, status }: RenderOptions, request: KibanaRequest, uiSettings: IUiSettingsClient, - { isAnonymousPage = false, vars }: IRenderOptions = {} + { isAnonymousPage = false, vars, includeExposedConfigKeys }: IRenderOptions = {} ) { const env = { mode: this.coreContext.env.mode, @@ -135,11 +135,15 @@ export class RenderingService { externalUrl: http.externalUrl, vars: vars ?? {}, uiPlugins: await Promise.all( - filteredPlugins.map(async ([id, plugin]) => ({ - id, - plugin, - config: await getUiConfig(uiPlugins, id), - })) + filteredPlugins.map(async ([id, plugin]) => { + const { browserConfig, exposedConfigKeys } = await getUiConfig(uiPlugins, id); + return { + id, + plugin, + config: browserConfig, + ...(includeExposedConfigKeys && { exposedConfigKeys }), + }; + }) ), legacyMetadata: { uiSettings: settings, @@ -155,5 +159,8 @@ export class RenderingService { const getUiConfig = async (uiPlugins: UiPlugins, pluginId: string) => { const browserConfig = uiPlugins.browserConfigs.get(pluginId); - return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {}) as Record; + return ((await browserConfig?.pipe(take(1)).toPromise()) ?? { + browserConfig: {}, + exposedConfigKeys: {}, + }) as { browserConfig: Record; exposedConfigKeys: Record }; }; diff --git a/src/core/server/rendering/types.ts b/src/core/server/rendering/types.ts index 121c272089a7c..2c0aafe61e018 100644 --- a/src/core/server/rendering/types.ts +++ b/src/core/server/rendering/types.ts @@ -93,6 +93,12 @@ export interface IRenderOptions { * @internal */ vars?: Record; + + /** + * @internal + * This is only used for integration tests that allow us to verify which config keys are exposed to the browser. + */ + includeExposedConfigKeys?: boolean; } /** @internal */ diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index daba13d656f52..fbd6fd1492094 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1135,6 +1135,8 @@ export interface HttpResources { // @public export interface HttpResourcesRenderOptions { headers?: ResponseHeaders; + // @internal + includeExposedConfigKeys?: boolean; } // @public @@ -1308,6 +1310,8 @@ export interface IntervalHistogram { // @public (undocumented) export interface IRenderOptions { + // @internal + includeExposedConfigKeys?: boolean; isAnonymousPage?: boolean; // @internal @deprecated vars?: Record; diff --git a/src/dev/bazel/pkg_npm_types.bzl b/src/dev/bazel/pkg_npm_types.bzl index e5caba5149053..f90d60252af2d 100644 --- a/src/dev/bazel/pkg_npm_types.bzl +++ b/src/dev/bazel/pkg_npm_types.bzl @@ -142,7 +142,7 @@ pkg_npm_types = rule( "_packager": attr.label( doc = "Target that executes the npm types package assembler binary", executable = True, - cfg = "host", + cfg = "exec", default = Label("//packages/kbn-type-summarizer:bazel-cli"), ), }, diff --git a/src/plugins/chart_expressions/expression_gauge/common/index.ts b/src/plugins/chart_expressions/expression_gauge/common/index.ts index 395aa3ed60861..24d4dc3c8d997 100755 --- a/src/plugins/chart_expressions/expression_gauge/common/index.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/index.ts @@ -14,9 +14,6 @@ export type { GaugeExpressionProps, FormatFactory, GaugeRenderProps, - CustomPaletteParams, - ColorStop, - RequiredPaletteParamTypes, GaugeArguments, GaugeShape, GaugeLabelMajorMode, diff --git a/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts index b2696acda6c7d..b090dc5346146 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts @@ -7,13 +7,14 @@ */ import { $Values } from '@kbn/utility-types'; +import type { PaletteOutput, CustomPaletteParams } from '@kbn/coloring'; import { Datatable, ExpressionFunctionDefinition, ExpressionValueRender, } from '../../../../expressions'; import { ExpressionValueVisDimension } from '../../../../visualizations/public'; -import { CustomPaletteState, PaletteOutput } from '../../../../charts/common'; +import { CustomPaletteState } from '../../../../charts/common'; import { EXPRESSION_GAUGE_NAME, GAUGE_FUNCTION_RENDERER_NAME, @@ -23,7 +24,6 @@ import { GaugeColorModes, GaugeCentralMajorModes, } from '../constants'; -import { CustomPaletteParams } from '.'; export type GaugeColorMode = $Values; export type GaugeShape = $Values; diff --git a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts index 4c2133e8572f8..2f1560550690b 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import { PersistedState } from '../../../../visualizations/public'; -import type { ChartsPluginSetup, PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry } from '@kbn/coloring'; +import type { PersistedState } from '../../../../visualizations/public'; +import type { ChartsPluginSetup } from '../../../../charts/public'; import type { IFieldFormat, SerializedFieldFormat } from '../../../../field_formats/common'; import type { GaugeExpressionProps } from './expression_functions'; @@ -19,23 +20,3 @@ export type GaugeRenderProps = GaugeExpressionProps & { paletteService: PaletteRegistry; uiState: PersistedState; }; - -export interface ColorStop { - color: string; - stop: number; -} - -export interface CustomPaletteParams { - name?: string; - reverse?: boolean; - rangeType?: 'number' | 'percent'; - continuity?: 'above' | 'below' | 'all' | 'none'; - progression?: 'fixed'; - rangeMin?: number; - rangeMax?: number; - stops?: ColorStop[]; - colorStops?: ColorStop[]; - steps?: number; -} - -export type RequiredPaletteParamTypes = Required; diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx index e7e1e47ca65f2..ef21811402c2a 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx @@ -7,6 +7,7 @@ */ import React from 'react'; +import { ColorStop } from '@kbn/coloring'; import { chartPluginMock } from '../../../../charts/public/mocks'; import { fieldFormatsServiceMock } from '../../../../field_formats/public/mocks'; import type { Datatable } from '../../../../expressions/public'; @@ -15,7 +16,6 @@ import { shallowWithIntl } from '@kbn/test-jest-helpers'; import { GaugeRenderProps, GaugeArguments, - ColorStop, GaugeLabelMajorModes, GaugeTicksPositions, GaugeColorModes, diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx index efaea7dd24954..e4687d19aa63c 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx @@ -8,8 +8,9 @@ import React, { FC, memo, useCallback } from 'react'; import { Chart, Goal, Settings } from '@elastic/charts'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { PaletteOutput } from '@kbn/coloring'; import { FieldFormat } from '../../../../field_formats/common'; -import type { CustomPaletteState, PaletteOutput } from '../../../../charts/public'; +import type { CustomPaletteState } from '../../../../charts/public'; import { EmptyPlaceholder } from '../../../../charts/public'; import { isVisDimension } from '../../../../visualizations/common/utils'; import { diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/utils/accessors.ts b/src/plugins/chart_expressions/expression_gauge/public/components/utils/accessors.ts index 31a2ff61ceaa7..cd5379f0e9ed7 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/utils/accessors.ts +++ b/src/plugins/chart_expressions/expression_gauge/public/components/utils/accessors.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ +import type { CustomPaletteParams } from '@kbn/coloring'; import type { DatatableColumn, DatatableRow } from 'src/plugins/expressions'; import { getAccessorByDimension } from '../../../../../visualizations/common/utils'; -import { Accessors, GaugeArguments, CustomPaletteParams } from '../../../common'; +import { Accessors, GaugeArguments } from '../../../common'; export const getValueFromAccessor = ( accessor: string, diff --git a/src/plugins/chart_expressions/expression_gauge/public/services/palette_service.ts b/src/plugins/chart_expressions/expression_gauge/public/services/palette_service.ts index cfcf2a818c5bc..d18db6340fd45 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/services/palette_service.ts +++ b/src/plugins/chart_expressions/expression_gauge/public/services/palette_service.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import type { PaletteRegistry } from '@kbn/coloring'; import { createGetterSetter } from '../../../../kibana_utils/public'; -import { PaletteRegistry } from '../../../../charts/public'; export const [getPaletteService, setPaletteService] = createGetterSetter('palette'); diff --git a/src/plugins/chart_expressions/expression_heatmap/common/index.ts b/src/plugins/chart_expressions/expression_heatmap/common/index.ts index 56bafc2a0d612..484dee11c300b 100755 --- a/src/plugins/chart_expressions/expression_heatmap/common/index.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/index.ts @@ -15,9 +15,6 @@ export type { BrushEvent, FormatFactory, HeatmapRenderProps, - CustomPaletteParams, - ColorStop, - RequiredPaletteParamTypes, HeatmapLegendConfigResult, HeatmapGridConfigResult, HeatmapArguments, diff --git a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts index 9208c8b48a29e..d96a803df92f5 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ import { Position } from '@elastic/charts'; +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, ExpressionFunctionDefinition, @@ -13,7 +14,7 @@ import { } from '../../../../expressions'; import { ExpressionValueVisDimension } from '../../../../visualizations/common'; -import { CustomPaletteState, PaletteOutput } from '../../../../charts/common'; +import { CustomPaletteState } from '../../../../charts/common'; import { EXPRESSION_HEATMAP_NAME, EXPRESSION_HEATMAP_LEGEND_NAME, diff --git a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts index fa8bc5ee2e19d..67160240d284b 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import type { ChartsPluginSetup, PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry } from '@kbn/coloring'; +import type { ChartsPluginSetup } from '../../../../charts/public'; import type { IFieldFormat, SerializedFieldFormat } from '../../../../field_formats/common'; import type { RangeSelectContext, ValueClickContext } from '../../../../embeddable/public'; import type { PersistedState } from '../../../../visualizations/public'; @@ -34,23 +35,3 @@ export type HeatmapRenderProps = HeatmapExpressionProps & { uiState: PersistedState; interactive: boolean; }; - -export interface ColorStop { - color: string; - stop: number; -} - -export interface CustomPaletteParams { - name?: string; - reverse?: boolean; - rangeType?: 'number' | 'percent'; - continuity?: 'above' | 'below' | 'all' | 'none'; - progression?: 'fixed'; - rangeMin?: number; - rangeMax?: number; - stops?: ColorStop[]; - colorStops?: ColorStop[]; - steps?: number; -} - -export type RequiredPaletteParamTypes = Required; diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx index 2121221cc9585..40d3563756c18 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx @@ -35,7 +35,7 @@ import { LegendColorPickerWrapperContext, LegendColorPickerWrapper, } from '../utils/get_color_picker'; -import { DEFAULT_PALETTE_NAME, defaultPaletteParams } from '../constants'; +import { defaultPaletteParams } from '../constants'; import { HeatmapIcon } from './heatmap_icon'; import './index.scss'; @@ -96,9 +96,11 @@ function computeColorRanges( ) { const paletteColors = paletteParams?.colors || - applyPaletteParams(paletteService, { type: 'palette', name: DEFAULT_PALETTE_NAME }, minMax).map( - ({ color }) => color - ); + applyPaletteParams( + paletteService, + { type: 'palette', name: defaultPaletteParams.name }, + minMax + ).map(({ color }) => color); // Repeat the first color at the beginning to cover below and above the defined palette const colors = [paletteColors[0], ...paletteColors]; diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.test.ts b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.test.ts index 7e9ccee19aa11..5199d4286e69e 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.test.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.test.ts @@ -11,10 +11,7 @@ import type { DatatableColumn } from 'src/plugins/expressions/public'; import { applyPaletteParams, getDataMinMax, - getPaletteStops, - getStepValue, remapStopsByNewInterval, - reversePalette, getSortPredicate, } from './helpers'; @@ -152,209 +149,6 @@ describe('getDataMinMax', () => { }); }); -describe('getPaletteStops', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - it('should correctly compute a predefined palette stops definition from only the name', () => { - expect( - getPaletteStops(paletteRegistry, { name: 'mock' }, { dataBounds: { min: 0, max: 100 } }) - ).toEqual([ - { color: 'blue', stop: 20 }, - { color: 'yellow', stop: 70 }, - ]); - }); - - it('should correctly compute a predefined palette stops definition from explicit prevPalette (override)', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default' }, - { dataBounds: { min: 0, max: 100 }, prevPalette: 'mock' } - ) - ).toEqual([ - { color: 'blue', stop: 20 }, - { color: 'yellow', stop: 70 }, - ]); - }); - - it('should infer the domain from dataBounds but start from 0', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default', rangeType: 'number' }, - { dataBounds: { min: 1, max: 11 }, prevPalette: 'mock' } - ) - ).toEqual([ - { color: 'blue', stop: 2 }, - { color: 'yellow', stop: 7 }, - ]); - }); - - it('should override the minStop when requested', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default', rangeType: 'number' }, - { dataBounds: { min: 1, max: 11 }, mapFromMinValue: true } - ) - ).toEqual([ - { color: 'red', stop: 1 }, - { color: 'black', stop: 6 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 40 }, - { color: 'red', stop: 80 }, - ], - }, - { dataBounds: { min: 0, max: 100 } } - ) - ).toEqual([ - { color: 'green', stop: 40 }, - { color: 'blue', stop: 80 }, - { color: 'red', stop: 100 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 40 }, - { color: 'red', stop: 100 }, - ], - }, - { dataBounds: { min: 0, max: 100 } } - ) - ).toEqual([ - { color: 'green', stop: 40 }, - { color: 'blue', stop: 100 }, - { color: 'red', stop: 101 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end (fractional)', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 0.4 }, - { color: 'red', stop: 1 }, - ], - }, - { dataBounds: { min: 0, max: 1 } } - ) - ).toEqual([ - { color: 'green', stop: 0.4 }, - { color: 'blue', stop: 1 }, - { color: 'red', stop: 2 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - stretch the stops to 100% percent', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 0.4 }, - { color: 'red', stop: 1 }, - ], - }, - { dataBounds: { min: 0, max: 1 } } - ) - ).toEqual([ - { color: 'green', stop: 0.4 }, - { color: 'blue', stop: 1 }, - { color: 'red', stop: 100 }, // default rangeType is percent, hence stretch to 100% - ]); - }); -}); - -describe('reversePalette', () => { - it('should correctly reverse color and stops', () => { - expect( - reversePalette([ - { color: 'red', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'blue', stop: 0.9 }, - ]) - ).toEqual([ - { color: 'blue', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'red', stop: 0.9 }, - ]); - }); -}); - -describe('getStepValue', () => { - it('should compute the next step based on the last 2 stops', () => { - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 100 - ) - ).toBe(50); - - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 80 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 90 - ) - ).toBe(10); // 90 - 80 - - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 100 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 100 - ) - ).toBe(1); - }); -}); - describe('getSortPredicate', () => { it('should return dataIndex if otherbucker it enabled', () => { const column = { diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts index c9bfa68da9f22..b82b52e1a1a49 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts @@ -5,61 +5,22 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import type { Datatable, DatatableColumn } from 'src/plugins/expressions/public'; -import type { CustomPaletteParams, ColorStop } from '../../common'; + import { + PaletteOutput, + PaletteRegistry, + CustomPaletteParams, + getPaletteStops, + reversePalette, + ColorStop, CUSTOM_PALETTE, - defaultPaletteParams, DEFAULT_MAX_STOP, DEFAULT_MIN_STOP, -} from '../constants'; +} from '@kbn/coloring'; -// very simple heuristic: pick last two stops and compute a new stop based on the same distance -// if the new stop is above max, then reduce the step to reach max, or if zero then just 1. -// -// it accepts two series of stops as the function is used also when computing stops from colorStops -export function getStepValue(colorStops: ColorStop[], newColorStops: ColorStop[], max: number) { - const length = newColorStops.length; - // workout the steps from the last 2 items - const dataStep = newColorStops[length - 1].stop - newColorStops[length - 2].stop || 1; - let step = Number(dataStep.toFixed(2)); - if (max < colorStops[length - 1].stop + step) { - const diffToMax = max - colorStops[length - 1].stop; - // if the computed step goes way out of bound, fallback to 1, otherwise reach max - step = diffToMax > 0 ? diffToMax : 1; - } - return step; -} - -// Need to shift the Custom palette in order to correctly visualize it when in display mode -function shiftPalette(stops: ColorStop[], max: number) { - // shift everything right and add an additional stop at the end - const result = stops.map((entry, i, array) => ({ - ...entry, - stop: i + 1 < array.length ? array[i + 1].stop : max, - })); - if (stops[stops.length - 1].stop === max) { - // extends the range by a fair amount to make it work the extra case for the last stop === max - const computedStep = getStepValue(stops, result, max) || 1; - // do not go beyond the unit step in this case - const step = Math.min(1, computedStep); - result[stops.length - 1].stop = max + step; - } - return result; -} +import type { Datatable, DatatableColumn } from 'src/plugins/expressions/public'; -function getOverallMinMax( - params: CustomPaletteParams | undefined, - dataBounds: { min: number; max: number } -) { - const { min: dataMin, max: dataMax } = getDataMinMax(params?.rangeType, dataBounds); - const minStopValue = params?.colorStops?.[0]?.stop ?? Infinity; - const maxStopValue = params?.colorStops?.[params.colorStops.length - 1]?.stop ?? -Infinity; - const overallMin = Math.min(dataMin, minStopValue); - const overallMax = Math.max(dataMax, maxStopValue); - return { min: overallMin, max: overallMax }; -} +import { defaultPaletteParams } from '../constants'; export function getDataMinMax( rangeType: CustomPaletteParams['rangeType'] | undefined, @@ -86,63 +47,6 @@ export function remapStopsByNewInterval( }; }); } -/** - * This is a generic function to compute stops from the current parameters. - */ -export function getPaletteStops( - palettes: PaletteRegistry, - activePaletteParams: CustomPaletteParams, - // used to customize color resolution - { - prevPalette, - dataBounds, - mapFromMinValue, - defaultPaletteName, - }: { - prevPalette?: string; - dataBounds: { min: number; max: number }; - mapFromMinValue?: boolean; - defaultPaletteName?: string; - } -) { - const { min: minValue, max: maxValue } = getOverallMinMax(activePaletteParams, dataBounds); - const interval = maxValue - minValue; - const { stops: currentStops, ...otherParams } = activePaletteParams || {}; - - if (activePaletteParams.name === 'custom' && activePaletteParams?.colorStops) { - // need to generate the palette from the existing controlStops - return shiftPalette(activePaletteParams.colorStops, maxValue); - } - // generate a palette from predefined ones and customize the domain - const colorStopsFromPredefined = palettes - .get( - prevPalette || activePaletteParams?.name || defaultPaletteName || defaultPaletteParams.name - ) - .getCategoricalColors(defaultPaletteParams.steps, otherParams); - - const newStopsMin = mapFromMinValue ? minValue : interval / defaultPaletteParams.steps; - - const stops = remapStopsByNewInterval( - colorStopsFromPredefined.map((color, index) => ({ color, stop: index })), - { - newInterval: interval, - oldInterval: colorStopsFromPredefined.length, - newMin: newStopsMin, - oldMin: 0, - } - ); - return stops; -} - -export function reversePalette(paletteColorRepresentation: ColorStop[] = []) { - const stops = paletteColorRepresentation.map(({ stop }) => stop); - return paletteColorRepresentation - .map(({ color }, i) => ({ - color, - stop: stops[paletteColorRepresentation.length - i - 1], - })) - .reverse(); -} /** * Some name conventions here: @@ -169,7 +73,7 @@ export function applyPaletteParams> // make a copy of it as they have to be manipulated later on let displayStops = getPaletteStops(palettes, activePalette?.params || {}, { dataBounds, - defaultPaletteName: activePalette?.name, + defaultPaletteName: activePalette?.name ?? defaultPaletteParams.name, }); if (activePalette?.params?.reverse && activePalette?.params?.name !== CUSTOM_PALETTE) { @@ -220,6 +124,7 @@ export const findMinMaxByColumnId = ( } return minMax; }; + interface SourceParams { order?: string; orderBy?: string; diff --git a/src/plugins/chart_expressions/expression_heatmap/public/constants.ts b/src/plugins/chart_expressions/expression_heatmap/public/constants.ts index 79e24d05e3fde..a643f15c2274c 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/constants.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/constants.ts @@ -5,16 +5,17 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { RequiredPaletteParamTypes } from '../common'; -export const DEFAULT_PALETTE_NAME = 'temperature'; -export const FIXED_PROGRESSION = 'fixed' as const; -export const CUSTOM_PALETTE = 'custom'; -export const DEFAULT_CONTINUITY = 'above'; -export const DEFAULT_MIN_STOP = 0; -export const DEFAULT_MAX_STOP = 100; -export const DEFAULT_COLOR_STEPS = 5; +import { + RequiredPaletteParamTypes, + FIXED_PROGRESSION, + DEFAULT_CONTINUITY, + DEFAULT_MIN_STOP, + DEFAULT_MAX_STOP, + DEFAULT_COLOR_STEPS, +} from '@kbn/coloring'; + export const defaultPaletteParams: RequiredPaletteParamTypes = { - name: DEFAULT_PALETTE_NAME, + name: 'temperature', reverse: false, rangeType: 'percent', rangeMin: DEFAULT_MIN_STOP, diff --git a/src/plugins/chart_expressions/expression_heatmap/public/services/palette_service.ts b/src/plugins/chart_expressions/expression_heatmap/public/services/palette_service.ts index 4e76e3149c7a6..7185422c79cad 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/services/palette_service.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/services/palette_service.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ +import type { PaletteRegistry } from '@kbn/coloring'; import { createGetterSetter } from '../../../../kibana_utils/public'; -import { PaletteRegistry, ChartsPluginSetup } from '../../../../charts/public'; +import { ChartsPluginSetup } from '../../../../charts/public'; export const [getPaletteService, setPaletteService] = createGetterSetter('palette'); diff --git a/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts index 894be5c4e6516..deb5f5e027abf 100644 --- a/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, ExpressionFunctionDefinition, @@ -13,7 +14,7 @@ import { Style, } from '../../../../expressions'; import { ExpressionValueVisDimension } from '../../../../visualizations/common'; -import { ColorMode, CustomPaletteState, PaletteOutput } from '../../../../charts/common'; +import { ColorMode, CustomPaletteState } from '../../../../charts/common'; import { VisParams, visType, LabelPositionType } from './expression_renderers'; import { EXPRESSION_METRIC_NAME } from '../constants'; diff --git a/src/plugins/chart_expressions/expression_metric/public/services/palette_service.ts b/src/plugins/chart_expressions/expression_metric/public/services/palette_service.ts index cfcf2a818c5bc..d18db6340fd45 100644 --- a/src/plugins/chart_expressions/expression_metric/public/services/palette_service.ts +++ b/src/plugins/chart_expressions/expression_metric/public/services/palette_service.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import type { PaletteRegistry } from '@kbn/coloring'; import { createGetterSetter } from '../../../../kibana_utils/public'; -import { PaletteRegistry } from '../../../../charts/public'; export const [getPaletteService, setPaletteService] = createGetterSetter('palette'); diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_renderers.ts index c6f29ef90c8e9..7ac7e9deedc20 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_renderers.ts @@ -7,10 +7,10 @@ */ import { Position } from '@elastic/charts'; +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, DatatableColumn } from '../../../../expressions/common'; import { SerializedFieldFormat } from '../../../../field_formats/common'; import { ExpressionValueVisDimension } from '../../../../visualizations/common'; -import { PaletteOutput } from '../../../../charts/common'; import { ChartTypes, ExpressionValuePartitionLabels } from './expression_functions'; export enum EmptySizeRatios { diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/palettes.ts b/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/palettes.ts index 5637acfdbee10..1c7d60923118c 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/palettes.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/palettes.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PaletteDefinition, SeriesLayer } from '../../../../charts/public'; +import type { PaletteDefinition, SeriesLayer } from '@kbn/coloring'; export const getPaletteRegistry = () => { const colors = [ diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx index c843bf189d77f..e8ab85f2877ff 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx @@ -20,7 +20,8 @@ import { SeriesIdentifier, } from '@elastic/charts'; import { useEuiTheme } from '@elastic/eui'; -import { LegendToggle, ChartsPluginSetup, PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry } from '@kbn/coloring'; +import { LegendToggle, ChartsPluginSetup } from '../../../../charts/public'; import type { PersistedState } from '../../../../visualizations/public'; import { getColumnByAccessor } from '../../../../visualizations/common/utils'; import { diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts index efeb1f038232d..d951d962d67f2 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PaletteDefinition, PaletteOutput } from '../../../../../charts/public'; +import type { PaletteOutput, PaletteDefinition } from '@kbn/coloring'; import { chartPluginMock } from '../../../../../charts/public/mocks'; import { Datatable } from '../../../../../expressions'; import { byDataColorPaletteMap } from './get_color'; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.ts index 183bf91e59740..f6d88d1fe802e 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.ts @@ -7,14 +7,9 @@ */ import { ShapeTreeNode } from '@elastic/charts'; import { isEqual } from 'lodash'; +import type { PaletteRegistry, SeriesLayer, PaletteOutput, PaletteDefinition } from '@kbn/coloring'; import type { FieldFormatsStart } from '../../../../../field_formats/public'; -import { - SeriesLayer, - PaletteRegistry, - lightenColor, - PaletteDefinition, - PaletteOutput, -} from '../../../../../charts/public'; +import { lightenColor } from '../../../../../charts/public'; import type { Datatable, DatatableRow } from '../../../../../expressions/public'; import { BucketColumns, ChartTypes, PartitionVisParams } from '../../../common/types'; import { DistinctSeries, getDistinctSeries } from '../get_distinct_series'; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.test.ts index c07bbf3ec6e16..0cc0fea93e6fe 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import { ShapeTreeNode } from '@elastic/charts'; -import { PaletteDefinition, SeriesLayer } from '../../../../../charts/public'; +import type { PaletteDefinition, SeriesLayer } from '@kbn/coloring'; import { dataPluginMock } from '../../../../../data/public/mocks'; import type { DataPublicPluginStart } from '../../../../../data/public'; import { getColor } from './get_color'; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.ts index 9f27ff628cf97..8280e7bd2a896 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_layers.ts @@ -7,9 +7,9 @@ */ import { Datum, PartitionLayer } from '@elastic/charts'; +import type { PaletteRegistry } from '@kbn/coloring'; import { FieldFormat } from '../../../../../field_formats/common'; import type { FieldFormatsStart } from '../../../../../field_formats/public'; -import { PaletteRegistry } from '../../../../../charts/public'; import type { Datatable, DatatableRow } from '../../../../../expressions/public'; import { BucketColumns, ChartTypes, PartitionVisParams } from '../../../common/types'; import { sortPredicateByType } from './sort_predicate'; diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts index 7463b6735bfe3..01c29ccc0e77d 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts @@ -7,7 +7,7 @@ */ import { $Values } from '@kbn/utility-types'; -import { PaletteOutput } from '../../../../charts/common'; +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, ExpressionFunctionDefinition, diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/__mocks__/palettes.ts b/src/plugins/chart_expressions/expression_tagcloud/public/__mocks__/palettes.ts index 7ca00b58f5624..0382a98bb76ec 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/__mocks__/palettes.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/public/__mocks__/palettes.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PaletteDefinition, SeriesLayer } from '../../../../charts/public'; +import type { PaletteDefinition, SeriesLayer } from '@kbn/coloring'; import { random } from 'lodash'; export const getPaletteRegistry = () => { diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx index 4c65c5837868d..5860c209f8be8 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { throttle } from 'lodash'; import { EuiIconTip, EuiResizeObserver } from '@elastic/eui'; import { Chart, Settings, Wordcloud, RenderChangeListener } from '@elastic/charts'; -import type { PaletteRegistry, PaletteOutput } from '../../../../charts/public'; +import type { PaletteRegistry, PaletteOutput } from '@kbn/coloring'; import { IInterpreterRenderHandlers } from '../../../../expressions/public'; import { getFormatService } from '../format_service'; import { diff --git a/src/plugins/chart_expressions/expression_xy/common/__mocks__/index.ts b/src/plugins/chart_expressions/expression_xy/common/__mocks__/index.ts index 4bafffc065835..f09ad04e77ddb 100644 --- a/src/plugins/chart_expressions/expression_xy/common/__mocks__/index.ts +++ b/src/plugins/chart_expressions/expression_xy/common/__mocks__/index.ts @@ -7,7 +7,7 @@ */ import { Position } from '@elastic/charts'; -import { PaletteOutput } from 'src/plugins/charts/common'; +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, DatatableRow } from 'src/plugins/expressions'; import { LayerTypes } from '../constants'; import { DataLayerConfigResult, LensMultiTable, XYArgs } from '../types'; diff --git a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts index 98889da771c04..044e75f95fc57 100644 --- a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts @@ -8,8 +8,8 @@ import { HorizontalAlignment, Position, VerticalAlignment } from '@elastic/charts'; import { $Values } from '@kbn/utility-types'; +import type { PaletteOutput } from '@kbn/coloring'; import { Datatable } from '../../../../expressions'; -import { PaletteOutput } from '../../../../charts/common'; import { EventAnnotationOutput } from '../../../../event_annotation/common'; import { AxisExtentModes, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index d69e8e8b645fa..eace75970c67a 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -38,6 +38,7 @@ import { } from '@elastic/charts'; import { IconType } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { PaletteRegistry, SeriesLayer } from '@kbn/coloring'; import type { Datatable, DatatableRow, DatatableColumn } from '../../../../expressions/public'; import { RenderMode } from '../../../../expressions/common'; import { FieldFormat } from '../../../../field_formats/common'; @@ -49,8 +50,6 @@ import { EventAnnotationServiceType } from '../../../../event_annotation/public' import { ChartsPluginSetup, ChartsPluginStart, - PaletteRegistry, - SeriesLayer, useActiveCursor, } from '../../../../../plugins/charts/public'; import { MULTILAYER_TIME_AXIS_STYLE } from '../../../../../plugins/charts/common'; diff --git a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx index 5e4921e85af62..170f4fb9bb87b 100644 --- a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx @@ -11,7 +11,8 @@ import { I18nProvider } from '@kbn/i18n-react'; import { ThemeServiceStart } from 'kibana/public'; import React from 'react'; import ReactDOM from 'react-dom'; -import type { ChartsPluginStart, PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry } from '@kbn/coloring'; +import type { ChartsPluginStart } from '../../../../charts/public'; import { EventAnnotationServiceType } from '../../../../event_annotation/public'; import { ExpressionRenderDefinition } from '../../../../expressions'; import { FormatFactory } from '../../../../field_formats/common'; diff --git a/src/plugins/controls/public/services/kibana/options_list.ts b/src/plugins/controls/public/services/kibana/options_list.ts index eb805ec4dbe02..a731b0acca62b 100644 --- a/src/plugins/controls/public/services/kibana/options_list.ts +++ b/src/plugins/controls/public/services/kibana/options_list.ts @@ -7,7 +7,7 @@ */ import { memoize } from 'lodash'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { buildEsQuery } from '@kbn/es-query'; import { TimeRange } from '../../../../data/public'; diff --git a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.test.ts b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.test.ts index 6e1a6ccf1c86e..9a2afecf0aa96 100644 --- a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.test.ts +++ b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.test.ts @@ -473,6 +473,113 @@ describe('dashboard', () => { }); }); + describe('7.10.0 - hidden panel titles', () => { + const migration = migrations['7.17.3']; + const doc: DashboardDoc730ToLatest = { + attributes: { + description: '', + kibanaSavedObjectMeta: { + searchSourceJSON: '', + }, + optionsJSON: '', + panelsJSON: `[ + {"version":"7.9.3","gridData":{"h":15,"i":"ad30af17-3897-4988-8dd9-1d4ccec60324","w":24,"x":0,"y":0},"panelIndex":"ad30af17-3897-4988-8dd9-1d4ccec60324","embeddableConfig":{"title":"Custom title"},"panelRefName":"panel_0"}, + {"version":"7.9.3","gridData":{"h":15,"i":"1132db5f-6fe9-4762-8199-3017bb6ed936","w":24,"x":24,"y":0},"panelIndex":"1132db5f-6fe9-4762-8199-3017bb6ed936","embeddableConfig":{"title":""},"panelRefName":"panel_1"}, + {"version":"7.9.3","gridData":{"h":15,"i":"9f0cc291-de38-42f4-b565-e13678cb5a88","w":24,"x":0,"y":15},"panelIndex":"9f0cc291-de38-42f4-b565-e13678cb5a88","embeddableConfig":{"title":""},"panelRefName":"panel_2"}, + {"version":"7.9.3","gridData":{"h":15,"i":"94b09a97-8775-4886-be22-c1ad53a7e361","w":24,"x":24,"y":15},"panelIndex":"94b09a97-8775-4886-be22-c1ad53a7e361","embeddableConfig":{},"panelRefName":"panel_3"} + ]`, + timeRestore: false, + title: 'Dashboard with blank titles', + version: 1, + }, + id: '376e6260-1f5e-11eb-91aa-7b6d5f8a61d6', + references: [], + type: 'dashboard', + }; + + test('all panels with explicitly set titles are left alone', () => { + const newDoc = migration(doc, contextMock); + const newPanels = JSON.parse(newDoc.attributes.panelsJSON); + expect(newPanels[0]).toMatchInlineSnapshot(` + Object { + "embeddableConfig": Object {}, + "gridData": Object { + "h": 15, + "i": "ad30af17-3897-4988-8dd9-1d4ccec60324", + "w": 24, + "x": 0, + "y": 0, + }, + "panelIndex": "ad30af17-3897-4988-8dd9-1d4ccec60324", + "panelRefName": "panel_0", + "title": "Custom title", + "version": "7.9.3", + } + `); + }); + + test('all panels with blank string titles are set to hidden', () => { + const newDoc = migration(doc, contextMock); + const newPanels = JSON.parse(newDoc.attributes.panelsJSON); + expect(newPanels[1]).toMatchInlineSnapshot(` + Object { + "embeddableConfig": Object { + "hidePanelTitles": true, + }, + "gridData": Object { + "h": 15, + "i": "1132db5f-6fe9-4762-8199-3017bb6ed936", + "w": 24, + "x": 24, + "y": 0, + }, + "panelIndex": "1132db5f-6fe9-4762-8199-3017bb6ed936", + "panelRefName": "panel_1", + "title": "", + "version": "7.9.3", + } + `); + expect(newPanels[2]).toMatchInlineSnapshot(` + Object { + "embeddableConfig": Object { + "hidePanelTitles": true, + }, + "gridData": Object { + "h": 15, + "i": "9f0cc291-de38-42f4-b565-e13678cb5a88", + "w": 24, + "x": 0, + "y": 15, + }, + "panelIndex": "9f0cc291-de38-42f4-b565-e13678cb5a88", + "panelRefName": "panel_2", + "title": "", + "version": "7.9.3", + } + `); + }); + + test('all panels with undefined titles are left alone', () => { + const newDoc = migration(doc, contextMock); + const newPanels = JSON.parse(newDoc.attributes.panelsJSON); + expect(newPanels[3]).toMatchInlineSnapshot(` + Object { + "embeddableConfig": Object {}, + "gridData": Object { + "h": 15, + "i": "94b09a97-8775-4886-be22-c1ad53a7e361", + "w": 24, + "x": 24, + "y": 15, + }, + "panelIndex": "94b09a97-8775-4886-be22-c1ad53a7e361", + "panelRefName": "panel_3", + "version": "7.9.3", + } + `); + }); + }); + describe('7.11.0 - embeddable persistable state extraction', () => { const migration = migrations['7.11.0']; const doc: DashboardDoc730ToLatest = { diff --git a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts index bd3051fc5a257..d50c199c7f0d4 100644 --- a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts +++ b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts @@ -164,6 +164,56 @@ type ValueOrReferenceInput = SavedObjectEmbeddableInput & { savedVis?: Serializable; }; +/** + * Before 7.10, hidden panel titles were stored as a blank string on the title attribute. In 7.10, this was replaced + * with a usage of the existing hidePanelTitles key. Even though blank string titles still technically work + * in versions > 7.10, they are less explicit than using the hidePanelTitles key. This migration transforms all + * blank string titled panels to panels with the titles explicitly hidden. + */ +export const migrateExplicitlyHiddenTitles: SavedObjectMigrationFn = (doc) => { + const { attributes } = doc; + + // Skip if panelsJSON is missing + if (typeof attributes?.panelsJSON !== 'string') return doc; + + try { + const panels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[]; + // Same here, prevent failing saved object import if ever panels aren't an array. + if (!Array.isArray(panels)) return doc; + + const newPanels: SavedDashboardPanel[] = []; + panels.forEach((panel) => { + // Convert each panel into the dashboard panel state + const originalPanelState = + convertSavedDashboardPanelToPanelState(panel); + newPanels.push( + convertPanelStateToSavedDashboardPanel( + { + ...originalPanelState, + explicitInput: { + ...originalPanelState.explicitInput, + ...(originalPanelState.explicitInput.title === '' && + !originalPanelState.explicitInput.hidePanelTitles + ? { hidePanelTitles: true } + : {}), + }, + }, + panel.version + ) + ); + }); + return { + ...doc, + attributes: { + ...attributes, + panelsJSON: JSON.stringify(newPanels), + }, + }; + } catch { + return doc; + } +}; + // Runs the embeddable migrations on each panel const migrateByValuePanels = (migrate: MigrateFunction, version: string): SavedObjectMigrationFn => @@ -258,14 +308,8 @@ export const createDashboardSavedObjectTypeMigrations = ( '7.3.0': flow(migrations730), '7.9.3': flow(migrateMatchAllQuery), '7.11.0': flow(createExtractPanelReferencesMigration(deps)), - - /** - * Any dashboard saved object migrations that come after this point will have to be wary of - * potentially overwriting embeddable migrations. An example of how to mitigate this follows: - */ - // '7.x': flow(yourNewMigrationFunction, embeddableMigrations['7.x'] ?? identity), - '7.14.0': flow(replaceIndexPatternReference), + '7.17.3': flow(migrateExplicitlyHiddenTitles), }; return mergeMigrationFunctionMaps(dashboardMigrations, embeddableMigrations); diff --git a/src/plugins/data/common/query/timefilter/get_time.ts b/src/plugins/data/common/query/timefilter/get_time.ts index fd21b2251ea3a..287b0f3de21e7 100644 --- a/src/plugins/data/common/query/timefilter/get_time.ts +++ b/src/plugins/data/common/query/timefilter/get_time.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { omitBy } from 'lodash'; import { buildRangeFilter } from '@kbn/es-query'; import type { Moment } from 'moment'; diff --git a/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts index 4b3ec90bb2cc2..9b2ed50fb2459 100644 --- a/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts +++ b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts @@ -7,7 +7,7 @@ */ import moment from 'moment'; -import dateMath, { Unit } from '@elastic/datemath'; +import dateMath, { Unit } from '@kbn/datemath'; import { parseEsInterval } from '../../../utils'; diff --git a/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts index 12c6d39ad905a..f8a89a8e33e46 100644 --- a/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts +++ b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts @@ -9,7 +9,7 @@ import { Assign } from 'utility-types'; import { isString, isObject as isObjectLodash, isPlainObject, sortBy } from 'lodash'; import moment, { Moment } from 'moment'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { parseInterval, splitStringInterval } from '../../../utils'; import { TimeRangeBounds } from '../../../../../query'; import { calcAutoIntervalLessThan, calcAutoIntervalNear } from './calc_auto_interval'; diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts index 3ed68d876c664..ea259fbf6239d 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; export class InvalidEsCalendarIntervalError extends Error { diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts index ff895a976ac64..0e5fc49fb1d29 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { leastCommonMultiple } from './least_common_multiple'; import { parseEsInterval } from './parse_es_interval'; diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts index b723c3f45c5a6..237a509277336 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath, { Unit } from '@elastic/datemath'; +import dateMath, { Unit } from '@kbn/datemath'; import { InvalidEsCalendarIntervalError } from './invalid_es_calendar_interval_error'; import { InvalidEsIntervalFormatError } from './invalid_es_interval_format_error'; diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts index e6ce43526306d..113abfb056f70 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts @@ -8,7 +8,7 @@ import { find } from 'lodash'; import moment from 'moment'; -import dateMath, { Unit } from '@elastic/datemath'; +import dateMath, { Unit } from '@kbn/datemath'; // Assume interval is in the form (value)(unit), such as "1h" const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + dateMath.units.join('|') + ')$'); diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts index 03b6bcf83c642..d147caf92711f 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { TimeRange } from '../../../../../common'; export function toAbsoluteDates(range: TimeRange) { diff --git a/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts index f88fd3b9a0157..0caf2d4ced530 100644 --- a/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { buildQueryFromFilters } from '@kbn/es-query'; import { memoize } from 'lodash'; import { CoreSetup } from 'src/core/public'; diff --git a/src/plugins/data/public/query/timefilter/lib/validate_timerange.ts b/src/plugins/data/public/query/timefilter/lib/validate_timerange.ts index 12271f8388ca5..e9eb97d004c91 100644 --- a/src/plugins/data/public/query/timefilter/lib/validate_timerange.ts +++ b/src/plugins/data/public/query/timefilter/lib/validate_timerange.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { TimeRange } from '../../../../common'; export function validateTimeRange(time?: TimeRange): boolean { diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx index 55b9876ac54ad..1ba108492e7f9 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx @@ -19,7 +19,7 @@ import { } from './field_editor.helpers'; describe('', () => { - const { server, httpRequestsMockHelpers } = setupEnvironment(); + const { httpRequestsMockHelpers } = setupEnvironment(); let testBed: FieldEditorTestBed; let onChange: jest.Mock = jest.fn(); @@ -70,7 +70,6 @@ describe('', () => { afterAll(() => { jest.useRealTimers(); - server.restore(); }); beforeEach(async () => { diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts index 1730593dbda20..a3ae323a1c3db 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts @@ -15,7 +15,7 @@ import { setup } from './field_editor_flyout_content.helpers'; import { mockDocuments, createPreviewError } from './helpers/mocks'; describe('', () => { - const { server, httpRequestsMockHelpers } = setupEnvironment(); + const { httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { jest.useFakeTimers(); @@ -23,7 +23,6 @@ describe('', () => { afterAll(() => { jest.useRealTimers(); - server.restore(); }); beforeEach(async () => { diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts index c3175d7097a36..fc680213c1995 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts @@ -32,7 +32,6 @@ describe('Field editor Preview panel', () => { afterAll(() => { jest.useRealTimers(); - server.restore(); }); let testBed: FieldEditorFlyoutContentTestBed; @@ -55,9 +54,6 @@ describe('Field editor Preview panel', () => { ]; beforeEach(async () => { - server.respondImmediately = true; - server.autoRespond = true; - httpRequestsMockHelpers.setFieldPreviewResponse({ values: ['mockedScriptValue'] }); setIndexPatternFields(indexPatternFields); setSearchResponse(mockDocuments); @@ -278,23 +274,18 @@ describe('Field editor Preview panel', () => { httpRequestsMockHelpers.setFieldPreviewResponse({ values: [scriptEmitResponse] }); const { - actions: { - toggleFormRow, - fields, - waitForUpdates, - getLatestPreviewHttpRequest, - getRenderedFieldsPreview, - }, + actions: { toggleFormRow, fields, waitForUpdates, getRenderedFieldsPreview }, } = testBed; await toggleFormRow('value'); await fields.updateName('myRuntimeField'); await fields.updateScript('echo("hello")'); await waitForUpdates(); // Run validations - const request = getLatestPreviewHttpRequest(server); // Make sure the payload sent is correct - expect(request.requestBody).toEqual({ + const firstCall = server.post.mock.calls[0] as Array<{ body: any }>; + const payload = JSON.parse(firstCall[1]?.body); + expect(payload).toEqual({ context: 'keyword_field', document: { description: 'First doc - description', @@ -373,10 +364,8 @@ describe('Field editor Preview panel', () => { test('should display an updating indicator while fetching the docs and the preview', async () => { // We want to test if the loading indicator is in the DOM, for that we don't want the server to // respond immediately. We'll manualy send the response. - server.respondImmediately = false; - server.autoRespond = false; - httpRequestsMockHelpers.setFieldPreviewResponse({ values: ['ok'] }); + httpRequestsMockHelpers.setFieldPreviewResponse({ values: ['ok'] }, undefined, true); const { exists, @@ -394,17 +383,14 @@ describe('Field editor Preview panel', () => { await fields.updateScript('echo("hello")'); expect(exists('isUpdatingIndicator')).toBe(true); // indicator while getting preview - server.respond(); await waitForUpdates(); expect(exists('isUpdatingIndicator')).toBe(false); }); test('should not display the updating indicator when neither the type nor the script has changed', async () => { - httpRequestsMockHelpers.setFieldPreviewResponse({ values: ['ok'] }); + httpRequestsMockHelpers.setFieldPreviewResponse({ values: ['ok'] }, undefined, true); // We want to test if the loading indicator is in the DOM, for that we need to manually // send the response from the server - server.respondImmediately = false; - server.autoRespond = false; const { exists, @@ -417,7 +403,6 @@ describe('Field editor Preview panel', () => { await fields.updateScript('echo("hello")'); expect(exists('isUpdatingIndicator')).toBe(true); - server.respond(); await waitForDocumentsAndPreviewUpdate(); expect(exists('isUpdatingIndicator')).toBe(false); diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/http_requests.ts b/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/http_requests.ts index 4b03db247bad1..4c7a5832f037c 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/http_requests.ts +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/http_requests.ts @@ -6,42 +6,37 @@ * Side Public License, v 1. */ -import sinon, { SinonFakeServer } from 'sinon'; -import { API_BASE_PATH } from '../../../common/constants'; +import { httpServiceMock } from '../../../../../../src/core/public/mocks'; type HttpResponse = Record | any[]; -// Register helpers to mock HTTP Requests -const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { - const setFieldPreviewResponse = (response?: HttpResponse, error?: any) => { - const status = error ? error.body.status || 400 : 200; - const body = error ? JSON.stringify(error.body) : JSON.stringify(response); - - server.respondWith('POST', `${API_BASE_PATH}/field_preview`, [ - status, - { 'Content-Type': 'application/json' }, - body, - ]); +const registerHttpRequestMockHelpers = ( + httpSetup: ReturnType +) => { + const setFieldPreviewResponse = (response?: HttpResponse, error?: any, delayResponse = false) => { + const body = error ? JSON.stringify(error.body) : response; + + httpSetup.post.mockImplementation(() => { + if (delayResponse) { + return new Promise((resolve) => { + setTimeout(() => resolve({ data: body }), 1000); + }); + } else { + return Promise.resolve({ data: body }); + } + }); }; - return { setFieldPreviewResponse, }; }; export const init = () => { - const server = sinon.fakeServer.create(); - server.respondImmediately = true; - - // Define default response for unhandled requests. - // We make requests to APIs which don't impact the component under test, e.g. UI metric telemetry, - // and we can mock them all with a 200 instead of mocking each one individually. - server.respondWith([200, {}, 'DefaultSinonMockServerResponse']); - - const httpRequestsMockHelpers = registerHttpRequestMockHelpers(server); + const httpSetup = httpServiceMock.createSetupContract(); + const httpRequestsMockHelpers = registerHttpRequestMockHelpers(httpSetup); return { - server, + httpSetup, httpRequestsMockHelpers, }; }; diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/setup_environment.tsx b/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/setup_environment.tsx index 722b1b1ec2cea..02d4f713871a3 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/setup_environment.tsx +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/helpers/setup_environment.tsx @@ -10,8 +10,6 @@ import './jest.mocks'; import React, { FunctionComponent } from 'react'; -import axios from 'axios'; -import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import { merge } from 'lodash'; import { notificationServiceMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; @@ -23,7 +21,6 @@ import { init as initHttpRequests } from './http_requests'; import { fieldFormatsMock as fieldFormats } from '../../../../field_formats/common/mocks'; import { FieldFormat } from '../../../../field_formats/common'; -const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); const dataStart = dataPluginMock.createStartContract(); const { search } = dataStart; @@ -61,12 +58,11 @@ search.search = spySearchQuery; let apiService: ApiService; export const setupEnvironment = () => { - // @ts-expect-error Axios does not fullfill HttpSetupn from core but enough for our tests - apiService = initApi(mockHttpClient); - const { server, httpRequestsMockHelpers } = initHttpRequests(); + const { httpSetup, httpRequestsMockHelpers } = initHttpRequests(); + apiService = initApi(httpSetup); return { - server, + server: httpSetup, httpRequestsMockHelpers, }; }; diff --git a/src/plugins/discover/public/application/main/components/chart/histogram.tsx b/src/plugins/discover/public/application/main/components/chart/histogram.tsx index 22eff35be2325..2a71207e82835 100644 --- a/src/plugins/discover/public/application/main/components/chart/histogram.tsx +++ b/src/plugins/discover/public/application/main/components/chart/histogram.tsx @@ -18,7 +18,7 @@ import { EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { Axis, BrushEndListener, diff --git a/src/plugins/discover/public/application/main/components/chart/point_series.test.ts b/src/plugins/discover/public/application/main/components/chart/point_series.test.ts index 37fa894f7f671..3497bc54b4a35 100644 --- a/src/plugins/discover/public/application/main/components/chart/point_series.test.ts +++ b/src/plugins/discover/public/application/main/components/chart/point_series.test.ts @@ -8,7 +8,7 @@ import { buildPointSeriesData } from './point_series'; import moment from 'moment'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; describe('buildPointSeriesData', () => { test('with valid data', () => { diff --git a/src/plugins/discover/public/application/main/components/chart/point_series.ts b/src/plugins/discover/public/application/main/components/chart/point_series.ts index b8cdf75d5fd36..88b5c444f4beb 100644 --- a/src/plugins/discover/public/application/main/components/chart/point_series.ts +++ b/src/plugins/discover/public/application/main/components/chart/point_series.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import { Duration, Moment } from 'moment'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { SerializedFieldFormat } from '../../../../../../field_formats/common'; export interface Column { diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 8be5e2b7ce4be..b6ee4133f1f75 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -25,7 +25,7 @@ import { useDiscoverServices } from '../../../../utils/use_discover_services'; import { DiscoverNoResults } from '../no_results'; import { LoadingSpinner } from '../loading_spinner/loading_spinner'; import { generateFilters } from '../../../../../../data/public'; -import { DataViewField } from '../../../../../../data_views/public'; +import { DataView, DataViewField, DataViewType } from '../../../../../../data_views/public'; import { DiscoverSidebarResponsive } from '../sidebar'; import { DiscoverLayoutProps } from './types'; import { SEARCH_FIELDS_FROM_SOURCE, SHOW_FIELD_STATISTICS } from '../../../../../common'; @@ -48,7 +48,7 @@ import { import { FieldStatisticsTable } from '../field_stats_table'; import { VIEW_MODE } from '../../../../components/view_mode_toggle'; import { DOCUMENTS_VIEW_CLICK, FIELD_STATISTICS_VIEW_CLICK } from '../field_stats_table/constants'; -import { DataViewType, DataView } from '../../../../../../data_views/public'; +import { hasActiveFilter } from './utils'; /** * Local storage key for sidebar persistence state @@ -234,7 +234,16 @@ export function DiscoverLayout({ history={history} />

- {savedSearch.title} + {savedSearch.title + ? i18n.translate('discover.pageTitleWithSavedSearch', { + defaultMessage: 'Discover - {savedSearchTitle}', + values: { + savedSearchTitle: savedSearch.title, + }, + }) + : i18n.translate('discover.pageTitleWithoutSavedSearch', { + defaultMessage: 'Discover - Search not yet saved', + })}

@@ -293,9 +302,7 @@ export function DiscoverLayout({ data={data} error={dataState.error} hasQuery={!!state.query?.query} - hasFilters={ - state.filters && state.filters.filter((f) => !f.meta.disabled).length > 0 - } + hasFilters={hasActiveFilter(state.filters)} onDisableFilters={onDisableFilters} /> )} diff --git a/src/plugins/discover/public/application/main/components/layout/utils.test.ts b/src/plugins/discover/public/application/main/components/layout/utils.test.ts new file mode 100644 index 0000000000000..2201ff3dfe476 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/layout/utils.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { Filter } from '@kbn/es-query'; +import { hasActiveFilter } from './utils'; + +const testFilter: Filter = { + meta: { + alias: null, + disabled: false, + negate: false, + }, + query: { query: 'hi' }, +}; +const testFilterDisabled: Filter = { + meta: { + alias: null, + disabled: true, + negate: false, + }, + query: { query: 'hi' }, +}; + +const testFilterBroken = {} as Filter; + +describe('hasActiveFilter', () => { + test('only active filters', () => { + const filters = [testFilter]; + const result = hasActiveFilter(filters); + expect(result).toBe(true); + }); + test('only disabled filters', () => { + const filters = [testFilterDisabled]; + const result = hasActiveFilter(filters); + expect(result).toBe(false); + }); + test('disabled and active filters', () => { + const filters = [testFilter, testFilterDisabled]; + const result = hasActiveFilter(filters); + expect(result).toBe(true); + }); + test('broken filter - edge case', () => { + const filters = [testFilterBroken]; + const result = hasActiveFilter(filters); + expect(result).toBe(true); + }); +}); diff --git a/src/plugins/discover/public/application/main/components/layout/utils.ts b/src/plugins/discover/public/application/main/components/layout/utils.ts new file mode 100644 index 0000000000000..bcf9dbb6178ec --- /dev/null +++ b/src/plugins/discover/public/application/main/components/layout/utils.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { Filter } from '@kbn/es-query'; + +/** + * Returns if true there's at least 1 active filter + */ +export function hasActiveFilter(filters: Filter[] | undefined) { + return filters && filters.filter((f) => !f.meta?.disabled).length > 0; +} diff --git a/src/plugins/discover/public/application/main/utils/get_dimensions.ts b/src/plugins/discover/public/application/main/utils/get_dimensions.ts index 1c8bc70bb17e2..c9a2a198d1f7e 100644 --- a/src/plugins/discover/public/application/main/utils/get_dimensions.ts +++ b/src/plugins/discover/public/application/main/utils/get_dimensions.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { DataPublicPluginStart, search, IAggConfigs } from '../../../../../data/public'; import { Dimensions, HistogramParamsBounds } from '../components/chart/point_series'; diff --git a/src/plugins/discover/public/application/main/utils/validate_time_range.ts b/src/plugins/discover/public/application/main/utils/validate_time_range.ts index e506fe6fdb898..7744a10f3e8ca 100644 --- a/src/plugins/discover/public/application/main/utils/validate_time_range.ts +++ b/src/plugins/discover/public/application/main/utils/validate_time_range.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; import { ToastsStart } from 'kibana/public'; diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table_cell_actions.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table_cell_actions.tsx index 9a50811ff0d8c..d5dc166e639f3 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table_cell_actions.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table_cell_actions.tsx @@ -147,7 +147,8 @@ export const TableActions = ({ toolTipContent: filtersExistsToolTip, icon: 'filter', disabled: filtersExistsDisabled, - onClick: onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '-')), + 'data-test-subj': `addExistsFilterButton-${field}`, + onClick: onClickAction(onFilter.bind({}, '_exists_', field, '+')), }, { name: toggleColumnsLabel, 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 7ad6cf697d10b..1abb7409709e0 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -10,11 +10,6 @@ import { MakeSchemaFrom } from 'src/plugins/usage_collection/server'; import { UsageStats } from './types'; export const stackManagementSchema: MakeSchemaFrom = { - // sensitive - 'timelion:quandl.key': { - type: 'keyword', - _meta: { description: 'Default value of the setting was changed.' }, - }, 'securitySolution:defaultIndex': { type: 'keyword', _meta: { description: 'Default value of the setting was changed.' }, @@ -35,10 +30,6 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'keyword', _meta: { description: 'Default value of the setting was changed.' }, }, - 'timelion:graphite.url': { - type: 'keyword', - _meta: { description: 'Default value of the setting changed.' }, - }, 'xpackDashboardMode:roles': { type: 'keyword', _meta: { description: 'Default value of the setting was changed.' }, 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 86ca596925f76..b9d50f888fa93 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -10,13 +10,11 @@ export interface UsageStats { /** * sensitive settings */ - 'timelion:quandl.key': string; 'securitySolution:defaultIndex': string; 'securitySolution:defaultThreatIndex': string; 'securitySolution:newsFeedUrl': string; 'xpackReporting:customPdfLogo': string; 'notifications:banner': string; - 'timelion:graphite.url': string; 'xpackDashboardMode:roles': string; 'securitySolution:ipReputationLinks': string; 'banners:textContent': string; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 76079970f26bc..c6a237ee2b09c 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7300,12 +7300,6 @@ }, "stack_management": { "properties": { - "timelion:quandl.key": { - "type": "keyword", - "_meta": { - "description": "Default value of the setting was changed." - } - }, "securitySolution:defaultIndex": { "type": "keyword", "_meta": { @@ -7336,12 +7330,6 @@ "description": "Default value of the setting was changed." } }, - "timelion:graphite.url": { - "type": "keyword", - "_meta": { - "description": "Default value of the setting changed." - } - }, "xpackDashboardMode:roles": { "type": "keyword", "_meta": { diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/lib/filter_editor_utils.ts b/src/plugins/unified_search/public/filter_bar/filter_editor/lib/filter_editor_utils.ts index 3b8fb867c361b..eb67d630f2393 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/lib/filter_editor_utils.ts +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/lib/filter_editor_utils.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { Filter, FieldFilter } from '@kbn/es-query'; import { ES_FIELD_TYPES } from '@kbn/field-types'; import isSemverValid from 'semver/functions/valid'; diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index ddba035b91fdd..1589c9c86f1df 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import classNames from 'classnames'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import deepEqual from 'fast-deep-equal'; diff --git a/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx b/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx index 22907ff16e24d..f060cfb311023 100644 --- a/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx @@ -21,7 +21,7 @@ import { EuiText, EuiFormRow, } from '@elastic/eui'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { isEqual, omit } from 'lodash'; diff --git a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx index ee6ee405c479d..29d8924a25077 100644 --- a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import type { PaletteOutput, PaletteRegistry } from '@kbn/coloring'; import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; import { EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index a8324570a9259..9be0726ae9eb3 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -22,7 +22,7 @@ import { import { Position } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; - +import type { PaletteRegistry } from '@kbn/coloring'; import { BasicOptions, SwitchOption, @@ -33,7 +33,6 @@ import { } from '../../../../../vis_default_editor/public'; import { VisEditorOptionsProps } from '../../../../../visualizations/public'; import { TruncateLabelsOption } from './truncate_labels'; -import { PaletteRegistry } from '../../../../../charts/public'; import { DEFAULT_PERCENT_DECIMALS } from '../../../common'; import { PieTypeProps } from '../../types'; import { diff --git a/src/plugins/vis_types/pie/public/to_ast.ts b/src/plugins/vis_types/pie/public/to_ast.ts index 2dcc1d916a86e..37f01fcc59340 100644 --- a/src/plugins/vis_types/pie/public/to_ast.ts +++ b/src/plugins/vis_types/pie/public/to_ast.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ +import type { PaletteOutput } from '@kbn/coloring'; import { getVisSchemas, VisToExpressionAst, SchemaConfig } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; -import { PaletteOutput } from '../../../charts/common'; import { PIE_VIS_EXPRESSION_NAME, PARTITION_LABELS_FUNCTION, diff --git a/src/plugins/vis_types/tagcloud/public/components/tag_cloud_options.tsx b/src/plugins/vis_types/tagcloud/public/components/tag_cloud_options.tsx index ff5f1e6edd6f8..870a05bcb9277 100644 --- a/src/plugins/vis_types/tagcloud/public/components/tag_cloud_options.tsx +++ b/src/plugins/vis_types/tagcloud/public/components/tag_cloud_options.tsx @@ -9,7 +9,7 @@ import React, { useState, useEffect } from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry } from '@kbn/coloring'; import { VisEditorOptionsProps } from '../../../../visualizations/public'; import { SelectOption, SwitchOption, PalettePicker } from '../../../../vis_default_editor/public'; import { ValidatedDualRange } from '../../../../kibana_react/public'; diff --git a/src/plugins/vis_types/tagcloud/public/to_ast.ts b/src/plugins/vis_types/tagcloud/public/to_ast.ts index e9ef8f84ba55b..c66660e78a78a 100644 --- a/src/plugins/vis_types/tagcloud/public/to_ast.ts +++ b/src/plugins/vis_types/tagcloud/public/to_ast.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PaletteOutput } from 'src/plugins/charts/common'; +import type { PaletteOutput } from '@kbn/coloring'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, diff --git a/src/plugins/vis_types/tagcloud/public/types.ts b/src/plugins/vis_types/tagcloud/public/types.ts index 996555ae99f83..e3c5c057a3405 100644 --- a/src/plugins/vis_types/tagcloud/public/types.ts +++ b/src/plugins/vis_types/tagcloud/public/types.ts @@ -5,7 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { ChartsPluginSetup, PaletteOutput } from '../../../charts/public'; +import type { PaletteOutput } from '@kbn/coloring'; +import type { ChartsPluginSetup } from '../../../charts/public'; import { ExpressionValueVisDimension } from '../../../visualizations/public'; interface TagCloudCommonParams { diff --git a/src/plugins/vis_types/timelion/common/constants.ts b/src/plugins/vis_types/timelion/common/constants.ts index a97bdd855107c..a49154b662c34 100644 --- a/src/plugins/vis_types/timelion/common/constants.ts +++ b/src/plugins/vis_types/timelion/common/constants.ts @@ -13,6 +13,4 @@ export const UI_SETTINGS = { TARGET_BUCKETS: 'timelion:target_buckets', MAX_BUCKETS: 'timelion:max_buckets', MIN_INTERVAL: 'timelion:min_interval', - GRAPHITE_URL: 'timelion:graphite.url', - QUANDL_KEY: 'timelion:quandl.key', }; diff --git a/src/plugins/vis_types/timelion/server/index.ts b/src/plugins/vis_types/timelion/server/index.ts index 396ef8b61c7bc..4bf47dff7076d 100644 --- a/src/plugins/vis_types/timelion/server/index.ts +++ b/src/plugins/vis_types/timelion/server/index.ts @@ -12,6 +12,7 @@ import { TimelionPlugin } from './plugin'; export const config: PluginConfigDescriptor = { schema: configSchema, + deprecations: ({ unused }) => [unused('graphiteUrls', { level: 'warning' })], }; export const plugin = (initializerContext: PluginInitializerContext) => diff --git a/src/plugins/vis_types/timelion/server/lib/config_manager.ts b/src/plugins/vis_types/timelion/server/lib/config_manager.ts index f12f7fce0668a..3ab60b0afaaed 100644 --- a/src/plugins/vis_types/timelion/server/lib/config_manager.ts +++ b/src/plugins/vis_types/timelion/server/lib/config_manager.ts @@ -7,18 +7,11 @@ */ import { PluginInitializerContext } from 'kibana/server'; -import { TypeOf } from '@kbn/config-schema'; -import { configSchema } from '../../config'; export class ConfigManager { private esShardTimeout: number = 0; - private graphiteUrls: string[] = []; constructor(config: PluginInitializerContext['config']) { - config.create>().subscribe((configUpdate) => { - this.graphiteUrls = configUpdate.graphiteUrls || []; - }); - config.legacy.globalConfig$.subscribe((configUpdate) => { this.esShardTimeout = configUpdate.elasticsearch.shardTimeout.asMilliseconds(); }); @@ -27,8 +20,4 @@ export class ConfigManager { getEsShardTimeout() { return this.esShardTimeout; } - - getGraphiteUrls() { - return this.graphiteUrls; - } } diff --git a/src/plugins/vis_types/timelion/server/routes/run.ts b/src/plugins/vis_types/timelion/server/routes/run.ts index 325c675011d13..bf829fe708854 100644 --- a/src/plugins/vis_types/timelion/server/routes/run.ts +++ b/src/plugins/vis_types/timelion/server/routes/run.ts @@ -90,7 +90,6 @@ export function runRoute( getFunction, getIndexPatternsService: () => indexPatternsService, getStartServices: core.getStartServices, - allowedGraphiteUrls: configManager.getGraphiteUrls(), esShardTimeout: configManager.getEsShardTimeout(), }); try { diff --git a/src/plugins/vis_types/timelion/server/series_functions/fixtures/tl_config.js b/src/plugins/vis_types/timelion/server/series_functions/fixtures/tl_config.js index 1b378db4ab25a..f3eb378095fc7 100644 --- a/src/plugins/vis_types/timelion/server/series_functions/fixtures/tl_config.js +++ b/src/plugins/vis_types/timelion/server/series_functions/fixtures/tl_config.js @@ -21,7 +21,6 @@ export default function () { }, esShardTimeout: moment.duration(30000), - allowedGraphiteUrls: ['https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite'], }); tlConfig.time = { diff --git a/src/plugins/vis_types/timelion/server/series_functions/graphite.js b/src/plugins/vis_types/timelion/server/series_functions/graphite.js deleted file mode 100644 index 06203c52debff..0000000000000 --- a/src/plugins/vis_types/timelion/server/series_functions/graphite.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import _ from 'lodash'; -import fetch from 'node-fetch'; -import moment from 'moment'; -import Datasource from '../lib/classes/datasource'; - -export default new Datasource('graphite', { - args: [ - { - name: 'metric', // _test-data.users.*.data - types: ['string'], - help: i18n.translate('timelion.help.functions.graphite.args.metricHelpText', { - defaultMessage: 'Graphite metric to pull, e.g., {metricExample}', - values: { - metricExample: '_test-data.users.*.data', - }, - }), - }, - ], - help: i18n.translate('timelion.help.functions.graphiteHelpText', { - defaultMessage: `[experimental] Pull data from graphite. Configure your graphite server in Kibana's Advanced Settings`, - }), - fn: function graphite(args, tlConfig) { - const config = args.byName; - - const time = { - min: moment(tlConfig.time.from).format('HH:mm[_]YYYYMMDD'), - max: moment(tlConfig.time.to).format('HH:mm[_]YYYYMMDD'), - }; - const allowedUrls = tlConfig.allowedGraphiteUrls; - const configuredUrl = tlConfig.settings['timelion:graphite.url'] || allowedUrls[0]; - if (!allowedUrls.includes(configuredUrl)) { - throw new Error( - i18n.translate('timelion.help.functions.notAllowedGraphiteUrl', { - defaultMessage: `This graphite URL is not configured on the kibana.yml file. - Please configure your graphite server list in the kibana.yml file under 'timelion.graphiteUrls' and - select one from Kibana's Advanced Settings`, - }) - ); - } - - const URL = - configuredUrl + - '/render/' + - '?format=json' + - '&from=' + - time.min + - '&until=' + - time.max + - '&target=' + - config.metric; - - return fetch(URL) - .then(function (resp) { - return resp.json(); - }) - .then(function (resp) { - const list = _.map(resp, function (series) { - const data = _.map(series.datapoints, function (point) { - return [point[1] * 1000, point[0]]; - }); - return { - data: data, - type: 'series', - fit: 'nearest', // TODO make this customizable - label: series.target, - }; - }); - - return { - type: 'seriesList', - list: list, - }; - }) - .catch(function (e) { - throw e; - }); - }, -}); diff --git a/src/plugins/vis_types/timelion/server/series_functions/graphite.test.js b/src/plugins/vis_types/timelion/server/series_functions/graphite.test.js deleted file mode 100644 index db4fb35039324..0000000000000 --- a/src/plugins/vis_types/timelion/server/series_functions/graphite.test.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -const expect = require('chai').expect; - -import fn from './graphite'; - -jest.mock('node-fetch', () => () => { - return Promise.resolve({ - json: function () { - return [ - { - target: '__beer__', - datapoints: [ - [3, 1000], - [14, 2000], - [1.5, 3000], - [92.6535, 4000], - ], - }, - ]; - }, - }); -}); - -import invoke from './helpers/invoke_series_fn.js'; - -describe('graphite', function () { - it('should wrap the graphite response up in a seriesList', function () { - return invoke(fn, []).then(function (result) { - expect(result.output.list[0].data[0][1]).to.eql(3); - expect(result.output.list[0].data[1][1]).to.eql(14); - }); - }); - - it('should convert the seconds to milliseconds', function () { - return invoke(fn, []).then(function (result) { - expect(result.output.list[0].data[1][0]).to.eql(2000 * 1000); - }); - }); - - it('should set the label to that of the graphite target', function () { - return invoke(fn, []).then(function (result) { - expect(result.output.list[0].label).to.eql('__beer__'); - }); - }); -}); diff --git a/src/plugins/vis_types/timelion/server/series_functions/quandl.js b/src/plugins/vis_types/timelion/server/series_functions/quandl.js deleted file mode 100644 index 3c209879d7a4c..0000000000000 --- a/src/plugins/vis_types/timelion/server/series_functions/quandl.js +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import _ from 'lodash'; -import fetch from 'node-fetch'; -import moment from 'moment'; - -import Datasource from '../lib/classes/datasource'; - -export default new Datasource('quandl', { - dataSource: true, - args: [ - { - name: 'code', - types: ['string', 'null'], - help: i18n.translate('timelion.help.functions.quandl.args.codeHelpText', { - defaultMessage: 'The quandl code to plot. You can find these on quandl.com.', - }), - }, - { - name: 'position', - types: ['number', 'null'], - help: i18n.translate('timelion.help.functions.quandl.args.positionHelpText', { - defaultMessage: - 'Some quandl sources return multiple series, which one should I use? 1 based index.', - }), - }, - ], - help: i18n.translate('timelion.help.functions.quandlHelpText', { - defaultMessage: ` - [experimental] - Pull data from quandl.com using the quandl code. Set {quandlKeyField} to your free API key in Kibana's - Advanced Settings. The API has a really low rate limit without a key.`, - values: { - quandlKeyField: '"timelion:quandl.key"', - }, - }), - fn: function quandlFn(args, tlConfig) { - const intervalMap = { - '1d': 'daily', - '1w': 'weekly', - '1M': 'monthly', - '1y': 'annual', - }; - - const config = _.defaults(args.byName, { - code: 'WIKI/AAPL', - position: 1, - interval: intervalMap[tlConfig.time.interval], - apikey: tlConfig.settings['timelion:quandl.key'], - }); - - if (!config.interval) { - throw new Error( - i18n.translate('timelion.serverSideErrors.quandlFunction.unsupportedIntervalErrorMessage', { - defaultMessage: - 'quandl() unsupported interval: {interval}. quandl() supports: {intervals}', - values: { - interval: tlConfig.time.interval, - intervals: _.keys(intervalMap).join(', '), - }, - }) - ); - } - - const time = { - min: moment.utc(tlConfig.time.from).format('YYYY-MM-DD'), - max: moment.utc(tlConfig.time.to).format('YYYY-MM-DD'), - }; - - // POSITIONS - // 1. open - // 2. high - // 3. low - // 4. close - // 5. volume - - const URL = - 'https://www.quandl.com/api/v1/datasets/' + - config.code + - '.json' + - '?sort_order=asc' + - '&trim_start=' + - time.min + - '&trim_end=' + - time.max + - '&collapse=' + - config.interval + - '&auth_token=' + - config.apikey; - - return fetch(URL) - .then(function (resp) { - return resp.json(); - }) - .then(function (resp) { - const data = _.map(resp.data, function (bucket) { - return [moment(bucket[0]).valueOf(), bucket[config.position]]; - }); - - return { - type: 'seriesList', - list: [ - { - data: data, - type: 'series', - fit: 'nearest', - label: resp.name, - }, - ], - }; - }); - }, -}); diff --git a/src/plugins/vis_types/timelion/server/series_functions/quandl.test.js b/src/plugins/vis_types/timelion/server/series_functions/quandl.test.js deleted file mode 100644 index 152339c804cec..0000000000000 --- a/src/plugins/vis_types/timelion/server/series_functions/quandl.test.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { parse } from 'query-string'; -import fn from './quandl'; -import moment from 'moment'; -import fetchMock from 'node-fetch'; - -const parseURL = require('url').parse; -const tlConfig = require('./fixtures/tl_config')(); - -function parseUrlParams(url) { - return parse(parseURL(url).query, { sort: false }); -} - -jest.mock('node-fetch', () => - jest.fn(() => - Promise.resolve({ - json: function () { - return { - name: '__beer__', - data: [ - ['2015-01-01', 3], - ['2015-01-02', 14], - ['2015-01-03', 15.92], - ['2015-01-04', 65.35], - ], - }; - }, - }) - ) -); - -import invoke from './helpers/invoke_series_fn.js'; - -describe('quandl', function () { - beforeEach(function () { - jest.clearAllMocks(); - }); - - it('should wrap the quandl response up in a seriesList', function () { - return invoke(fn, []).then(function (result) { - expect(result.output.list[0].data[0][1]).toEqual(3); - expect(result.output.list[0].data[1][1]).toEqual(14); - }); - }); - - it('should set the label to that of the quandl name', function () { - return invoke(fn, []).then(function (result) { - expect(result.output.list[0].label).toEqual('__beer__'); - }); - }); - - it('should call the quandl API with the quandl code that has been passed', function () { - return invoke(fn, ['BEER/IS_GOOD']).then(function () { - expect(fetchMock).toHaveBeenCalled(); - expect(fetchMock.mock.calls[0][0].match(/datasets\/(.*).json/)[1]).toEqual('BEER/IS_GOOD'); - }); - }); - - it('should limit the time span and interval to the stuff attached to tlConfig', function () { - return invoke(fn, []).then(function () { - const params = parseUrlParams(fetchMock.mock.calls[0][0]); - expect(params.trim_start).toEqual(moment.utc(tlConfig.time.from).format('YYYY-MM-DD')); - expect(params.trim_end).toEqual(moment.utc(tlConfig.time.to).format('YYYY-MM-DD')); - }); - }); - - it('should throw an error is passed an unsupported interval', function () { - return expect(invoke(fn, [], { time: { interval: '2d' } })).rejects.toThrowError(); - }); - - it('should use the configured API key when talking to quandl', function () { - return invoke(fn, [], { settings: { 'timelion:quandl.key': 'bEeR' } }).then(function () { - const params = parseUrlParams(fetchMock.mock.calls[0][0]); - expect(params.auth_token).toEqual('bEeR'); - }); - }); -}); diff --git a/src/plugins/vis_types/timelion/server/timelion.json b/src/plugins/vis_types/timelion/server/timelion.json index ec3db84e447a3..c3f5ded2fcb78 100644 --- a/src/plugins/vis_types/timelion/server/timelion.json +++ b/src/plugins/vis_types/timelion/server/timelion.json @@ -1,14 +1,8 @@ { - "quandl": { - "key": "someKeyHere" - }, "es": { "timefield": "@timestamp", "default_index": "_all" }, - "graphite": { - "url": "https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite" - }, "default_rows": 2, "default_columns": 2, "max_buckets": 2000, diff --git a/src/plugins/vis_types/timelion/server/ui_settings.ts b/src/plugins/vis_types/timelion/server/ui_settings.ts index a79385be08531..30c170b135da8 100644 --- a/src/plugins/vis_types/timelion/server/ui_settings.ts +++ b/src/plugins/vis_types/timelion/server/ui_settings.ts @@ -12,10 +12,6 @@ import type { UiSettingsParams } from 'kibana/server'; import { UI_SETTINGS } from '../common/constants'; -const experimentalLabel = i18n.translate('timelion.uiSettings.experimentalLabel', { - defaultMessage: 'technical preview', -}); - export function getUiSettings(): Record> { return { [UI_SETTINGS.LEGACY_CHARTS_LIBRARY]: { @@ -94,33 +90,5 @@ export function getUiSettings(): Record> { category: ['timelion'], schema: schema.string(), }, - [UI_SETTINGS.GRAPHITE_URL]: { - name: i18n.translate('timelion.uiSettings.graphiteURLLabel', { - defaultMessage: 'Graphite URL', - description: - 'The URL should be in the form of https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite', - }), - value: '', - description: i18n.translate('timelion.uiSettings.graphiteURLDescription', { - defaultMessage: - '{experimentalLabel} The URL of your graphite host. If no URL is set, the first graphite URL configured in kibana.yml is used.', - values: { experimentalLabel: `[${experimentalLabel}]` }, - }), - category: ['timelion'], - schema: schema.nullable(schema.string()), - }, - [UI_SETTINGS.QUANDL_KEY]: { - name: i18n.translate('timelion.uiSettings.quandlKeyLabel', { - defaultMessage: 'Quandl key', - }), - value: 'someKeyHere', - description: i18n.translate('timelion.uiSettings.quandlKeyDescription', { - defaultMessage: '{experimentalLabel} Your API key from www.quandl.com', - values: { experimentalLabel: `[${experimentalLabel}]` }, - }), - sensitive: true, - category: ['timelion'], - schema: schema.string(), - }, }; } diff --git a/src/plugins/vis_types/timeseries/common/interval_regexp.ts b/src/plugins/vis_types/timeseries/common/interval_regexp.ts index 7e190ab6e8d2f..80aea32f0feb3 100644 --- a/src/plugins/vis_types/timeseries/common/interval_regexp.ts +++ b/src/plugins/vis_types/timeseries/common/interval_regexp.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; export const GTE_INTERVAL_RE = new RegExp(`^>=([\\d\\.]+\\s*(${dateMath.units.join('|')}))$`); export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`); diff --git a/src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx b/src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx index 749d6ca62bfa9..56d763ad64eb5 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import type { PaletteRegistry, PaletteOutput } from '@kbn/coloring'; import { EuiColorPalettePicker } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { rainbowColors } from '../lib/rainbow_colors'; diff --git a/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx b/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx index 5f33fc34e7d67..f2bf6425cf775 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx @@ -14,8 +14,7 @@ import { XYChartSeriesIdentifier, GeometryValue } from '@elastic/charts'; import { IUiSettingsClient } from 'src/core/public'; import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { PersistedState } from 'src/plugins/visualizations/public'; -import { PaletteRegistry } from 'src/plugins/charts/public'; - +import type { PaletteRegistry } from '@kbn/coloring'; import { TimeseriesLoading } from './timeseries_loading'; import { TimeseriesVisTypes } from './vis_types'; import type { FetchedIndexPattern, PanelData, TimeseriesVisData } from '../../../common/types'; diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts index 512a9d1ff9169..9061e71283e0c 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts @@ -10,8 +10,7 @@ import React, { lazy } from 'react'; import { XYChartSeriesIdentifier, GeometryValue } from '@elastic/charts'; import { IUiSettingsClient } from 'src/core/public'; import { PersistedState } from 'src/plugins/visualizations/public'; -import { PaletteRegistry } from 'src/plugins/charts/public'; - +import type { PaletteRegistry } from '@kbn/coloring'; import { TimeseriesVisParams } from '../../../types'; import type { TimeseriesVisData, PanelData } from '../../../../common/types'; import type { FieldFormatMap } from '../../../../../../data/common'; diff --git a/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts b/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts index e02965c1b0657..ad6fd361400b4 100644 --- a/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts +++ b/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts @@ -5,7 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; + +import type { PaletteRegistry, PaletteOutput } from '@kbn/coloring'; import { PALETTES } from '../../../common/enums'; import type { PanelData } from '../../../common/types'; import { computeGradientFinalColor } from './compute_gradient_final_color'; diff --git a/src/plugins/vis_types/timeseries/public/trigger_action/index.ts b/src/plugins/vis_types/timeseries/public/trigger_action/index.ts index 15fb1aec2974c..5cdbc72d08fe3 100644 --- a/src/plugins/vis_types/timeseries/public/trigger_action/index.ts +++ b/src/plugins/vis_types/timeseries/public/trigger_action/index.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { PaletteOutput } from '../../../../charts/public'; +import type { PaletteOutput } from '@kbn/coloring'; import type { NavigateToLensContext, VisualizeEditorLayersContext, diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts index c841f08895b7a..b630427781179 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { convertIntervalToUnit, parseInterval, diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts index e1cc1f1f26eb2..9e48b306445b2 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import type { Panel } from '../../../../common/types'; import { RollupSearchCapabilities } from './rollup_search_capabilities'; diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts index 1468d5ddee5bf..34d0824df7fca 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; export type Unit = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'y'; diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts index e02b403c8ba13..58c96eca99b61 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { Unit } from '@elastic/datemath'; +import type { Unit } from '@kbn/datemath'; import { getUnitValue, diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js index a2dd549fd828f..9e9b866c7b98e 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js @@ -8,7 +8,7 @@ import _ from 'lodash'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; // Assume interval is in the form (value)(unit), such as "1h" const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + dateMath.units.join('|') + ')$'); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts index 64999154c10fb..356df6cd86f5e 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { getUnitValue, diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts index b3a29287208d6..3252736669bce 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts @@ -7,7 +7,7 @@ */ import { sortBy, isNumber } from 'lodash'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; /** @ts-ignore */ import { INTERVAL_STRING_RE } from '../../../../common/interval_regexp'; diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js index de2e0f57a111b..e518894c5511a 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js +++ b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js @@ -8,7 +8,7 @@ import $ from 'jquery'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { scheme, loader, logger, Warn, version as vegaVersion, expressionFunction } from 'vega'; import { expressionInterpreter } from 'vega-interpreter'; import { version as vegaLiteVersion } from 'vega-lite'; diff --git a/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js index a0a4fce8d7af4..83055f4a4c5a0 100644 --- a/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js +++ b/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js @@ -7,7 +7,7 @@ */ import d3 from 'd3'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; export class TimeMarker { constructor(times, xScale, height) { diff --git a/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx index 1c93fe92b79af..b073f32ea3a58 100644 --- a/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx @@ -7,7 +7,7 @@ */ import React, { useState, useEffect } from 'react'; - +import type { PaletteRegistry } from '@kbn/coloring'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE } from '@kbn/analytics'; import { EuiFormRow, EuiRange } from '@elastic/eui'; @@ -16,7 +16,6 @@ import { SwitchOption, PalettePicker, } from '../../../../../../../vis_default_editor/public'; -import { PaletteRegistry } from '../../../../../../../charts/public'; import { ChartType } from '../../../../../common'; import { VisParams } from '../../../../types'; diff --git a/src/plugins/vis_types/xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts index 687e291976606..c0913226f9614 100644 --- a/src/plugins/vis_types/xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -7,7 +7,8 @@ */ import type { Fit, Position } from '@elastic/charts'; -import type { Style, Labels, PaletteOutput } from '../../../../charts/public'; +import type { PaletteOutput } from '@kbn/coloring'; +import type { Style, Labels } from '../../../../charts/public'; import type { SchemaConfig, ExpressionValueXYDimension, diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index a77037ce025cb..05d2d0b0765cd 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -7,7 +7,7 @@ */ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; - +import type { PaletteRegistry } from '@kbn/coloring'; import { Chart, ElementClickListener, @@ -29,7 +29,6 @@ import { LegendToggle, getBrushFromChartBrushEventFn, ClickTriggerEvent, - PaletteRegistry, useActiveCursor, } from '../../../charts/public'; import { Datatable, IInterpreterRenderHandlers } from '../../../expressions/public'; diff --git a/src/plugins/visualizations/public/vis_types/types.ts b/src/plugins/visualizations/public/vis_types/types.ts index 14da9eb887e0c..ee4459e4e772e 100644 --- a/src/plugins/visualizations/public/vis_types/types.ts +++ b/src/plugins/visualizations/public/vis_types/types.ts @@ -8,10 +8,10 @@ import type { IconType } from '@elastic/eui'; import type { ReactNode } from 'react'; +import type { PaletteOutput } from '@kbn/coloring'; import type { Adapters } from 'src/plugins/inspector'; import type { AggGroupNames, AggParam, AggGroupName, Query } from '../../../data/public'; import type { DataView } from '../../../data_views/public'; -import { PaletteOutput } from '../../../charts/public'; import type { Vis, VisEditorOptionsProps, VisParams, VisToExpressionAst } from '../types'; import { VisGroups } from './vis_groups_enum'; diff --git a/test/functional/apps/discover/_doc_navigation.ts b/test/functional/apps/discover/_classic_table_doc_navigation.ts similarity index 66% rename from test/functional/apps/discover/_doc_navigation.ts rename to test/functional/apps/discover/_classic_table_doc_navigation.ts index 19f61851ef961..c768d9600c189 100644 --- a/test/functional/apps/discover/_doc_navigation.ts +++ b/test/functional/apps/discover/_classic_table_doc_navigation.ts @@ -19,12 +19,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const kibanaServer = getService('kibanaServer'); - describe('doc link in discover', function contextSize() { + describe('classic table doc link', function contextSize() { before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ + defaultIndex: 'logstash-*', 'doc_table:legacy': true, 'discover:searchFieldsFromSource': true, }); @@ -39,6 +40,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.waitForDocTableLoadingComplete(); }); + beforeEach(async function () { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitForDocTableLoadingComplete(); + }); + it('should open the doc view of the selected document', async function () { // navigate to the doc view await docTable.clickRowToggle({ rowIndex: 0 }); @@ -58,35 +65,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - // no longer relevant as null field won't be returned in the Fields API response - xit('add filter should create an exists filter if value is null (#7189)', async function () { + it('should create an exists filter from the doc view of the selected document', async function () { await PageObjects.discover.waitUntilSearchingHasFinished(); - // Filter special document - await filterBar.addFilter('agent', 'is', 'Missing/Fields'); - await PageObjects.discover.waitUntilSearchingHasFinished(); - - await retry.try(async () => { - // navigate to the doc view - await docTable.clickRowToggle({ rowIndex: 0 }); - const details = await docTable.getDetailsRow(); - await docTable.addInclusiveFilter(details, 'referer'); - await PageObjects.discover.waitUntilSearchingHasFinished(); + await docTable.toggleRowExpanded(); + const detailsRow = await docTable.getDetailsRow(); + await docTable.addExistsFilter(detailsRow, '@timestamp'); - const hasInclusiveFilter = await filterBar.hasFilter( - 'referer', - 'exists', - true, - false, - true - ); - expect(hasInclusiveFilter).to.be(true); - - await docTable.removeInclusiveFilter(details, 'referer'); - await PageObjects.discover.waitUntilSearchingHasFinished(); - const hasExcludeFilter = await filterBar.hasFilter('referer', 'exists', true, false, false); - expect(hasExcludeFilter).to.be(true); - }); + const hasExistsFilter = await filterBar.hasFilter('@timestamp', 'exists', true, false, false); + expect(hasExistsFilter).to.be(true); }); }); } diff --git a/test/functional/apps/discover/_data_grid_doc_navigation.ts b/test/functional/apps/discover/_data_grid_doc_navigation.ts index 73077dcc9749a..2da6db97aa13f 100644 --- a/test/functional/apps/discover/_data_grid_doc_navigation.ts +++ b/test/functional/apps/discover/_data_grid_doc_navigation.ts @@ -54,37 +54,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - // no longer relevant as null field won't be returned in the Fields API response - xit('add filter should create an exists filter if value is null (#7189)', async function () { + it('should create an exists filter from doc view of the selected document', async function () { await PageObjects.discover.waitUntilSearchingHasFinished(); - // Filter special document - await filterBar.addFilter('agent', 'is', 'Missing/Fields'); - await PageObjects.discover.waitUntilSearchingHasFinished(); - - await retry.try(async () => { - // navigate to the doc view - await dataGrid.clickRowToggle({ rowIndex: 0 }); - const details = await dataGrid.getDetailsRow(); - await dataGrid.addInclusiveFilter(details, 'referer'); - await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle({ rowIndex: 0 }); - const hasInclusiveFilter = await filterBar.hasFilter( - 'referer', - 'exists', - true, - false, - true - ); - expect(hasInclusiveFilter).to.be(true); + await testSubjects.click('openFieldActionsButton-@timestamp'); + await testSubjects.click('addExistsFilterButton-@timestamp'); - await dataGrid.clickRowToggle({ rowIndex: 0 }); - const detailsExcluding = await dataGrid.getDetailsRow(); - await dataGrid.removeInclusiveFilter(detailsExcluding, 'referer'); - await PageObjects.discover.waitUntilSearchingHasFinished(); - const hasExcludeFilter = await filterBar.hasFilter('referer', 'exists', true, false, false); - expect(hasExcludeFilter).to.be(true); - }); + const hasExistsFilter = await filterBar.hasFilter('@timestamp', 'exists', true, false, false); + expect(hasExistsFilter).to.be(true); }); }); } diff --git a/test/functional/apps/discover/_saved_queries.ts b/test/functional/apps/discover/_saved_queries.ts index 0e821b7006bf9..fd49a03413321 100644 --- a/test/functional/apps/discover/_saved_queries.ts +++ b/test/functional/apps/discover/_saved_queries.ts @@ -25,22 +25,39 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }; + const from = 'Sep 20, 2015 @ 08:00:00.000'; + const to = 'Sep 21, 2015 @ 08:00:00.000'; + const setUpQueriesWithFilters = async () => { + await kibanaServer.savedObjects.clean({ types: ['search', 'query'] }); // set up a query with filters and a time filter log.debug('set up a query with filters to save'); - const from = 'Sep 20, 2015 @ 08:00:00.000'; - const to = 'Sep 21, 2015 @ 08:00:00.000'; await PageObjects.common.setTime({ from, to }); await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern('logstash-*'); + await retry.try(async function tryingForTime() { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('4,731'); + }); + await filterBar.addFilter('extension.raw', 'is one of', 'jpg'); + await retry.try(async function tryingForTime() { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('3,029'); + }); + await queryBar.setQuery('response:200'); + await queryBar.submitQuery(); + await retry.try(async function tryingForTime() { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('2,792'); + }); }; - // Failing: See https://github.com/elastic/kibana/issues/124990 - describe.skip('saved queries saved objects', function describeIndexTests() { + describe('saved queries saved objects', function describeIndexTests() { before(async function () { log.debug('load kibana index with default index pattern'); - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern', 'query'] }); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); await kibanaServer.importExport.load( @@ -52,12 +69,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace(defaultSettings); log.debug('discover'); await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setDefaultAbsoluteRange(); }); after(async () => { await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/date_nested'); + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern', 'query'] }); + await kibanaServer.savedObjects.clean({ types: ['search', 'query'] }); await esArchiver.unload('test/functional/fixtures/es_archiver/date_nested'); await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); await PageObjects.common.unsetTime(); @@ -90,6 +108,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await queryBar.getQueryString()).to.eql(''); await PageObjects.discover.selectIndexPattern('logstash-*'); + const currentDataView = await PageObjects.discover.getCurrentlySelectedDataView(); + expect(currentDataView).to.be('logstash-*'); + await retry.try(async function tryingForTime() { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('4,731'); + }); expect(await filterBar.hasFilter('extension.raw', 'jpg')).to.be(false); expect(await queryBar.getQueryString()).to.eql(''); @@ -99,8 +123,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/124986 - describe.skip('saved query management component functionality', function () { + describe('saved query management component functionality', function () { before(async () => await setUpQueriesWithFilters()); it('should show the saved query management component when there are no saved queries', async () => { @@ -118,6 +141,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { true, true ); + await savedQueryManagementComponent.savedQueryExistOrFail('OkResponse'); await savedQueryManagementComponent.savedQueryTextExist('response:200'); }); @@ -128,20 +152,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await savedQueryManagementComponent.loadSavedQuery('OkResponse'); const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes(); expect(await filterBar.hasFilter('extension.raw', 'jpg')).to.be(true); - expect(timePickerValues.start).to.not.eql(PageObjects.timePicker.defaultStartTime); - expect(timePickerValues.end).to.not.eql(PageObjects.timePicker.defaultEndTime); + expect(timePickerValues.start).to.eql(from); + expect(timePickerValues.end).to.eql(to); }); it('preserves the currently loaded query when the page is reloaded', async () => { await browser.refresh(); const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes(); expect(await filterBar.hasFilter('extension.raw', 'jpg')).to.be(true); - expect(timePickerValues.start).to.not.eql(PageObjects.timePicker.defaultStartTime); - expect(timePickerValues.end).to.not.eql(PageObjects.timePicker.defaultEndTime); - await retry.waitFor( - 'the right hit count', - async () => (await PageObjects.discover.getHitCount()) === '2,792' - ); + expect(timePickerValues.start).to.eql(from); + expect(timePickerValues.end).to.eql(to); + await retry.waitForWithTimeout('the right hit count', 65000, async () => { + const hitCount = await PageObjects.discover.getHitCount(); + log.debug(`Found hit count is ${hitCount}. Looking for 2,792.`); + return hitCount === '2,792'; + }); expect(await savedQueryManagementComponent.getCurrentlyLoadedQueryID()).to.be('OkResponse'); }); @@ -172,17 +197,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('does not allow saving a query with a non-unique name', async () => { - // this check allows this test to run stand alone, also should fix occacional flakiness - const savedQueryExists = await savedQueryManagementComponent.savedQueryExist('OkResponse'); - if (!savedQueryExists) { - await savedQueryManagementComponent.saveNewQuery( - 'OkResponse', - '200 responses for .jpg over 24 hours', - true, - true - ); - await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); - } await savedQueryManagementComponent.saveNewQueryWithNameError('OkResponse'); }); diff --git a/test/functional/apps/discover/index.ts b/test/functional/apps/discover/index.ts index c9497e872d7b9..994cfeb851281 100644 --- a/test/functional/apps/discover/index.ts +++ b/test/functional/apps/discover/index.ts @@ -37,7 +37,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_source_filters')); loadTestFile(require.resolve('./_large_string')); loadTestFile(require.resolve('./_inspector')); - loadTestFile(require.resolve('./_doc_navigation')); + loadTestFile(require.resolve('./_classic_table_doc_navigation')); loadTestFile(require.resolve('./_date_nanos')); loadTestFile(require.resolve('./_date_nanos_mixed')); loadTestFile(require.resolve('./_indexpattern_without_timefield')); diff --git a/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts b/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts index c1c929b0e2ce7..d2e4d4386cbfd 100644 --- a/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts +++ b/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts @@ -31,9 +31,9 @@ export class RenderingPlugin implements Plugin { const { isAnonymousPage } = req.query; if (isAnonymousPage) { - return res.renderAnonymousCoreApp(); + return res.renderAnonymousCoreApp({ includeExposedConfigKeys: true }); } - return res.renderCoreApp(); + return res.renderCoreApp({ includeExposedConfigKeys: true }); } ); } diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 4752f77f6cdae..c18e38cc1a4d6 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import _ from 'lodash'; import expect from '@kbn/expect'; import '../../plugins/core_provider_plugin/types'; @@ -21,6 +22,9 @@ declare global { } } +const EXPOSED_CONFIG_SETTINGS_ERROR = + 'Actual config settings exposed to the browser do not match what is expected; this assertion fails if extra settings are present and/or expected settings are missing'; + export default function ({ getService }: PluginFunctionalProviderContext) { const appsMenu = getService('appsMenu'); const browser = getService('browser'); @@ -41,6 +45,10 @@ export default function ({ getService }: PluginFunctionalProviderContext) { }); }; + const getInjectedMetadata = () => + browser.execute(() => { + return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!); + }); const getUserSettings = () => browser.execute(() => { return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!) @@ -53,9 +61,197 @@ export default function ({ getService }: PluginFunctionalProviderContext) { return window.__RENDERING_SESSION__; }); - // Talked to @dover, he aggreed we can skip these tests that are unexpectedly flaky - describe.skip('rendering service', () => { - it('renders "core" application', async () => { + describe('rendering service', () => { + it('exposes plugin config settings to authenticated users', async () => { + await navigateTo('/render/core'); + const injectedMetadata = await getInjectedMetadata(); + expect(injectedMetadata).to.not.be.empty(); + expect(injectedMetadata.uiPlugins).to.not.be.empty(); + + const actualExposedConfigKeys = []; + for (const { plugin, exposedConfigKeys } of injectedMetadata.uiPlugins) { + const configPath = Array.isArray(plugin.configPath) + ? plugin.configPath.join('.') + : plugin.configPath; + for (const [exposedConfigKey, type] of Object.entries(exposedConfigKeys)) { + actualExposedConfigKeys.push(`${configPath}.${exposedConfigKey} (${type})`); + } + } + const expectedExposedConfigKeys = [ + // NOTE: each exposed config key has its schema type at the end in "(parentheses)". The schema type comes from Joi; in particular, + // "(any)" can mean a few other data types. This is only intended to be a hint to make it easier for future reviewers to understand + // what types of config settings can be exposed to the browser. + // When plugin owners make a change that exposes additional config values, the changes will be reflected in this test assertion. + // Ensure that your change does not unintentionally expose any sensitive values! + 'console.ui.enabled (boolean)', + 'dashboard.allowByValueEmbeddables (boolean)', + 'data.autocomplete.querySuggestions.enabled (boolean)', + 'data.autocomplete.valueSuggestions.enabled (boolean)', + 'data.autocomplete.valueSuggestions.terminateAfter (duration)', + 'data.autocomplete.valueSuggestions.tiers (array)', + 'data.autocomplete.valueSuggestions.timeout (duration)', + 'data.search.aggs.shardDelay.enabled (boolean)', + 'enterpriseSearch.host (string)', + 'home.disableWelcomeScreen (boolean)', + 'map.emsFileApiUrl (string)', + 'map.emsFontLibraryUrl (string)', + 'map.emsLandingPageUrl (string)', + 'map.emsTileApiUrl (string)', + 'map.emsTileLayerId.bright (string)', + 'map.emsTileLayerId.dark (string)', + 'map.emsTileLayerId.desaturated (string)', + 'map.emsUrl (string)', + 'map.includeElasticMapsService (boolean)', + 'map.tilemap.options.attribution (string)', + 'map.tilemap.options.bounds (array)', + 'map.tilemap.options.default (boolean)', + 'map.tilemap.options.errorTileUrl (string)', + 'map.tilemap.options.maxZoom (number)', + 'map.tilemap.options.minZoom (number)', + 'map.tilemap.options.reuseTiles (boolean)', + 'map.tilemap.options.subdomains (array)', + 'map.tilemap.options.tileSize (number)', + 'map.tilemap.options.tms (boolean)', + 'map.tilemap.url (string)', + 'monitoring.kibana.collection.enabled (boolean)', + 'monitoring.kibana.collection.interval (number)', + 'monitoring.ui.ccs.enabled (boolean)', + 'monitoring.ui.container.apm.enabled (boolean)', + 'monitoring.ui.container.elasticsearch.enabled (boolean)', + 'monitoring.ui.container.logstash.enabled (boolean)', + 'monitoring.ui.enabled (boolean)', + 'monitoring.ui.min_interval_seconds (number)', + 'monitoring.ui.show_license_expiration (boolean)', + 'newsfeed.fetchInterval (duration)', + 'newsfeed.mainInterval (duration)', + 'newsfeed.service.pathTemplate (string)', + 'newsfeed.service.urlRoot (any)', + 'telemetry.allowChangingOptInStatus (boolean)', + 'telemetry.banner (boolean)', + 'telemetry.enabled (boolean)', + 'telemetry.optIn (any)', + 'telemetry.sendUsageFrom (alternatives)', + 'telemetry.sendUsageTo (any)', + 'usageCollection.uiCounters.debug (boolean)', + 'usageCollection.uiCounters.enabled (boolean)', + 'vis_type_vega.enableExternalUrls (boolean)', + 'xpack.apm.profilingEnabled (boolean)', + 'xpack.apm.serviceMapEnabled (boolean)', + 'xpack.apm.ui.enabled (boolean)', + 'xpack.apm.ui.maxTraceItems (number)', + 'xpack.apm.ui.transactionGroupBucketSize (number)', + 'xpack.cases.markdownPlugins.lens (boolean)', + 'xpack.ccr.ui.enabled (boolean)', + 'xpack.cloud.base_url (string)', + 'xpack.cloud.chat.chatURL (string)', + 'xpack.cloud.chat.enabled (boolean)', + 'xpack.cloud.cname (string)', + 'xpack.cloud.deployment_url (string)', + 'xpack.cloud.full_story.enabled (boolean)', + 'xpack.cloud.full_story.org_id (any)', + 'xpack.cloud.id (string)', + 'xpack.cloud.organization_url (string)', + 'xpack.cloud.profile_url (string)', + 'xpack.data_enhanced.search.sessions.cleanupInterval (duration)', + 'xpack.data_enhanced.search.sessions.defaultExpiration (duration)', + 'xpack.data_enhanced.search.sessions.enabled (boolean)', + 'xpack.data_enhanced.search.sessions.expireInterval (duration)', + 'xpack.data_enhanced.search.sessions.management.expiresSoonWarning (duration)', + 'xpack.data_enhanced.search.sessions.management.maxSessions (number)', + 'xpack.data_enhanced.search.sessions.management.refreshInterval (duration)', + 'xpack.data_enhanced.search.sessions.management.refreshTimeout (duration)', + 'xpack.data_enhanced.search.sessions.maxUpdateRetries (number)', + 'xpack.data_enhanced.search.sessions.monitoringTaskTimeout (duration)', + 'xpack.data_enhanced.search.sessions.notTouchedInProgressTimeout (duration)', + 'xpack.data_enhanced.search.sessions.notTouchedTimeout (duration)', + 'xpack.data_enhanced.search.sessions.pageSize (number)', + 'xpack.data_enhanced.search.sessions.trackingInterval (duration)', + 'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean)', + 'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)', + 'xpack.fleet.agents.enabled (boolean)', + 'xpack.global_search.search_timeout (duration)', + 'xpack.graph.canEditDrillDownUrls (boolean)', + 'xpack.graph.savePolicy (alternatives)', + 'xpack.ilm.ui.enabled (boolean)', + 'xpack.index_management.ui.enabled (boolean)', + 'xpack.infra.sources.default.fields.message (array)', + 'xpack.license_management.ui.enabled (boolean)', + 'xpack.maps.preserveDrawingBuffer (boolean)', + 'xpack.maps.showMapsInspectorAdapter (boolean)', + 'xpack.observability.unsafe.alertingExperience.enabled (boolean)', + 'xpack.observability.unsafe.cases.enabled (boolean)', + 'xpack.observability.unsafe.overviewNext.enabled (boolean)', + 'xpack.observability.unsafe.rules.enabled (boolean)', + 'xpack.osquery.actionEnabled (boolean)', + 'xpack.osquery.packs (boolean)', + 'xpack.osquery.savedQueries (boolean)', + 'xpack.remote_clusters.ui.enabled (boolean)', + /** + * NOTE: The Reporting plugin is currently disabled in functional tests (see test/functional/config.js). + * It will be re-enabled once #102552 is completed. + */ + // 'xpack.reporting.roles.allow (array)', + // 'xpack.reporting.roles.enabled (boolean)', + // 'xpack.reporting.poll.jobCompletionNotifier.interval (number)', + // 'xpack.reporting.poll.jobCompletionNotifier.intervalErrorMultiplier (number)', + // 'xpack.reporting.poll.jobsRefresh.interval (number)', + // 'xpack.reporting.poll.jobsRefresh.intervalErrorMultiplier (number)', + 'xpack.rollup.ui.enabled (boolean)', + 'xpack.saved_object_tagging.cache_refresh_interval (duration)', + 'xpack.security.loginAssistanceMessage (string)', + 'xpack.security.sameSiteCookies (alternatives)', + 'xpack.security.showInsecureClusterWarning (boolean)', + 'xpack.securitySolution.enableExperimental (array)', + 'xpack.snapshot_restore.slm_ui.enabled (boolean)', + 'xpack.snapshot_restore.ui.enabled (boolean)', + 'xpack.trigger_actions_ui.enableExperimental (array)', + 'xpack.trigger_actions_ui.enableGeoTrackingThresholdAlert (boolean)', + 'xpack.upgrade_assistant.readonly (boolean)', + 'xpack.upgrade_assistant.ui.enabled (boolean)', + ]; + // We don't assert that actualExposedConfigKeys and expectedExposedConfigKeys are equal, because test failure messages with large + // arrays are hard to grok. Instead, we take the difference between the two arrays and assert them separately, that way it's + // abundantly clear when the test fails that (A) Kibana is exposing a new key, or (B) Kibana is no longer exposing a key. + const extra = _.difference(actualExposedConfigKeys, expectedExposedConfigKeys).sort(); + const missing = _.difference(expectedExposedConfigKeys, actualExposedConfigKeys).sort(); + expect({ extra, missing }).to.eql({ extra: [], missing: [] }, EXPOSED_CONFIG_SETTINGS_ERROR); + }); + + it('exposes plugin config settings to unauthenticated users', async () => { + await navigateTo('/render/core?isAnonymousPage=true'); + const injectedMetadata = await getInjectedMetadata(); + expect(injectedMetadata).to.not.be.empty(); + expect(injectedMetadata.uiPlugins).to.not.be.empty(); + + const actualExposedConfigKeys = []; + for (const { plugin, exposedConfigKeys } of injectedMetadata.uiPlugins) { + const configPath = Array.isArray(plugin.configPath) + ? plugin.configPath.join('.') + : plugin.configPath; + for (const [exposedConfigKey, type] of Object.entries(exposedConfigKeys)) { + actualExposedConfigKeys.push(`${configPath}.${exposedConfigKey} (${type})`); + } + } + const expectedExposedConfigKeys = [ + // NOTE: each exposed config key has its schema type at the end in "(parentheses)". The schema type comes from Joi; in particular, + // "(any)" can mean a few other data types. This is only intended to be a hint to make it easier for future reviewers to understand + // what types of config settings can be exposed to the browser. + // When plugin owners make a change that exposes additional config values, the changes will be reflected in this test assertion. + // Ensure that your change does not unintentionally expose any sensitive values! + 'xpack.security.loginAssistanceMessage (string)', + 'xpack.security.sameSiteCookies (alternatives)', + 'xpack.security.showInsecureClusterWarning (boolean)', + ]; + // We don't assert that actualExposedConfigKeys and expectedExposedConfigKeys are equal, because test failure messages with large + // arrays are hard to grok. Instead, we take the difference between the two arrays and assert them separately, that way it's + // abundantly clear when the test fails that (A) Kibana is exposing a new key, or (B) Kibana is no longer exposing a key. + const extra = _.difference(actualExposedConfigKeys, expectedExposedConfigKeys).sort(); + const missing = _.difference(expectedExposedConfigKeys, actualExposedConfigKeys).sort(); + expect({ extra, missing }).to.eql({ extra: [], missing: [] }, EXPOSED_CONFIG_SETTINGS_ERROR); + }); + + // FLAKY + it.skip('renders "core" application', async () => { await navigateTo('/render/core'); const [loadingMessage, userSettings] = await Promise.all([ @@ -70,7 +266,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) { expect(await exists('renderingHeader')).to.be(true); }); - it('renders "core" application without user settings', async () => { + // FLAKY + it.skip('renders "core" application without user settings', async () => { await navigateTo('/render/core?isAnonymousPage=true'); const [loadingMessage, userSettings] = await Promise.all([ @@ -85,7 +282,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) { expect(await exists('renderingHeader')).to.be(true); }); - it('navigates between standard application and one with custom appRoute', async () => { + // FLAKY + it.skip('navigates between standard application and one with custom appRoute', async () => { await navigateTo('/'); await find.waitForElementStale(await findLoadingMessage()); @@ -108,7 +306,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) { ]); }); - it('navigates between applications with custom appRoutes', async () => { + // FLAKY + it.skip('navigates between applications with custom appRoutes', async () => { await navigateTo('/'); await find.waitForElementStale(await findLoadingMessage()); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts index e53b84ca76496..27830a4f74892 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts @@ -51,12 +51,14 @@ describe('Rules', () => { cy.contains('Alerts and rules').click(); cy.contains('Create error count rule').click(); - // Check for the existence of this element to make sure the form + // Check for the existence of these elements to make sure the form // has loaded. cy.contains('for the last'); + cy.contains('Actions'); + cy.contains('Save').should('not.be.disabled'); // Save, with no actions - cy.contains('button:not(:disabled)', 'Save').click(); + cy.contains('Save').click(); cy.get(confirmModalButtonSelector).click(); cy.contains(`Created rule "${ruleName}`); diff --git a/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/save_modal.tsx b/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/save_modal.tsx index 9ea40fdd38a36..291cde98fd58f 100644 --- a/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/save_modal.tsx +++ b/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/save_modal.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { EuiModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useHistory } from 'react-router-dom'; diff --git a/x-pack/plugins/apm/public/context/url_params_context/helpers.test.ts b/x-pack/plugins/apm/public/context/url_params_context/helpers.test.ts index 9ab0948fd75aa..9ed05a1ef186e 100644 --- a/x-pack/plugins/apm/public/context/url_params_context/helpers.test.ts +++ b/x-pack/plugins/apm/public/context/url_params_context/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import moment from 'moment-timezone'; import * as helpers from './helpers'; diff --git a/x-pack/plugins/apm/public/context/url_params_context/helpers.ts b/x-pack/plugins/apm/public/context/url_params_context/helpers.ts index 6856c0e7d2506..1fb70e929ad5a 100644 --- a/x-pack/plugins/apm/public/context/url_params_context/helpers.ts +++ b/x-pack/plugins/apm/public/context/url_params_context/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { pickBy } from 'lodash'; import { UrlParams } from './types'; diff --git a/x-pack/plugins/apm/scripts/test/e2e.js b/x-pack/plugins/apm/scripts/test/e2e.js index 148d5011b1ecb..a4a0cc79cac2d 100644 --- a/x-pack/plugins/apm/scripts/test/e2e.js +++ b/x-pack/plugins/apm/scripts/test/e2e.js @@ -6,7 +6,7 @@ */ /* eslint-disable no-console */ - +const { times } = require('lodash'); const path = require('path'); const yargs = require('yargs'); const childProcess = require('child_process'); @@ -45,6 +45,10 @@ const { argv } = yargs(process.argv.slice(2)) type: 'boolean', description: 'stop tests after the first failure', }) + .option('times', { + type: 'number', + description: 'Repeat the test n number of times', + }) .help(); const { server, runner, open, grep, bail, kibanaInstallDir } = argv; @@ -63,5 +67,28 @@ const grepArg = grep ? `--grep "${grep}"` : ''; const bailArg = bail ? `--bail` : ''; const cmd = `node ../../../../scripts/${ftrScript} --config ${config} ${grepArg} ${bailArg} --kibana-install-dir '${kibanaInstallDir}'`; -console.log(`Running "${cmd}"`); -childProcess.execSync(cmd, { cwd: e2eDir, stdio: 'inherit' }); +function runTests() { + console.log(`Running "${cmd}"`); + childProcess.execSync(cmd, { cwd: e2eDir, stdio: 'inherit' }); +} + +if (argv.times) { + const runCounter = { succeeded: 0, failed: 0, remaining: argv.times }; + let exitStatus = 0; + times(argv.times, () => { + try { + runTests(); + runCounter.succeeded++; + } catch (e) { + exitStatus = 1; + runCounter.failed++; + } + runCounter.remaining--; + if (argv.times > 1) { + console.log(runCounter); + } + }); + process.exit(exitStatus); +} else { + runTests(); +} diff --git a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts b/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts index 5affecb3541cc..f84fe4d3169fb 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; import { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts index b61e03319b916..751dbf5126750 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { ExpressionValueFilter, ExpressionFunctionDefinition } from '../../../types'; import { getFunctionHelp, getFunctionErrors } from '../../../i18n'; diff --git a/x-pack/plugins/canvas/common/lib/build_embeddable_filters.ts b/x-pack/plugins/canvas/common/lib/build_embeddable_filters.ts index c98d2f080452a..9209eec105b23 100644 --- a/x-pack/plugins/canvas/common/lib/build_embeddable_filters.ts +++ b/x-pack/plugins/canvas/common/lib/build_embeddable_filters.ts @@ -6,7 +6,7 @@ */ import { buildQueryFilter, Filter } from '@kbn/es-query'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { maxBy, minBy } from 'lodash'; import { ExpressionValueFilter } from '../../types'; // @ts-expect-error untyped local diff --git a/x-pack/plugins/canvas/public/components/workpad_filters/filter_views/time_filter.ts b/x-pack/plugins/canvas/public/components/workpad_filters/filter_views/time_filter.ts index 1dc02f61d05f7..afdd1d89d3690 100644 --- a/x-pack/plugins/canvas/public/components/workpad_filters/filter_views/time_filter.ts +++ b/x-pack/plugins/canvas/public/components/workpad_filters/filter_views/time_filter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; import { FilterType, FilterViewSpec, SimpleFilterViewField } from '../../../../types'; import { formatByKey } from '../utils'; diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index be4ba273c5408..37cddf0eba9a5 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -27,7 +27,6 @@ export const RULE_FAILED = `failed`; // activated via a simple code change in a single location. export const INTERNAL_FEATURE_FLAGS = { showBenchmarks: false, - showTrendLineMock: false, showManageRulesMock: false, showRisksMock: false, } as const; diff --git a/x-pack/plugins/cloud_security_posture/common/types.ts b/x-pack/plugins/cloud_security_posture/common/types.ts index b414b49ef30d3..b9403128220f5 100644 --- a/x-pack/plugins/cloud_security_posture/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/common/types.ts @@ -25,6 +25,10 @@ export interface ResourceType extends FindingsEvaluation { name: string; } +export interface PostureTrend extends Stats { + timestamp: string; +} + export interface Cluster { meta: { clusterId: string; @@ -33,12 +37,14 @@ export interface Cluster { }; stats: Stats; resourcesTypes: ResourceType[]; + trend: PostureTrend[]; } export interface ComplianceDashboardData { stats: Stats; resourcesTypes: ResourceType[]; clusters: Cluster[]; + trend: PostureTrend[]; } export interface Benchmark { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/cloud_posture_score_chart.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/cloud_posture_score_chart.tsx index 980e85f66e3f5..dd872b49aec62 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/cloud_posture_score_chart.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/cloud_posture_score_chart.tsx @@ -19,23 +19,27 @@ import { timeFormatter, } from '@elastic/charts'; import { EuiFlexGroup, EuiText, EuiHorizontalRule, EuiFlexItem } from '@elastic/eui'; +import { FormattedDate, FormattedTime } from '@kbn/i18n-react'; +import moment from 'moment'; import { statusColors } from '../../../common/constants'; -import type { Stats } from '../../../../common/types'; +import type { PostureTrend, Stats } from '../../../../common/types'; import * as TEXT from '../translations'; import { CompactFormattedNumber } from '../../../components/compact_formatted_number'; -import { INTERNAL_FEATURE_FLAGS } from '../../../../common/constants'; interface CloudPostureScoreChartProps { + trend: PostureTrend[]; data: Stats; id: string; partitionOnElementClick: (elements: PartitionElementEvent[]) => void; } +const getPostureScorePercentage = (postureScore: number): string => `${Math.round(postureScore)}%`; + const ScoreChart = ({ data: { totalPassed, totalFailed }, id, partitionOnElementClick, -}: CloudPostureScoreChartProps) => { +}: Omit) => { const data = [ { label: TEXT.PASSED, value: totalPassed }, { label: TEXT.FAILED, value: totalFailed }, @@ -79,7 +83,7 @@ const PercentageInfo = ({ totalPassed, totalFindings, }: CloudPostureScoreChartProps['data']) => { - const percentage = `${Math.round(postureScore)}%`; + const percentage = getPostureScorePercentage(postureScore); return ( @@ -94,32 +98,53 @@ const PercentageInfo = ({ ); }; -const mockData = [ - [0, 9], - [1000, 70], - [2000, 40], - [4000, 90], - [5000, 53], -]; +const convertTrendToEpochTime = (trend: PostureTrend) => ({ + ...trend, + timestamp: moment(trend.timestamp).valueOf(), +}); -const ComplianceTrendChart = () => ( - - - - - - -); +const ComplianceTrendChart = ({ trend }: { trend: PostureTrend[] }) => { + const epochTimeTrend = trend.map(convertTrendToEpochTime); + + return ( + + ( + <> + + {', '} + + + ), + }} + /> + + + getPostureScorePercentage(rawScore)} + /> + + ); +}; export const CloudPostureScoreChart = ({ data, + trend, id, partitionOnElementClick, }: CloudPostureScoreChartProps) => ( @@ -136,7 +161,7 @@ export const CloudPostureScoreChart = ({ - + ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx index 565811bca7ee7..a3b32ef3fe2c6 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx @@ -100,6 +100,7 @@ export const BenchmarksSection = ({ handleElementClick(cluster.meta.clusterId, elements) } diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx index fa2e4e872034c..c123459d9e963 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx @@ -50,6 +50,7 @@ export const SummarySection = ({ complianceData }: { complianceData: ComplianceD diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts index 154c2d58cd330..99046d38dfcc6 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts @@ -17,9 +17,10 @@ import type { ComplianceDashboardData } from '../../../common/types'; import { CSP_KUBEBEAT_INDEX_PATTERN, STATS_ROUTE_PATH } from '../../../common/constants'; import { CspAppContext } from '../../plugin'; import { getResourcesTypes } from './get_resources_types'; -import { getClusters } from './get_clusters'; +import { ClusterWithoutTrend, getClusters } from './get_clusters'; import { getStats } from './get_stats'; import { CspRouter } from '../../types'; +import { getTrends, Trends } from './get_trends'; export interface ClusterBucket { ordered_top_hits: AggregationsTopHitsAggregate; @@ -74,6 +75,18 @@ const getLatestCyclesIds = async (esClient: ElasticsearchClient): Promise + clustersWithoutTrends.map((cluster) => ({ + ...cluster, + trend: trends.map(({ timestamp, clusters: clustersTrendData }) => ({ + timestamp, + ...clustersTrendData[cluster.meta.clusterId], + })), + })); + +const getSummaryTrend = (trends: Trends) => + trends.map(({ timestamp, summary }) => ({ timestamp, ...summary })); + // TODO: Utilize ES "Point in Time" feature https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html export const defineGetComplianceDashboardRoute = ( router: CspRouter, @@ -96,16 +109,21 @@ export const defineGetComplianceDashboardRoute = ( }, }; - const [stats, resourcesTypes, clusters] = await Promise.all([ + const [stats, resourcesTypes, clustersWithoutTrends, trends] = await Promise.all([ getStats(esClient, query), getResourcesTypes(esClient, query), getClusters(esClient, query), + getTrends(esClient), ]); + const clusters = getClustersTrends(clustersWithoutTrends, trends); + const trend = getSummaryTrend(trends); + const body: ComplianceDashboardData = { stats, resourcesTypes, clusters, + trend, }; return response.ok({ diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts index 98171bf5ec332..a030a744c2d2d 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts @@ -11,7 +11,7 @@ import type { QueryDslQueryContainer, SearchRequest, } from '@elastic/elasticsearch/lib/api/types'; -import { ComplianceDashboardData } from '../../../common/types'; +import { Cluster } from '../../../common/types'; import { getResourceTypeFromAggs, resourceTypeAggQuery } from './get_resources_types'; import type { ResourceTypeQueryResult } from './get_resources_types'; import { CSP_KUBEBEAT_INDEX_PATTERN } from '../../../common/constants'; @@ -35,6 +35,8 @@ interface ClustersQueryResult { aggs_by_cluster_id: Aggregation; } +export type ClusterWithoutTrend = Omit; + export const getClustersQuery = (query: QueryDslQueryContainer): SearchRequest => ({ index: CSP_KUBEBEAT_INDEX_PATTERN, size: 0, @@ -66,9 +68,7 @@ export const getClustersQuery = (query: QueryDslQueryContainer): SearchRequest = }, }); -export const getClustersFromAggs = ( - clusters: ClusterBucket[] -): ComplianceDashboardData['clusters'] => +export const getClustersFromAggs = (clusters: ClusterBucket[]): ClusterWithoutTrend[] => clusters.map((cluster) => { // get cluster's meta data const benchmarks = cluster.benchmarks.buckets; @@ -103,7 +103,7 @@ export const getClustersFromAggs = ( export const getClusters = async ( esClient: ElasticsearchClient, query: QueryDslQueryContainer -): Promise => { +): Promise => { const queryResult = await esClient.search(getClustersQuery(query), { meta: true, }); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts new file mode 100644 index 0000000000000..127cf3e1a3f80 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts @@ -0,0 +1,131 @@ +/* + * 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 { getTrendsFromQueryResult, ScoreTrendDoc } from './get_trends'; + +const trendDocs: ScoreTrendDoc[] = [ + { + '@timestamp': '2022-04-06T15:30:00Z', + total_findings: 20, + passed_findings: 5, + failed_findings: 15, + score_by_cluster_id: { + first_cluster_id: { + total_findings: 20, + passed_findings: 5, + failed_findings: 15, + }, + }, + }, + { + '@timestamp': '2022-04-06T15:00:00Z', + total_findings: 40, + passed_findings: 25, + failed_findings: 15, + score_by_cluster_id: { + second_cluster_id: { + total_findings: 20, + passed_findings: 10, + failed_findings: 10, + }, + third_cluster_id: { + total_findings: 20, + passed_findings: 15, + failed_findings: 5, + }, + }, + }, + { + '@timestamp': '2022-04-05T15:30:00Z', + total_findings: 30, + passed_findings: 25, + failed_findings: 5, + score_by_cluster_id: { + forth_cluster_id: { + total_findings: 25, + passed_findings: 25, + failed_findings: 0, + }, + fifth_cluster_id: { + total_findings: 5, + passed_findings: 0, + failed_findings: 5, + }, + }, + }, +]; + +describe('getTrendsFromQueryResult', () => { + it('should return value matching Trends type definition, in descending order, and with postureScore', async () => { + const trends = getTrendsFromQueryResult(trendDocs); + expect(trends).toEqual([ + { + timestamp: '2022-04-06T15:30:00Z', + summary: { + totalFindings: 20, + totalPassed: 5, + totalFailed: 15, + postureScore: 25.0, + }, + clusters: { + first_cluster_id: { + totalFindings: 20, + totalPassed: 5, + totalFailed: 15, + postureScore: 25.0, + }, + }, + }, + { + timestamp: '2022-04-06T15:00:00Z', + summary: { + totalFindings: 40, + totalPassed: 25, + totalFailed: 15, + postureScore: 62.5, + }, + clusters: { + second_cluster_id: { + totalFindings: 20, + totalPassed: 10, + totalFailed: 10, + postureScore: 50.0, + }, + third_cluster_id: { + totalFindings: 20, + totalPassed: 15, + totalFailed: 5, + postureScore: 75.0, + }, + }, + }, + { + timestamp: '2022-04-05T15:30:00Z', + summary: { + totalFindings: 30, + totalPassed: 25, + totalFailed: 5, + postureScore: 83.3, + }, + clusters: { + forth_cluster_id: { + totalFindings: 25, + totalPassed: 25, + totalFailed: 0, + postureScore: 100.0, + }, + fifth_cluster_id: { + totalFindings: 5, + totalPassed: 0, + totalFailed: 5, + postureScore: 0, + }, + }, + }, + ]); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts new file mode 100644 index 0000000000000..a432d275fdb64 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts @@ -0,0 +1,73 @@ +/* + * 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 } from 'kibana/server'; +import { BENCHMARK_SCORE_INDEX_PATTERN } from '../../../common/constants'; +import { Stats } from '../../../common/types'; +import { calculatePostureScore } from './get_stats'; + +export interface ScoreTrendDoc { + '@timestamp': string; + total_findings: number; + passed_findings: number; + failed_findings: number; + score_by_cluster_id: Record< + string, + { + total_findings: number; + passed_findings: number; + failed_findings: number; + } + >; +} + +export const getTrendsAggsQuery = () => ({ + index: BENCHMARK_SCORE_INDEX_PATTERN, + size: 5, + sort: '@timestamp:desc', +}); + +export type Trends = Array<{ + timestamp: string; + summary: Stats; + clusters: Record; +}>; + +export const getTrendsFromQueryResult = (scoreTrendDocs: ScoreTrendDoc[]): Trends => + scoreTrendDocs.map((data) => ({ + timestamp: data['@timestamp'], + summary: { + totalFindings: data.total_findings, + totalFailed: data.failed_findings, + totalPassed: data.passed_findings, + postureScore: calculatePostureScore(data.passed_findings, data.failed_findings), + }, + clusters: Object.fromEntries( + Object.entries(data.score_by_cluster_id).map(([clusterId, cluster]) => [ + clusterId, + { + totalFindings: cluster.total_findings, + totalFailed: cluster.failed_findings, + totalPassed: cluster.passed_findings, + postureScore: calculatePostureScore(cluster.passed_findings, cluster.failed_findings), + }, + ]) + ), + })); + +export const getTrends = async (esClient: ElasticsearchClient): Promise => { + const trendsQueryResult = await esClient.search(getTrendsAggsQuery()); + + if (!trendsQueryResult.hits.hits) throw new Error('missing trend results from score index'); + + const scoreTrendDocs = trendsQueryResult.hits.hits.map((hit) => { + if (!hit._source) throw new Error('missing _source data for one or more of trend results'); + return hit._source; + }); + + return getTrendsFromQueryResult(scoreTrendDocs); +}; diff --git a/x-pack/plugins/data_visualizer/common/services/time_buckets.js b/x-pack/plugins/data_visualizer/common/services/time_buckets.js index 49de535ee6c26..92b60cbf6ca10 100644 --- a/x-pack/plugins/data_visualizer/common/services/time_buckets.js +++ b/x-pack/plugins/data_visualizer/common/services/time_buckets.js @@ -9,7 +9,7 @@ import { FIELD_FORMAT_IDS } from '../../../../../src/plugins/field_formats/commo import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; import { ary, assign, isPlainObject, isString, sortBy } from 'lodash'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { parseInterval } from '../utils/parse_interval'; const { duration: d } = moment; diff --git a/x-pack/plugins/data_visualizer/common/utils/parse_interval.ts b/x-pack/plugins/data_visualizer/common/utils/parse_interval.ts index 6ca280dc12ebd..73a20974cde4f 100644 --- a/x-pack/plugins/data_visualizer/common/utils/parse_interval.ts +++ b/x-pack/plugins/data_visualizer/common/utils/parse_interval.ts @@ -6,7 +6,7 @@ */ import { duration, Duration, unitOfTime } from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; type SupportedUnits = unitOfTime.Base; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts index 5f20f02b96c7e..3cc3fa329359d 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts @@ -7,7 +7,7 @@ import moment from 'moment'; import { TimefilterContract } from 'src/plugins/data/public'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { i18n } from '@kbn/i18n'; import type { ToastsStart } from 'kibana/public'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/app.tsx b/x-pack/plugins/fleet/public/applications/fleet/app.tsx index b5872b0a995a9..cd4ba97019766 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/app.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/app.tsx @@ -279,7 +279,7 @@ const FleetTopNav = memo( const topNavConfig: TopNavMenuData[] = [ { label: i18n.translate('xpack.fleet.appNavigation.sendFeedbackButton', { - defaultMessage: 'Send Feedback', + defaultMessage: 'Send feedback', }), iconType: 'popout', run: () => window.open(FEEDBACK_URL), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx index 72642e68d85c1..c0b8f158f43de 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx @@ -46,7 +46,7 @@ export interface EditOutputFlyoutProps { const OUTPUT_TYPE_OPTIONS = [ { value: 'elasticsearch', text: 'Elasticsearch' }, - { value: 'logstash', text: 'Logstash (BETA)' }, + { value: 'logstash', text: 'Logstash (beta)' }, ]; export const EditOutputFlyout: React.FunctionComponent = ({ @@ -138,14 +138,15 @@ export const EditOutputFlyout: React.FunctionComponent = isLogstashOutput && ( - {i18n.translate('xpack.fleet.editOutputFlyout.learnMoreLink', { - defaultMessage: 'Learn more', - })} - + sendFeedback: ( + + + ), }} /> @@ -203,13 +204,13 @@ export const EditOutputFlyout: React.FunctionComponent = helpText={ + ), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx index 57b8681e834bb..ea0e1541fb41c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx @@ -72,7 +72,7 @@ describe('Output form validation', () => { const res = validateLogstashHosts(['https://test.fr:5044']); expect(res).toEqual([ - { index: 0, message: 'Invalid logstash host should not start with http(s)' }, + { index: 0, message: 'Host address must begin with a domain name or IP address' }, ]); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx index 13b90fe661f61..9a95b9e834ec1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx @@ -67,7 +67,7 @@ export function validateLogstashHosts(value: string[]) { if (val.match(/^http([s]){0,1}:\/\//)) { res.push({ message: i18n.translate('xpack.fleet.settings.outputForm.logstashHostProtocolError', { - defaultMessage: 'Invalid logstash host should not start with http(s)', + defaultMessage: 'Host address must begin with a domain name or IP address', }), index: idx, }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/logstash_instructions/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/logstash_instructions/index.tsx index 19ff2cbc61d77..1fdffd1c8a30b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/logstash_instructions/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/logstash_instructions/index.tsx @@ -34,21 +34,21 @@ export const LogstashInstructions = () => { title={ } > <> + ), @@ -71,14 +71,14 @@ const CollapsibleCallout: React.FunctionComponent = ({ children setIsOpen(false)}> ) : ( setIsOpen(true)} fill={true}> )} @@ -191,13 +191,6 @@ const LogstashInstructionSteps = () => { }} /> - - - - ), }, diff --git a/x-pack/plugins/fleet/server/types/models/output.test.ts b/x-pack/plugins/fleet/server/types/models/output.test.ts index 8ad2b14299c73..4441630653a99 100644 --- a/x-pack/plugins/fleet/server/types/models/output.test.ts +++ b/x-pack/plugins/fleet/server/types/models/output.test.ts @@ -14,12 +14,12 @@ describe('Output model', () => { }); it('should return an error for an invalid host', () => { - expect(validateLogstashHost('!@#%&!#!@')).toMatchInlineSnapshot(`"Invalid logstash host"`); + expect(validateLogstashHost('!@#%&!#!@')).toMatchInlineSnapshot(`"Invalid Logstash host"`); }); it('should return an error for an invalid host with http scheme', () => { expect(validateLogstashHost('https://test.fr:5044')).toMatchInlineSnapshot( - `"Invalid logstash host should not start with http(s)"` + `"Host address must begin with a domain name or IP address"` ); }); }); diff --git a/x-pack/plugins/fleet/server/types/models/output.ts b/x-pack/plugins/fleet/server/types/models/output.ts index 86b2a70a318fc..2354412d073b2 100644 --- a/x-pack/plugins/fleet/server/types/models/output.ts +++ b/x-pack/plugins/fleet/server/types/models/output.ts @@ -11,7 +11,7 @@ import { outputType } from '../../../common/constants'; export function validateLogstashHost(val: string) { if (val.match(/^http([s]){0,1}:\/\//)) { - return 'Invalid logstash host should not start with http(s)'; + return 'Host address must begin with a domain name or IP address'; } try { @@ -21,7 +21,7 @@ export function validateLogstashHost(val: string) { return 'Invalid host'; } } catch (err) { - return 'Invalid logstash host'; + return 'Invalid Logstash host'; } } diff --git a/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/components/metrics_node_details_link.tsx b/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/components/metrics_node_details_link.tsx index b51e1bc8b7707..cb83afbc10e3f 100644 --- a/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/components/metrics_node_details_link.tsx +++ b/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/components/metrics_node_details_link.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { parse } from '@elastic/datemath'; +import { parse } from '@kbn/datemath'; import { EuiLink } from '@elastic/eui'; import React from 'react'; import { useLinkProps } from '../../../../../../observability/public'; diff --git a/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/hooks/use_infrastructure_node_metrics.ts b/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/hooks/use_infrastructure_node_metrics.ts index 47e4fd86f04e2..f3daa1b429aca 100644 --- a/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/hooks/use_infrastructure_node_metrics.ts +++ b/x-pack/plugins/infra/public/components/infrastructure_node_metrics_tables/shared/hooks/use_infrastructure_node_metrics.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { parse } from '@elastic/datemath'; +import { parse } from '@kbn/datemath'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useEffect, useMemo, useState } from 'react'; import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/loading_item_view.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/loading_item_view.tsx index 316249ec0fe3c..f6e3ff27f2467 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/loading_item_view.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/loading_item_view.tsx @@ -15,7 +15,7 @@ import { } from '@elastic/eui'; import { FormattedMessage, FormattedTime, FormattedRelative } from '@kbn/i18n-react'; import * as React from 'react'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; import { LogTextSeparator } from './log_text_separator'; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx index bba95b0fffb05..34faac3aefa0c 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiSuperDatePicker } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import moment from 'moment'; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx index a845e59ce6d32..73d0046ce9643 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx @@ -7,7 +7,7 @@ import { useCallback, useMemo, useState } from 'react'; import useInterval from 'react-use/lib/useInterval'; -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import moment from 'moment'; import * as rt from 'io-ts'; import { TimeRange as KibanaTimeRange } from '../../../../../../../src/plugins/data/public'; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts index ada9b0d468fdc..5bbc55dd0f48e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts @@ -9,7 +9,7 @@ import { useCallback, useState, useEffect } from 'react'; import * as rt from 'io-ts'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { constant, identity } from 'fp-ts/lib/function'; import createContainer from 'constate'; import { useUrlState } from '../../../../utils/use_url_state'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx index 8da96586be979..cf766bdb104e5 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx @@ -6,7 +6,7 @@ */ import React, { useCallback, useEffect, useState, useContext } from 'react'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Source } from '../../../../containers/metrics_source'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts index 80af26401c334..98e54daadcade 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts @@ -8,7 +8,7 @@ import createContainer from 'constate'; import { useState, useCallback, useEffect } from 'react'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import * as rt from 'io-ts'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx index 461d0defb000a..9a2b8366f920f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx @@ -14,7 +14,7 @@ import { EuiContextMenuPanelDescriptor, EuiPopover, } from '@elastic/eui'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { Capabilities } from 'src/core/public'; import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources'; import { AlertFlyout } from '../../../../alerting/metric_threshold/components/alert_flyout'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index 788760a0dfe1c..ab4bf11dadb35 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { useEffect, useState } from 'react'; import { DataViewBase } from '@kbn/es-query'; import { isEqual } from 'lodash'; diff --git a/x-pack/plugins/infra/public/utils/convert_interval_to_string.ts b/x-pack/plugins/infra/public/utils/convert_interval_to_string.ts index 075535993e09c..7435e4264a2b2 100644 --- a/x-pack/plugins/infra/public/utils/convert_interval_to_string.ts +++ b/x-pack/plugins/infra/public/utils/convert_interval_to_string.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; import * as rt from 'io-ts'; diff --git a/x-pack/plugins/infra/public/utils/datemath.ts b/x-pack/plugins/infra/public/utils/datemath.ts index fa67c86544fb0..2ed4f68b7a934 100644 --- a/x-pack/plugins/infra/public/utils/datemath.ts +++ b/x-pack/plugins/infra/public/utils/datemath.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath, { Unit } from '@elastic/datemath'; +import dateMath, { Unit } from '@kbn/datemath'; const JS_MAX_DATE = 8640000000000000; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts index b5033bb9a6043..e10558be54033 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { countBy } from 'lodash'; import { MappedAnomalyHit } from '../../infra_ml'; import { MlSystem, MlAnomalyDetectors } from '../../../types'; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts index 20657880c497e..c53119cb14299 100644 --- a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; export const GTE_INTERVAL_RE = new RegExp(`^>=([\\d\\.]+\\s*(${dateMath.units.join('|')}))$`); export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`); diff --git a/x-pack/plugins/infra/server/utils/round_timestamp.ts b/x-pack/plugins/infra/server/utils/round_timestamp.ts index e15fceec5120f..cd2234ed9eef7 100644 --- a/x-pack/plugins/infra/server/utils/round_timestamp.ts +++ b/x-pack/plugins/infra/server/utils/round_timestamp.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import moment from 'moment'; export const roundTimestamp = (timestamp: number, unit: Unit) => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts index cdaac370c31f1..f7ffdee236979 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts @@ -733,6 +733,41 @@ describe('suggestion helpers', () => { ); }); + it('should get the top non-hidden suggestion if there is no active visualization', () => { + defaultParams[0] = { + '1': { + getTableSpec: () => [], + datasourceId: '', + getOperationForColumnId: jest.fn(), + getVisualDefaults: jest.fn(), + getSourceId: jest.fn(), + getFilters: jest.fn(), + }, + }; + defaultParams[3] = { + testVis: mockVisualization1, + vis2: mockVisualization2, + }; + mockVisualization1.getSuggestions.mockReturnValue([]); + mockVisualization2.getSuggestions.mockReturnValue([ + { + score: 0.3, + title: 'second suggestion', + state: { second: true }, + previewIcon: 'empty', + }, + { + score: 0.5, + title: 'mop suggestion', + state: { first: true }, + previewIcon: 'empty', + hide: true, + }, + ]); + const result = getTopSuggestionForField(...defaultParams); + expect(result!.title).toEqual('second suggestion'); + }); + it('should return nothing if visualization does not produce suggestions', () => { mockVisualization1.getSuggestions.mockReturnValue([]); const result = getTopSuggestionForField(...defaultParams); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index f7b3aca890d6a..f24158d2db501 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -289,5 +289,9 @@ export function getTopSuggestionForField( field, mainPalette, }); - return suggestions.find((s) => s.visualizationId === visualization.activeId) || suggestions[0]; + return ( + suggestions.find((s) => s.visualizationId === visualization.activeId) || + suggestions.filter((suggestion) => !suggestion.hide)[0] || + suggestions[0] + ); } diff --git a/x-pack/plugins/lens/public/heatmap_visualization/suggestions.test.ts b/x-pack/plugins/lens/public/heatmap_visualization/suggestions.test.ts index 77d3f4fdde441..dbe2d9a7c9771 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/suggestions.test.ts +++ b/x-pack/plugins/lens/public/heatmap_visualization/suggestions.test.ts @@ -357,6 +357,59 @@ describe('heatmap suggestions', () => { ]); }); + test('for tables with a single metric dimension', () => { + expect( + getSuggestions({ + table: { + layerId: 'first', + isMultiRow: true, + columns: [ + { + columnId: 'test-column', + operation: { + isBucketed: false, + dataType: 'number', + label: 'Count of records', + }, + }, + ], + changeType: 'reduced', + }, + state: { + layerId: 'first', + layerType: layerTypes.DATA, + } as HeatmapVisualizationState, + keptLayerIds: ['first'], + }) + ).toEqual([ + { + state: { + layerId: 'first', + layerType: layerTypes.DATA, + shape: 'heatmap', + valueAccessor: 'test-column', + gridConfig: { + type: HEATMAP_GRID_FUNCTION, + isCellLabelVisible: false, + isYAxisLabelVisible: true, + isXAxisLabelVisible: true, + isYAxisTitleVisible: false, + isXAxisTitleVisible: false, + }, + legend: { + isVisible: true, + position: Position.Right, + type: LEGEND_FUNCTION, + }, + }, + title: 'Heat map', + hide: true, + previewIcon: 'empty', + score: 0.3, + }, + ]); + }); + test('when at least one axis has a date histogram', () => { expect( getSuggestions({ diff --git a/x-pack/plugins/lens/public/heatmap_visualization/suggestions.ts b/x-pack/plugins/lens/public/heatmap_visualization/suggestions.ts index e1478c1605e7f..c13b6eb655e3b 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/suggestions.ts +++ b/x-pack/plugins/lens/public/heatmap_visualization/suggestions.ts @@ -59,6 +59,7 @@ export const getSuggestions: Visualization['getSugges } const isSingleBucketDimension = groups.length === 1 && metrics.length === 0; + const isOnlyMetricDimension = groups.length === 0 && metrics.length === 1; /** * Hide for: @@ -74,7 +75,8 @@ export const getSuggestions: Visualization['getSugges table.changeType === 'reduced' || table.changeType === 'reorder' || isSingleBucketDimension || - hasOnlyDatehistogramBuckets; + hasOnlyDatehistogramBuckets || + isOnlyMetricDimension; const newState: HeatmapVisualizationState = { shape: CHART_SHAPES.HEATMAP, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index 7a391b1639a58..82b4a0aa33409 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -8,7 +8,7 @@ import './field_item.scss'; import React, { useCallback, useState, useMemo } from 'react'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { EuiButtonGroup, EuiButtonIcon, diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/x-pack/plugins/lens/server/routes/field_stats.ts index 787e21b2dd9d9..2a719957cd851 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/x-pack/plugins/lens/server/routes/field_stats.ts @@ -6,7 +6,7 @@ */ import { errors } from '@elastic/elasticsearch'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { schema } from '@kbn/config-schema'; import { CoreSetup } from 'src/core/server'; import type { DataViewField } from 'src/plugins/data_views/common'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/__snapshots__/symbol_utils.test.js.snap b/x-pack/plugins/maps/public/classes/styles/vector/__snapshots__/symbol_utils.test.js.snap new file mode 100644 index 0000000000000..d4936639523c3 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/__snapshots__/symbol_utils.test.js.snap @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`styleSvg Should add fill style property to svg element 1`] = ` +" + + + +" +`; + +exports[`styleSvg Should add stroke and stroke-wdth style properties to svg element 1`] = ` +" + + + +" +`; + +exports[`styleSvg Should not add style property when style not provided 1`] = ` +" + + + +" +`; + +exports[`styleSvg Should override any inherent fill and stroke styles in SVGs 1`] = ` +" + + + + + +" +`; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/symbol_icon.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/symbol_icon.tsx index 4cc4d4169d7e0..fd9b952dbbdea 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/symbol_icon.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/symbol_icon.tsx @@ -7,7 +7,7 @@ import React, { Component, CSSProperties } from 'react'; // @ts-expect-error -import { CUSTOM_ICON_PREFIX_SDF, getSymbolSvg, styleSvg, buildSrcUrl } from '../../symbol_utils'; +import { styleSvg, buildSrcUrl } from '../../symbol_utils'; interface Props { symbolId: string; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.js b/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.js index af165863ffc9c..108a2eb686dcf 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.js @@ -106,15 +106,17 @@ export function buildSrcUrl(svgString) { export async function styleSvg(svgString, fill, stroke) { const svgXml = await parseXmlString(svgString); - let style = ''; - if (fill) { - style += `fill:${fill};`; - } - if (stroke) { - style += `stroke:${stroke};`; - style += `stroke-width:1;`; - } - if (style) svgXml.svg.$.style = style; + + // Elements nested under svg root may define style attribute + // Wildcard descendent selector provides more specificity to ensure root svg style attribute is applied instead of children style attributes + svgXml.svg.style = ` + svg * { + ${fill ? `fill: ${fill}` : '#000'} !important; + ${stroke ? `stroke: ${stroke}` : '#000'} !important; + stroke-width: 1 !important; + vector-effect: non-scaling-stroke !important; + } + `; const builder = new xml2js.Builder(); return builder.buildObject(svgXml); } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.test.js b/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.test.js index 8c85702b19579..f6d40bd70dbea 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.test.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/symbol_utils.test.js @@ -20,26 +20,33 @@ describe('styleSvg', () => { const unstyledSvgString = ''; const styledSvg = await styleSvg(unstyledSvgString); - expect(styledSvg.split('\n')[1]).toBe( - '' - ); + expect(styledSvg).toMatchSnapshot(); }); it('Should add fill style property to svg element', async () => { const unstyledSvgString = ''; const styledSvg = await styleSvg(unstyledSvgString, 'red'); - expect(styledSvg.split('\n')[1]).toBe( - '' - ); + expect(styledSvg).toMatchSnapshot(); }); it('Should add stroke and stroke-wdth style properties to svg element', async () => { const unstyledSvgString = ''; const styledSvg = await styleSvg(unstyledSvgString, 'red', 'white'); - expect(styledSvg.split('\n')[1]).toBe( - '' - ); + expect(styledSvg).toMatchSnapshot(); + }); + + it('Should override any inherent fill and stroke styles in SVGs', async () => { + const unstyledSvgString = ` + + + + + + `; + + const styledSvg = await styleSvg(unstyledSvgString, 'blue', 'black'); + expect(styledSvg).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/maps/public/connected_components/map_settings_panel/map_settings_panel.tsx b/x-pack/plugins/maps/public/connected_components/map_settings_panel/map_settings_panel.tsx index 1efa07e280039..005c40f48cce6 100644 --- a/x-pack/plugins/maps/public/connected_components/map_settings_panel/map_settings_panel.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_settings_panel/map_settings_panel.tsx @@ -74,6 +74,12 @@ export function MapSettingsPanel({
+ + - -
diff --git a/x-pack/plugins/ml/common/util/date_utils.ts b/x-pack/plugins/ml/common/util/date_utils.ts index d09c0bbe0ca39..c668eda03a7be 100644 --- a/x-pack/plugins/ml/common/util/date_utils.ts +++ b/x-pack/plugins/ml/common/util/date_utils.ts @@ -7,7 +7,7 @@ // utility functions for handling dates -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { formatDate } from '@elastic/eui'; import { TimeRange } from '../../../../../src/plugins/data/common'; import { TIME_FORMAT } from '../constants/time_format'; diff --git a/x-pack/plugins/ml/common/util/parse_interval.ts b/x-pack/plugins/ml/common/util/parse_interval.ts index 6ca280dc12ebd..73a20974cde4f 100644 --- a/x-pack/plugins/ml/common/util/parse_interval.ts +++ b/x-pack/plugins/ml/common/util/parse_interval.ts @@ -6,7 +6,7 @@ */ import { duration, Duration, unitOfTime } from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; type SupportedUnits = unitOfTime.Base; diff --git a/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts index 7e14639f1b8b4..b4fecef196ef0 100644 --- a/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { getTimefilter, getToastNotifications } from '../../util/dependency_cache'; import { ml, GetTimeFieldRangeResponse } from '../../services/ml_api_service'; diff --git a/x-pack/plugins/ml/public/application/util/chart_utils.test.js b/x-pack/plugins/ml/public/application/util/chart_utils.test.js index 0900bfacd354e..2c457b079542a 100644 --- a/x-pack/plugins/ml/public/application/util/chart_utils.test.js +++ b/x-pack/plugins/ml/public/application/util/chart_utils.test.js @@ -8,7 +8,7 @@ import seriesConfig from '../explorer/explorer_charts/__mocks__/mock_series_config_filebeat'; jest.mock('./dependency_cache', () => { - const dateMath = require('@elastic/datemath'); + const dateMath = require('@kbn/datemath'); let _time = undefined; const timefilter = { setTime: (time) => { diff --git a/x-pack/plugins/ml/public/application/util/time_buckets.js b/x-pack/plugins/ml/public/application/util/time_buckets.js index d9cfa7729d8d8..21a991ce0a190 100644 --- a/x-pack/plugins/ml/public/application/util/time_buckets.js +++ b/x-pack/plugins/ml/public/application/util/time_buckets.js @@ -7,7 +7,7 @@ import { isPlainObject, isString, ary, sortBy, assign } from 'lodash'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { timeBucketsCalcAutoIntervalProvider } from './calc_auto_interval'; import { parseInterval } from '../../../common/util/parse_interval'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx index d4a060359b146..200c332d7aa1d 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiDatePicker, EuiDatePickerRange } from '@elastic/eui'; import { Moment } from 'moment'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; import { useSeriesStorage } from '../hooks/use_series_storage'; import { useUiSetting } from '../../../../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/observability/public/utils/date.ts b/x-pack/plugins/observability/public/utils/date.ts index b694bd61d39a9..5839adf92618b 100644 --- a/x-pack/plugins/observability/public/utils/date.ts +++ b/x-pack/plugins/observability/public/utils/date.ts @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; export function getAbsoluteTime(range: string, opts: Parameters[1] = {}) { const parsed = datemath.parse(range, opts); diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx index 004c82d2c3f3f..96bb1c6289b4a 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.tsx +++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx @@ -7,7 +7,7 @@ import querystring from 'querystring'; import React from 'react'; -import { renderToStaticMarkup } from 'react-dom/server'; +import { renderToString } from 'react-dom/server'; import type { Observable, Subscription } from 'rxjs'; import type { @@ -178,7 +178,7 @@ export class AuthorizationService { http.registerOnPreResponse((request, preResponse, toolkit) => { if (preResponse.statusCode === 403 && canRedirectRequest(request)) { const next = `${http.basePath.get(request)}${request.url.pathname}${request.url.search}`; - const body = renderToStaticMarkup( + const body = renderToString( - - - - {title}} - body={body} - actions={actions} - /> - - - + + + + + {title}} + body={body} + actions={actions} + /> + + + + diff --git a/x-pack/plugins/security_solution/public/app/deep_links/index.ts b/x-pack/plugins/security_solution/public/app/deep_links/index.ts index a6eb2f04a6c75..c80f2ca282f47 100644 --- a/x-pack/plugins/security_solution/public/app/deep_links/index.ts +++ b/x-pack/plugins/security_solution/public/app/deep_links/index.ts @@ -207,6 +207,14 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [ }), path: `${HOSTS_PATH}/uncommonProcesses`, }, + { + id: SecurityPageName.hostsAnomalies, + title: i18n.translate('xpack.securitySolution.search.hosts.anomalies', { + defaultMessage: 'Anomalies', + }), + path: `${HOSTS_PATH}/anomalies`, + isPremium: true, + }, { id: SecurityPageName.hostsEvents, title: i18n.translate('xpack.securitySolution.search.hosts.events', { @@ -222,12 +230,12 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [ path: `${HOSTS_PATH}/externalAlerts`, }, { - id: SecurityPageName.hostsAnomalies, - title: i18n.translate('xpack.securitySolution.search.hosts.anomalies', { - defaultMessage: 'Anomalies', + id: SecurityPageName.usersRisk, + title: i18n.translate('xpack.securitySolution.search.hosts.risk', { + defaultMessage: 'Hosts by risk', }), - path: `${HOSTS_PATH}/anomalies`, - isPremium: true, + path: `${HOSTS_PATH}/hostRisk`, + experimentalKey: 'riskyHostsEnabled', }, { id: SecurityPageName.sessions, @@ -319,7 +327,7 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [ { id: SecurityPageName.usersRisk, title: i18n.translate('xpack.securitySolution.search.users.risk', { - defaultMessage: 'Risk', + defaultMessage: 'Users by risk', }), path: `${USERS_PATH}/userRisk`, experimentalKey: 'riskyUsersEnabled', diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index b3948681c491c..7dfa75d6daaa2 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -32,7 +32,10 @@ import { useFieldBrowserOptions, FieldEditorActions, } from '../../../timelines/components/fields_browser'; -import { useSessionView } from '../../../timelines/components/timeline/session_tab_content/use_session_view'; +import { + useSessionViewNavigation, + useSessionView, +} from '../../../timelines/components/timeline/session_tab_content/use_session_view'; const EMPTY_CONTROL_COLUMNS: ControlColumnProps[] = []; @@ -157,7 +160,11 @@ const StatefulEventsViewerComponent: React.FC = ({ const globalFilters = useMemo(() => [...filters, ...(pageFilters ?? [])], [filters, pageFilters]); const trailingControlColumns: ControlColumnProps[] = EMPTY_CONTROL_COLUMNS; - const { DetailsPanel, SessionView, Navigation } = useSessionView({ + const { Navigation } = useSessionViewNavigation({ + timelineId: id, + }); + + const { DetailsPanel, SessionView } = useSessionView({ entityType, timelineId: id, }); diff --git a/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx b/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx index dc2ba963972a1..879a735b33004 100644 --- a/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { EuiSuperDatePicker, OnRefreshChangeProps, diff --git a/x-pack/plugins/security_solution/public/common/components/url_state/normalize_time_range.test.ts b/x-pack/plugins/security_solution/public/common/components/url_state/normalize_time_range.test.ts index a87b1206c0082..c5c18a10922a1 100644 --- a/x-pack/plugins/security_solution/public/common/components/url_state/normalize_time_range.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/url_state/normalize_time_range.test.ts @@ -13,7 +13,7 @@ import { RelativeTimeRange, isRelativeTimeRange, } from '../../store/inputs/model'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { getTimeRangeSettings } from '../../utils/default_date_settings'; const getTimeRangeSettingsMock = getTimeRangeSettings as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/common/hooks/eql/helpers.ts b/x-pack/plugins/security_solution/public/common/hooks/eql/helpers.ts index 7594696336eda..63c1dd7f2d927 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/eql/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/eql/helpers.ts @@ -6,7 +6,7 @@ */ import moment from 'moment'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { inputsModel } from '../../../common/store'; import type { EqlSearchStrategyResponse } from '../../../../../../../src/plugins/data/common'; diff --git a/x-pack/plugins/security_solution/public/common/hooks/eql/types.ts b/x-pack/plugins/security_solution/public/common/hooks/eql/types.ts index 4bf5aa73863df..06fb0e1c72b3e 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/eql/types.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/eql/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { InspectResponse } from '../../../types'; import { ChartData } from '../../components/charts/common'; diff --git a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.test.ts b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.test.ts index 00edace90b7fd..36246cc602f11 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.test.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { renderHook, act } from '@testing-library/react-hooks'; import { of, throwError } from 'rxjs'; import { delay } from 'rxjs/operators'; diff --git a/x-pack/plugins/security_solution/public/common/utils/default_date_settings.ts b/x-pack/plugins/security_solution/public/common/utils/default_date_settings.ts index ed747dbcf22bb..3743560698378 100644 --- a/x-pack/plugins/security_solution/public/common/utils/default_date_settings.ts +++ b/x-pack/plugins/security_solution/public/common/utils/default_date_settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment'; import { isBoolean, isNumber, isString } from 'lodash/fp'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx index 95042ac776875..1c3c010c972f7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx @@ -10,7 +10,7 @@ import { getOr, isEmpty } from 'lodash/fp'; import moment from 'moment'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FilterStateStore, Filter } from '@kbn/es-query'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts index b57af8ede2fef..f4e58c0d34c74 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts @@ -8,7 +8,7 @@ import { Position, ScaleType } from '@elastic/charts'; import { EuiSelectOption } from '@elastic/eui'; import { Type, Language, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import type { Filter } from '@kbn/es-query'; import * as i18n from './translations'; import { histogramDateTimeFormatter } from '../../../../common/components/utils'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx index 2dac0b68b0299..a870b837a7d33 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useEffect, useMemo } from 'react'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { ThreatMapping, Type } from '@kbn/securitysolution-io-ts-alerting-types'; import styled from 'styled-components'; import { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.tsx index 3b640592535b6..326811783fc4a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useMemo } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { EuiFlexGroup, EuiFlexItem, EuiText, EuiSpacer, EuiLoadingChart } from '@elastic/eui'; import styled from 'styled-components'; import { Type } from '@kbn/securitysolution-io-ts-alerting-types'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx index d5278144cf70a..4e05327d74981 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx @@ -6,7 +6,7 @@ */ import { useEffect, useState, useCallback } from 'react'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { Type, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import { FieldValueQueryBar } from '../query_bar'; import { usePreviewRule } from '../../../containers/detection_engine/rules/use_preview_rule'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts index a75558b8a8a1a..7223e11eed76d 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts @@ -6,7 +6,7 @@ */ import { camelCase } from 'lodash'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { HttpStart } from 'src/core/public'; import { diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_preview_rule.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_preview_rule.ts index b610e96273ebd..3d813c8d10a68 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_preview_rule.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_preview_rule.ts @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { RULE_PREVIEW_FROM, RULE_PREVIEW_INTERVAL, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts index e18886166f470..49f8b386108b1 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts @@ -6,7 +6,7 @@ */ import { has, isEmpty } from 'lodash/fp'; -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import moment from 'moment'; import deepmerge from 'deepmerge'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx index e5381757670ea..166395673e726 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx @@ -35,8 +35,6 @@ import { import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; describe('rule helpers', () => { - // @ts-expect-error 4.3.5 upgrade - likely requires moment upgrade - // https://github.com/elastic/kibana/issues/120236 moment.suppressDeprecationWarnings = true; describe('getStepsData', () => { test('returns object with about, define, schedule and actions step properties formatted', () => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 39a6b12d63132..d91eed9301ae4 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment'; import memoizeOne from 'memoize-one'; import { useLocation } from 'react-router-dom'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts index 1bfb99c68ef66..96687895b99c6 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment'; import { HostInfo, HostMetadata } from '../../../../common/endpoint/types'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx index a57fa8d8e4ce5..423f6188c1b8c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx @@ -8,7 +8,7 @@ import { useDispatch } from 'react-redux'; import React, { memo, useCallback } from 'react'; import styled from 'styled-components'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { EuiFlexGroup, EuiFlexItem, diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx index e5aef07754f48..2087bb1a5e511 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { useMemo, useEffect } from 'react'; +import React, { useMemo, useEffect, useRef, useLayoutEffect } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiLoadingSpinner } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { useGlobalFullScreen, useTimelineFullScreen, @@ -29,20 +30,28 @@ import { SourcererScopeName } from '../../../common/store/sourcerer/model'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { sourcererSelectors } from '../../../common/store'; -const OverlayContainer = styled.div` +const OverlayStyle = css` display: flex; flex-direction: column; flex: 1; width: 100%; `; -const FullScreenOverlayContainer = styled.div` +const OverlayContainer = styled.div` + ${OverlayStyle} +`; + +const FullScreenOverlayStyles = css` position: fixed; top: 0; bottom: 0; left: 0; right: 0; - z-index: ${(props) => props.theme.eui.euiZLevel3}; + z-index: ${euiThemeVars.euiZLevel3}; +`; + +const FullScreenOverlayContainer = styled.div` + ${FullScreenOverlayStyles} `; const StyledResolver = styled(Resolver)` @@ -134,26 +143,25 @@ const GraphOverlayComponent: React.FC = ({ [defaultDataView.patternList, isInTimeline, timelinePatterns] ); - if (!isInTimeline && sessionViewConfig !== null) { - if (fullScreen) { - return ( - - - {Navigation} - {SessionView} - - - ); - } else { - return ( - - - {Navigation} - {SessionView} - - - ); + const sessionContainerRef = useRef(null); + + useLayoutEffect(() => { + if (fullScreen && sessionContainerRef.current) { + sessionContainerRef.current.setAttribute('style', FullScreenOverlayStyles.join('')); + } else if (sessionContainerRef.current) { + sessionContainerRef.current.setAttribute('style', OverlayStyle.join('')); } + }, [fullScreen]); + + if (!isInTimeline && sessionViewConfig !== null) { + return ( + + + {Navigation} + {SessionView} + + + ); } else if (fullScreen && !isInTimeline) { return ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx index adedda3a5f253..b835c87308e15 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx @@ -12,7 +12,7 @@ import { timelineSelectors } from '../../../store/timeline'; import { useShallowEqualSelector } from '../../../../common/hooks/use_selector'; import { TimelineId } from '../../../../../common/types/timeline'; import { GraphOverlay } from '../../graph_overlay'; -import { useSessionView } from '../session_tab_content/use_session_view'; +import { useSessionViewNavigation, useSessionView } from '../session_tab_content/use_session_view'; interface GraphTabContentProps { timelineId: TimelineId; @@ -35,7 +35,11 @@ const GraphTabContentComponent: React.FC = ({ timelineId } (state) => getTimeline(state, timelineId)?.graphEventId ); - const { shouldShowDetailsPanel, DetailsPanel, Navigation, SessionView } = useSessionView({ + const { Navigation } = useSessionViewNavigation({ + timelineId, + }); + + const { shouldShowDetailsPanel, DetailsPanel, SessionView } = useSessionView({ timelineId, }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/index.tsx index 8035dda95081f..324c13d320f45 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/index.tsx @@ -9,9 +9,10 @@ import React, { useState, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; import { TimelineId } from '../../../../../common/types/timeline'; -import { useSessionView } from './use_session_view'; +import { useSessionViewNavigation, useSessionView } from './use_session_view'; const FlexItemWithMargin = styled(EuiFlexItem)` + width: 100%; ${({ theme }) => `margin: 0 ${theme.eui.euiSizeM};`} `; @@ -43,7 +44,10 @@ const SessionTabContent: React.FC = ({ timelineId }) => { setHeight(node.getBoundingClientRect().height); } }, []); - const { SessionView, shouldShowDetailsPanel, DetailsPanel, Navigation } = useSessionView({ + const { Navigation } = useSessionViewNavigation({ + timelineId, + }); + const { SessionView, shouldShowDetailsPanel, DetailsPanel } = useSessionView({ timelineId, height, }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx index 3e1f087a0d726..12fedad3b225e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx @@ -17,7 +17,7 @@ import { useTimelineFullScreen, useGlobalFullScreen, } from '../../../../common/containers/use_full_screen'; -import { useSessionView } from './use_session_view'; +import { useSessionView, useSessionViewNavigation } from './use_session_view'; const mockDispatch = jest.fn(); jest.mock('../../../../common/hooks/use_selector'); @@ -139,7 +139,7 @@ describe('useSessionView with active timeline and a session id and graph event i const testProps = { timelineId: TimelineId.active, }; - return useSessionView(testProps); + return useSessionViewNavigation(testProps); }, { wrapper: Wrapper } ); @@ -194,7 +194,7 @@ describe('useSessionView with active timeline and a session id and graph event i const testProps = { timelineId: TimelineId.hostsPageEvents, }; - return useSessionView(testProps); + return useSessionViewNavigation(testProps); }, { wrapper: Wrapper } ); @@ -203,4 +203,70 @@ describe('useSessionView with active timeline and a session id and graph event i expect(renderResult.getByText('Close analyzer')).toBeTruthy(); }); }); + + describe('useSessionView and useSessionViewNavigation should handle separate parts', () => { + beforeEach(() => { + setTimelineFullScreen = jest.fn(); + setGlobalFullScreen = jest.fn(); + (useTimelineFullScreen as jest.Mock).mockImplementation(() => ({ + setTimelineFullScreen, + })); + (useGlobalFullScreen as jest.Mock).mockImplementation(() => ({ + setGlobalFullScreen, + })); + (useDeepEqualSelector as jest.Mock).mockImplementation(() => { + return { + ...mockTimelineModel, + activeTab: TimelineTabs.session, + graphEventId: 'current-graph-event-id', + sessionViewConfig: { + sessionEntityId: 'test', + }, + show: true, + }; + }); + }); + afterEach(() => { + (useDeepEqualSelector as jest.Mock).mockClear(); + }); + it('useSessionView should handle session view and details panel', () => { + const { result } = renderHook( + () => { + const testProps = { + timelineId: TimelineId.active, + }; + return useSessionView(testProps); + }, + { wrapper: Wrapper } + ); + expect(kibana.services.sessionView.getSessionView).toHaveBeenCalled(); + + expect(result.current).toHaveProperty('openDetailsPanel'); + expect(result.current).toHaveProperty('shouldShowDetailsPanel'); + expect(result.current).toHaveProperty('SessionView'); + expect(result.current).toHaveProperty('DetailsPanel'); + + expect(result.current).not.toHaveProperty('Navigation'); + expect(result.current).not.toHaveProperty('onCloseOverlay'); + }); + + it('useSessionViewNavigation should handle Navigation component and on close callback', () => { + const { result } = renderHook( + () => { + const testProps = { + timelineId: TimelineId.hostsPageEvents, + }; + return useSessionViewNavigation(testProps); + }, + { wrapper: Wrapper } + ); + expect(result.current).toHaveProperty('Navigation'); + expect(result.current).toHaveProperty('onCloseOverlay'); + + expect(result.current).not.toHaveProperty('openDetailsPanel'); + expect(result.current).not.toHaveProperty('shouldShowDetailsPanel'); + expect(result.current).not.toHaveProperty('SessionView'); + expect(result.current).not.toHaveProperty('DetailsPanel'); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx index 370509e4c88dc..693429ac9fc8c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx @@ -46,6 +46,7 @@ export interface SessionViewConfig { const FullScreenButtonIcon = styled(EuiButtonIcon)` margin: 4px 0 4px 0; `; + interface NavigationProps { fullScreen: boolean; globalFullScreen: boolean; @@ -106,16 +107,7 @@ NavigationComponent.displayName = 'NavigationComponent'; const Navigation = React.memo(NavigationComponent); -export const useSessionView = ({ - timelineId, - entityType, - height, -}: { - timelineId: TimelineId; - entityType?: EntityType; - height?: number; -}) => { - const { sessionView } = useKibana().services; +export const useSessionViewNavigation = ({ timelineId }: { timelineId: TimelineId }) => { const dispatch = useDispatch(); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); @@ -187,6 +179,60 @@ export const useSessionView = ({ setGlobalFullScreen, globalFullScreen, ]); + const navigation = useMemo(() => { + return ( + + ); + }, [ + fullScreen, + globalFullScreen, + activeTab, + graphEventId, + onCloseOverlay, + timelineFullScreen, + timelineId, + toggleFullScreen, + ]); + + return { + onCloseOverlay, + Navigation: navigation, + }; +}; + +export const useSessionView = ({ + timelineId, + entityType, + height, +}: { + timelineId: TimelineId; + entityType?: EntityType; + height?: number; +}) => { + const { sessionView } = useKibana().services; + const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); + + const { globalFullScreen } = useGlobalFullScreen(); + const { timelineFullScreen } = useTimelineFullScreen(); + + const { sessionViewConfig, activeTab } = useDeepEqualSelector( + (state) => getTimeline(state, timelineId) ?? timelineDefaults + ); + + const fullScreen = useMemo( + () => isFullScreen({ globalFullScreen, timelineId, timelineFullScreen }), + [globalFullScreen, timelineId, timelineFullScreen] + ); + const sourcererScope = useMemo(() => { if (timelineId === TimelineId.active) { return SourcererScopeName.timeline; @@ -217,36 +263,10 @@ export const useSessionView = ({ : null; }, [fullScreen, openDetailsPanel, sessionView, sessionViewConfig, height]); - const navigation = useMemo(() => { - return ( - - ); - }, [ - fullScreen, - globalFullScreen, - activeTab, - graphEventId, - onCloseOverlay, - timelineFullScreen, - timelineId, - toggleFullScreen, - ]); - return { - onCloseOverlay, openDetailsPanel, shouldShowDetailsPanel, SessionView: sessionViewComponent, DetailsPanel, - Navigation: navigation, }; }; diff --git a/x-pack/plugins/security_solution/public/transforms/utils/adjust_timerange.ts b/x-pack/plugins/security_solution/public/transforms/utils/adjust_timerange.ts index e9334379d7b0b..464ccd8692512 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/adjust_timerange.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/adjust_timerange.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment, { Duration } from 'moment'; import type { TimerangeInput } from '../../../common/search_strategy'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts index e7810e6fe0078..288fd7a688e3c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { eqlExecutor } from './eql'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts index 417382b0bd05a..bc756bf9681e3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { mlExecutor } from './ml'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts index 14c56aa3bc9be..01e61b6917cc4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/find_ml_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/find_ml_signals.ts index 10f89b56229dc..7d2041d86e395 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/find_ml_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/find_ml_signals.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { KibanaRequest, SavedObjectsClientContract } from '../../../../../../../src/core/server'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index 02ed86b65e878..3b0d5d17b4445 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -18,7 +18,6 @@ import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; -// @ts-expect-error 4.3.5 upgrade - likely requires moment upgrade moment.suppressDeprecationWarnings = true; import { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index a0d73707466ce..738a9d9dd0c50 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -9,7 +9,7 @@ import { chunk, get, invert, isEmpty, partition } from 'lodash'; import moment from 'moment'; import uuidv5 from 'uuid/v5'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { TransportResult } from '@elastic/elasticsearch'; import { ALERT_UUID, ALERT_RULE_UUID, ALERT_RULE_PARAMETERS } from '@kbn/rule-data-utils'; diff --git a/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts b/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts index df16f26730d98..581134eae1782 100644 --- a/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts +++ b/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts @@ -1325,6 +1325,7 @@ export const childProcessMock: Process = { } as ProcessEvent), isUserEntered: () => false, getMaxAlertLevel: () => null, + getEndTime: () => '', }; export const processMock: Process = { @@ -1497,6 +1498,7 @@ export const processMock: Process = { } as ProcessEvent), isUserEntered: () => false, getMaxAlertLevel: () => null, + getEndTime: () => '', }; export const sessionViewBasicProcessMock: Process = { @@ -1504,6 +1506,7 @@ export const sessionViewBasicProcessMock: Process = { events: mockEvents, hasExec: () => true, isUserEntered: () => true, + getEndTime: () => '', }; export const sessionViewAlertProcessMock: Process = { @@ -1514,6 +1517,7 @@ export const sessionViewAlertProcessMock: Process = { getAlerts: () => mockAlerts, hasExec: () => true, isUserEntered: () => true, + getEndTime: () => '', }; export const mockProcessMap = mockEvents.reduce( @@ -1540,6 +1544,7 @@ export const mockProcessMap = mockEvents.reduce( getDetails: () => event, isUserEntered: () => false, getMaxAlertLevel: () => null, + getEndTime: () => '', }; return processMap; }, diff --git a/x-pack/plugins/session_view/common/types/process_tree/index.ts b/x-pack/plugins/session_view/common/types/process_tree/index.ts index 2020884b141a6..c4cb85a81dd0c 100644 --- a/x-pack/plugins/session_view/common/types/process_tree/index.ts +++ b/x-pack/plugins/session_view/common/types/process_tree/index.ts @@ -76,6 +76,11 @@ export interface ProcessFields { end?: string; user?: User; group?: Group; + real_user?: User; + real_group?: Group; + saved_user?: User; + saved_group?: Group; + supplemental_groups?: Group[]; exit_code?: number; entry_meta?: EntryMeta; tty?: Teletype; @@ -173,6 +178,7 @@ export interface Process { isUserEntered(): boolean; getMaxAlertLevel(): number | null; getChildren(verboseMode: boolean): Process[]; + getEndTime(): string; } export type ProcessMap = { diff --git a/x-pack/plugins/session_view/public/components/process_tree/helpers.ts b/x-pack/plugins/session_view/public/components/process_tree/helpers.ts index 064f11c10a736..2f383271f498d 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/helpers.ts +++ b/x-pack/plugins/session_view/public/components/process_tree/helpers.ts @@ -170,11 +170,11 @@ export const searchProcessTree = (processMap: ProcessMap, searchQuery: string | // b) matches the plain text search above // Returns the processMap with it's processes autoExpand bool set to true or false // process.autoExpand is read by process_tree_node to determine whether to auto expand it's child processes. -export const autoExpandProcessTree = (processMap: ProcessMap) => { +export const autoExpandProcessTree = (processMap: ProcessMap, jumpToEntityId?: string) => { for (const processId of Object.keys(processMap)) { const process = processMap[processId]; - if (process.searchMatched || process.isUserEntered()) { + if (process.searchMatched || process.isUserEntered() || jumpToEntityId === process.id) { let { parent } = process; const parentIdSet = new Set(); diff --git a/x-pack/plugins/session_view/public/components/process_tree/hooks.ts b/x-pack/plugins/session_view/public/components/process_tree/hooks.ts index 009b839f6d55c..1725abdcdb5b9 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/hooks.ts +++ b/x-pack/plugins/session_view/public/components/process_tree/hooks.ts @@ -31,6 +31,7 @@ interface UseProcessTreeDeps { alerts: ProcessEvent[]; searchQuery?: string; updatedAlertsStatus: AlertStatusEventEntityIdMap; + jumpToEntityId?: string; } export class ProcessImpl implements Process { @@ -147,11 +148,8 @@ export class ProcessImpl implements Process { } getEndTime() { - const endEvent = this.filterEventsByAction(this.events, EventAction.end); - if (endEvent.length === 0) { - return ''; - } - return endEvent[endEvent.length - 1]['@timestamp']; + const endEvent = this.findEventByAction(this.events, EventAction.end); + return endEvent?.['@timestamp'] || ''; } // isUserEntered is a best guess at which processes were initiated by a real person @@ -231,6 +229,7 @@ export const useProcessTree = ({ alerts, searchQuery, updatedAlertsStatus, + jumpToEntityId, }: UseProcessTreeDeps) => { // initialize map, as well as a placeholder for session leader process // we add a fake session leader event, sourced from wide event data. @@ -305,8 +304,8 @@ export const useProcessTree = ({ useEffect(() => { setSearchResults(searchProcessTree(processMap, searchQuery)); - autoExpandProcessTree(processMap); - }, [searchQuery, processMap]); + autoExpandProcessTree(processMap, jumpToEntityId); + }, [searchQuery, processMap, jumpToEntityId]); // set new orphans array on the session leader const sessionLeader = processMap[sessionEntityId]; diff --git a/x-pack/plugins/session_view/public/components/process_tree/index.tsx b/x-pack/plugins/session_view/public/components/process_tree/index.tsx index b8c9bbc77c9b1..158e5b8faa24a 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/index.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree/index.tsx @@ -96,6 +96,7 @@ export const ProcessTree = ({ alerts, searchQuery, updatedAlertsStatus, + jumpToEntityId, }); const eventsRemaining = useMemo(() => { diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/index.test.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/index.test.tsx index 81b3c184baaa4..7a3e3f775d992 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/index.test.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/index.test.tsx @@ -64,7 +64,7 @@ describe('ProcessTreeNode component', () => { // expect(renderResult.queryByText(/orphaned/i)).toBeTruthy(); // }); - it('renders Exec icon and exit code for executed process', async () => { + it('renders Exec icon', async () => { const executedProcessMock: typeof processMock = { ...processMock, hasExec: () => true, @@ -75,26 +75,6 @@ describe('ProcessTreeNode component', () => { ); expect(renderResult.queryByTestId('sessionView:processTreeNodeExecIcon')).toBeTruthy(); - expect(renderResult.queryByTestId('sessionView:processTreeNodeExitCode')).toBeTruthy(); - }); - - it('does not render exit code if it does not exist', async () => { - const processWithoutExitCode: typeof processMock = { - ...processMock, - hasExec: () => true, - getDetails: () => ({ - ...processMock.getDetails(), - process: { - ...processMock.getDetails().process, - exit_code: undefined, - }, - }), - }; - - renderResult = mockedContext.render( - - ); - expect(renderResult.queryByTestId('sessionView:processTreeNodeExitCode')).toBeFalsy(); }); it('calls onChangeJumpToEventVisibility with isVisible false if jumpToEvent is not visible', async () => { diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx index b835d1d0e035d..208a0c6fbfd5b 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx @@ -209,7 +209,6 @@ export function ProcessTreeNode({ tty, parent, working_directory: workingDirectory, - exit_code: exitCode, start, } = processDetails.process; @@ -249,6 +248,11 @@ export function ProcessTreeNode({ ) : ( + {timeStampOn && ( + + {timeStampsNormal} + + )} {' '} @@ -256,18 +260,7 @@ export function ProcessTreeNode({ {dataOrDash(workingDirectory)}  {dataOrDash(args?.[0])}{' '} {args?.slice(1).join(' ')} - {exitCode !== undefined && ( - - {' '} - [exit_code: {exitCode}] - - )} - {timeStampOn && ( - - {timeStampsNormal} - - )} )} diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index 6ba0901e973bf..1e41878814697 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -62,7 +62,7 @@ export const SessionView = ({ LOCAL_STORAGE_DISPLAY_OPTIONS_KEY, { timestamp: true, - verboseMode: true, + verboseMode: false, } ); const [fetchAlertStatus, setFetchAlertStatus] = useState([]); diff --git a/x-pack/plugins/session_view/public/components/session_view_detail_panel/helpers.ts b/x-pack/plugins/session_view/public/components/session_view_detail_panel/helpers.ts index a96330a35b084..083bc35ac49d4 100644 --- a/x-pack/plugins/session_view/public/components/session_view_detail_panel/helpers.ts +++ b/x-pack/plugins/session_view/public/components/session_view_detail_panel/helpers.ts @@ -6,7 +6,6 @@ */ import { EventAction, Process, ProcessFields } from '../../../common/types/process_tree'; import { DetailPanelProcess, EuiTabProps } from '../../types'; -import { ProcessImpl } from '../process_tree/hooks'; const FILTER_FORKS_EXECS = [EventAction.fork, EventAction.exec]; @@ -57,33 +56,39 @@ export const getDetailPanelProcess = (process: Process | undefined) => { }; } - const endProcesses = new ProcessImpl(process.id); + const details = process.getDetails(); processData.id = process.id; - processData.start = process.events[0]?.['@timestamp'] ?? ''; + processData.start = details.process?.start ?? ''; processData.args = []; processData.executable = []; - process.events.forEach((event) => { - if (!processData.userName) { - processData.userName = event.user?.name ?? ''; - } - if (!processData.groupName) { - processData.groupName = event.group?.name ?? ''; - } - if (!processData.pid) { - processData.pid = event.process?.pid; - } - if (!processData.working_directory) { - processData.working_directory = event.process?.working_directory ?? ''; - } - if (!processData.tty) { - processData.tty = event.process?.tty; - } + if (!processData.userName) { + processData.userName = details.process?.user?.name ?? ''; + } + if (!processData.groupName) { + processData.groupName = details.process?.group?.name ?? ''; + } + if (!processData.pid) { + processData.pid = details.process?.pid; + } + if (!processData.working_directory) { + processData.working_directory = details.process?.working_directory ?? ''; + } + if (!processData.tty) { + processData.tty = details.process?.tty; + } + if (details.process?.args && details.process.args.length > 0) { + processData.args = details.process.args; + } + if (details.process?.exit_code !== undefined) { + processData.exit_code = details.process.exit_code; + } - if (event.process?.args && event.process.args.length > 0) { - processData.args = event.process.args; - } + // we grab the executable from each process lifecycle event to give an indication + // of the processes journey. Processes can sometimes exec multiple times, so it's good + // information to have. + process.events.forEach((event) => { if ( event.process?.executable && event.event?.action && @@ -91,19 +96,13 @@ export const getDetailPanelProcess = (process: Process | undefined) => { ) { processData.executable.push([event.process.executable, `(${event.event.action})`]); } - if (event.process?.exit_code !== undefined) { - processData.exit_code = event.process.exit_code; - } - endProcesses.addEvent(event); }); - processData.end = endProcesses.getEndTime() as string; - processData.entryLeader = getDetailPanelProcessLeader(process.events[0]?.process?.entry_leader); - processData.sessionLeader = getDetailPanelProcessLeader( - process.events[0]?.process?.session_leader - ); - processData.groupLeader = getDetailPanelProcessLeader(process.events[0]?.process?.group_leader); - processData.parent = getDetailPanelProcessLeader(process.events[0]?.process?.parent); + processData.end = process.getEndTime(); + processData.entryLeader = getDetailPanelProcessLeader(details?.process?.entry_leader); + processData.sessionLeader = getDetailPanelProcessLeader(details?.process?.session_leader); + processData.groupLeader = getDetailPanelProcessLeader(details?.process?.group_leader); + processData.parent = getDetailPanelProcessLeader(details?.process?.parent); return processData; }; diff --git a/x-pack/plugins/session_view/public/components/session_view_detail_panel/index.tsx b/x-pack/plugins/session_view/public/components/session_view_detail_panel/index.tsx index c2e8eec173422..86cfacfb72d06 100644 --- a/x-pack/plugins/session_view/public/components/session_view_detail_panel/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view_detail_panel/index.tsx @@ -105,7 +105,7 @@ export const SessionViewDetailPanel = ({ const styles = useStyles(); return ( -
+
{tabs.map((tab, index) => ( { const { euiTheme } = useEuiTheme(); const cached = useMemo(() => { - const detailsPanelLeftBorder: CSSObject = { - borderLeft: euiTheme.border.thin, + const { border, colors } = euiTheme; + + const detailsPanel: CSSObject = { + borderLeft: border.thin, + backgroundColor: colors.emptyShade, }; return { - detailsPanelLeftBorder, + detailsPanel, }; }, [euiTheme]); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 5fe2512e96ee9..8d800c8ba38aa 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -4294,8 +4294,6 @@ "timelion.help.functions.firstHelpText": "Il s'agit d'une fonction interne qui renvoie simplement la liste de séries d'entrée. Ne l'utilisez pas.", "timelion.help.functions.fit.args.modeHelpText": "L'algorithme à utiliser pour adapter les séries à la cible. L'une des options suivantes : {fitFunctions}.", "timelion.help.functions.fitHelpText": "Remplit les valeurs nulles à l'aide d'une fonction fit définie.", - "timelion.help.functions.graphite.args.metricHelpText": "Indicateur Graphite à extraire, par ex. {metricExample}", - "timelion.help.functions.graphiteHelpText": "[expérimental] Extrayez des données de Graphite. Configurez votre serveur Graphite dans les paramètres avancés de Kibana.", "timelion.help.functions.hide.args.hideHelpText": "Masquer ou afficher les séries", "timelion.help.functions.hideHelpText": "Masquer les séries par défaut", "timelion.help.functions.holt.args.alphaHelpText": "\n Pondération de lissage de 0 à 1.\n Augmentez l’alpha pour que la nouvelle série suive de plus près l'originale.\n Diminuez-le pour rendre la série plus lisse.", @@ -4337,7 +4335,6 @@ "timelion.help.functions.movingstdHelpText": "Calculez l'écart-type mobile pour une fenêtre donnée. Utilise l'algorithme naïf en deux passes. Les erreurs d'arrondi peuvent devenir plus évidentes avec les séries très longues ou celles comportant de très grands nombres.", "timelion.help.functions.multiply.args.multiplierHelpText": "Nombre de séries par lequel multiplier. Une liste de plusieurs séries sera appliquée pour l'étiquette.", "timelion.help.functions.multiplyHelpText": "Multiplie les valeurs d'une ou de plusieurs séries d'une liste de séries à chaque position, dans chaque série, de la liste de séries d'entrée.", - "timelion.help.functions.notAllowedGraphiteUrl": "Cette URL Graphite n'est pas configurée dans le fichier kibana.yml.\n Veuillez configurer votre liste de serveurs Graphite dans le fichier kibana.yml, sous \"timelion.graphiteUrls\", puis\n en sélectionner un dans les paramètres avancés de Kibana.", "timelion.help.functions.points.args.fillColorHelpText": "Couleur à utiliser pour remplir le point", "timelion.help.functions.points.args.fillHelpText": "Nombre compris entre 0 et 10 représentant l'opacité du remplissage", "timelion.help.functions.points.args.radiusHelpText": "Taille des points", @@ -4349,9 +4346,6 @@ "timelion.help.functions.precisionHelpText": "Le nombre de chiffres à garder lors de la troncature de la partie décimale de la valeur", "timelion.help.functions.props.args.globalHelpText": "Définir des propositions sur la liste de séries plutôt que sur chaque série", "timelion.help.functions.propsHelpText": "À utiliser à vos risques et périls ; définit des propriétés arbitraires sur la série. Par exemple : {example}", - "timelion.help.functions.quandl.args.codeHelpText": "Le code Quandl à tracer. Disponible sur quandl.com.", - "timelion.help.functions.quandl.args.positionHelpText": "Certaines sources Quandl renvoient plusieurs séries. Laquelle utiliser ? Index basé sur 1.", - "timelion.help.functions.quandlHelpText": "\n [expérimental]\n Extrayez des données de quandl.com à l'aide du code Quandl. Définissez {quandlKeyField} sur votre clé d'API gratuite dans\n les paramètres avancés de Kibana. La limite de taux de l'API est très basse sans clé.", "timelion.help.functions.range.args.maxHelpText": "Nouvelle valeur maximale", "timelion.help.functions.range.args.minHelpText": "Nouvelle valeur minimale", "timelion.help.functions.rangeHelpText": "Modifie le maximum et le minimum d'une série sans changer la forme.", @@ -4401,7 +4395,6 @@ "timelion.serverSideErrors.movingaverageFunction.notValidPositionErrorMessage": "Les positions valides sont : {validPositions}.", "timelion.serverSideErrors.movingstdFunction.notValidPositionErrorMessage": "Les positions valides sont : {validPositions}.", "timelion.serverSideErrors.pointsFunction.notValidSymbolErrorMessage": "Les symboles valides sont : {validSymbols}.", - "timelion.serverSideErrors.quandlFunction.unsupportedIntervalErrorMessage": "Intervalle non pris en charge par quandl() : {interval}. Les intervalles pris en charge par quandl() sont les suivants : {intervals}.", "timelion.serverSideErrors.sheetParseErrorMessage": "Attendu : {expectedDescription} au caractère {column}", "timelion.serverSideErrors.unknownArgumentErrorMessage": "Argument inconnu pour {functionName} : {argumentName}", "timelion.serverSideErrors.unknownArgumentTypeErrorMessage": "Type d'argument non pris en charge : {argument}", @@ -4412,9 +4405,6 @@ "timelion.timelionDescription": "Affichez des données temporelles sur un graphe.", "timelion.uiSettings.defaultIndexDescription": "Index Elasticsearch par défaut dans lequel rechercher avec {esParam}", "timelion.uiSettings.defaultIndexLabel": "Index par défaut", - "timelion.uiSettings.experimentalLabel": "expérimental", - "timelion.uiSettings.graphiteURLDescription": "{experimentalLabel} L'URL de l'hôte Graphite", - "timelion.uiSettings.graphiteURLLabel": "URL Graphite", "timelion.uiSettings.legacyChartsLibraryDeprication": "Ce paramètre est déclassé et ne sera plus pris en charge à partir de la version 8.0.", "timelion.uiSettings.legacyChartsLibraryDescription": "Active la bibliothèque de graphiques héritée pour les graphiques Timelion dans Visualize.", "timelion.uiSettings.legacyChartsLibraryLabel": "Bibliothèque de graphiques Timelion héritée", @@ -4422,8 +4412,6 @@ "timelion.uiSettings.maximumBucketsLabel": "Nombre maximal de compartiments", "timelion.uiSettings.minimumIntervalDescription": "Le plus petit intervalle qui sera calculé lors de l'utilisation de l'option \"auto\"", "timelion.uiSettings.minimumIntervalLabel": "Intervalle minimum", - "timelion.uiSettings.quandlKeyDescription": "{experimentalLabel} Votre clé d'API de www.quandl.com", - "timelion.uiSettings.quandlKeyLabel": "Clé Quandl", "timelion.uiSettings.targetBucketsDescription": "Le nombre de compartiments visé lors de l'utilisation d'intervalles automatiques", "timelion.uiSettings.targetBucketsLabel": "Compartiments cibles", "timelion.uiSettings.timeFieldDescription": "Champ par défaut contenant un horodatage lors de l'utilisation de {esParam}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index df04c6e4cf4c1..641d7debc580e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5035,8 +5035,6 @@ "timelion.help.functions.firstHelpText": "これは単純に input seriesList を返す内部機能です。この機能は使わないでください", "timelion.help.functions.fit.args.modeHelpText": "数列をターゲットに合わせるためのアルゴリズムです。次のいずれかです。{fitFunctions}", "timelion.help.functions.fitHelpText": "定義された fit 関数を使用して空値を入力します", - "timelion.help.functions.graphite.args.metricHelpText": "取得する Graphite メトリック、例:{metricExample}", - "timelion.help.functions.graphiteHelpText": "[実験的] Graphite からデータを取得します。Kibana の高度な設定で Graphite サーバーを構成します", "timelion.help.functions.hide.args.hideHelpText": "数列の表示と非表示を切り替えます", "timelion.help.functions.hideHelpText": "デフォルトで数列を非表示にします", "timelion.help.functions.holt.args.alphaHelpText": "\n 0 から 1 の平滑化加重です。\n アルファを上げると新しい数列がオリジナルにさらに近くなります。\n 下げると数列がスムーズになります", @@ -5078,7 +5076,6 @@ "timelion.help.functions.movingstdHelpText": "特定期間の移動標準偏差を計算します。ネイティブ two-pass アルゴリズムを使用します。非常に長い数列や、非常に大きな数字を含む数列では、四捨五入による誤差がより明らかになる可能性があります。", "timelion.help.functions.multiply.args.multiplierHelpText": "掛ける数字または数列です。複数数列を含む seriesList はラベルに適用されます。", "timelion.help.functions.multiplyHelpText": "seriesList の 1 つまたは複数の数列の値をインプット seriesList の各数列のそれぞれの配置に掛けます。", - "timelion.help.functions.notAllowedGraphiteUrl": "この Graphite URL は kibana.yml ファイルで構成されていません。\n 「timelion.graphiteUrls」で kibana.yml ファイルの Graphite サーバーリストを構成し、\n Kibana の高度な設定でいずれかを選択してください", "timelion.help.functions.points.args.fillColorHelpText": "点を塗りつぶす色です。", "timelion.help.functions.points.args.fillHelpText": "塗りつぶしの透明度を表す 0 から 10 までの数字です", "timelion.help.functions.points.args.radiusHelpText": "点のサイズです", @@ -5090,9 +5087,6 @@ "timelion.help.functions.precisionHelpText": "値の小数点以下を切り捨てる桁数です", "timelion.help.functions.props.args.globalHelpText": "各数列に対し、seriesList にプロップを設定します", "timelion.help.functions.propsHelpText": "数列に任意のプロパティを設定するため、自己責任で行ってください。例:{example}。", - "timelion.help.functions.quandl.args.codeHelpText": "プロットする Quandl コードです。これらは quandl.com に掲載されています。", - "timelion.help.functions.quandl.args.positionHelpText": "Quandl ソースによっては、複数数列を返すものがあります。どれを使用しますか?1 ベースインデックス", - "timelion.help.functions.quandlHelpText": "\n [実験的]\n Quandl コードで quandl.com からデータを取得します。Kibana で {quandlKeyField} を空き API キーに設定\n 高度な設定API は、キーなしでは非常に低いレート制限があります。", "timelion.help.functions.range.args.maxHelpText": "新しい最高値です", "timelion.help.functions.range.args.minHelpText": "新しい最低値です", "timelion.help.functions.rangeHelpText": "同じシェイプを維持しつつ数列の最高値と最低値を変更します", @@ -5143,7 +5137,6 @@ "timelion.serverSideErrors.movingaverageFunction.notValidPositionErrorMessage": "有効な配置:{validPositions}", "timelion.serverSideErrors.movingstdFunction.notValidPositionErrorMessage": "有効な配置:{validPositions}", "timelion.serverSideErrors.pointsFunction.notValidSymbolErrorMessage": "有効なシンボル:{validSymbols}", - "timelion.serverSideErrors.quandlFunction.unsupportedIntervalErrorMessage": "quandl()でサポートされていない間隔:{interval}. quandl()でサポートされている間隔:{intervals}", "timelion.serverSideErrors.sheetParseErrorMessage": "予想:文字 {column} で {expectedDescription}", "timelion.serverSideErrors.unknownArgumentErrorMessage": "{functionName} への不明な引数:{argumentName}", "timelion.serverSideErrors.unknownArgumentTypeErrorMessage": "引数タイプがサポートされていません:{argument}", @@ -5154,9 +5147,6 @@ "timelion.timelionDescription": "グラフに時系列データを表示します。", "timelion.uiSettings.defaultIndexDescription": "{esParam} で検索するデフォルトの Elasticsearch インデックスです", "timelion.uiSettings.defaultIndexLabel": "デフォルトのインデックス", - "timelion.uiSettings.experimentalLabel": "テクニカルプレビュー", - "timelion.uiSettings.graphiteURLDescription": "{experimentalLabel} Graphite ホストの URL", - "timelion.uiSettings.graphiteURLLabel": "Graphite URL", "timelion.uiSettings.legacyChartsLibraryDeprication": "この設定はサポートが終了し、将来のバージョンではサポートされません。", "timelion.uiSettings.legacyChartsLibraryDescription": "VisualizeでTimelionグラフのレガシーグラフライブラリを有効にします", "timelion.uiSettings.legacyChartsLibraryLabel": "Timelionレガシーグラフライブラリ", @@ -5164,8 +5154,6 @@ "timelion.uiSettings.maximumBucketsLabel": "バケットの最大数", "timelion.uiSettings.minimumIntervalDescription": "「auto」を使用時に計算される最小の間隔です", "timelion.uiSettings.minimumIntervalLabel": "最低間隔", - "timelion.uiSettings.quandlKeyDescription": "{experimentalLabel} www.quandl.com からの API キーです", - "timelion.uiSettings.quandlKeyLabel": "Quandl キー", "timelion.uiSettings.targetBucketsDescription": "自動間隔の使用時に目標となるバケット数です。", "timelion.uiSettings.targetBucketsLabel": "目標バケット数", "timelion.uiSettings.timeFieldDescription": "{esParam} の使用時にタイムスタンプを含むデフォルトのフィールドです", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index dd4b6d7f4bb75..059e2f68cd5f2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5043,8 +5043,6 @@ "timelion.help.functions.firstHelpText": "这是内部函数,只返回输入 seriesList。请勿使用", "timelion.help.functions.fit.args.modeHelpText": "用于将序列拟合到目标的算法。以下之一:{fitFunctions}", "timelion.help.functions.fitHelpText": "使用已定义的拟合函数填充 null 值", - "timelion.help.functions.graphite.args.metricHelpText": "要拉取的 Graphite 指标,例如 {metricExample}", - "timelion.help.functions.graphiteHelpText": "[实验性] 从 Graphite 拉取数据。在 Kibana 的“高级设置”中配置 Graphite 服务器", "timelion.help.functions.hide.args.hideHelpText": "隐藏或取消隐藏序列", "timelion.help.functions.hideHelpText": "默认隐藏序列", "timelion.help.functions.holt.args.alphaHelpText": "\n 平滑权重,0 到 1。\n 增加 alpha 值会使新序列更接近原始序列。\n 降低 alpha 值会使序列更平滑", @@ -5086,7 +5084,6 @@ "timelion.help.functions.movingstdHelpText": "计算特定时间窗的移动标准偏差。使用朴素的扫描两遍算法。对于极长的序列,或含有极大数的序列,舍入误差可能会更明显。", "timelion.help.functions.multiply.args.multiplierHelpText": "要乘以的数字或序列。具有多个序列的 seriesList 以标签方式进行应用。", "timelion.help.functions.multiplyHelpText": "将 seriesList 中一个或多个序列的值乘以输入 seriesList 的每个序列中的每个位置", - "timelion.help.functions.notAllowedGraphiteUrl": "在 kibana.yml 文件中未配置此 Graphite URL。\n 请在 kibana.yml 文件中“timelion.graphiteUrls”下配置 Graphite 服务器列表,并\n 从 Kibana 的“高级设置”中选择一个", "timelion.help.functions.points.args.fillColorHelpText": "用于填充点的颜色", "timelion.help.functions.points.args.fillHelpText": "介于 0 到 10 之间的数字,代表填充的不透明度", "timelion.help.functions.points.args.radiusHelpText": "点的大小", @@ -5098,9 +5095,6 @@ "timelion.help.functions.precisionHelpText": "将值的小数部分截断至的位数", "timelion.help.functions.props.args.globalHelpText": "在 seriesList 与每个序列上设置属性", "timelion.help.functions.propsHelpText": "在序列上可设置任意属性,但请自担风险。例如 {example}", - "timelion.help.functions.quandl.args.codeHelpText": "用于绘图的 quandl 代码。可以在 quandl.com 找到这些内容。", - "timelion.help.functions.quandl.args.positionHelpText": "某些 quandl 源代码会返回多个序列,我该使用哪一个?从 1 开始 的索引。", - "timelion.help.functions.quandlHelpText": "\n [实验性]\n 使用 quandl 代码从 quandl.com 拉取数据。在 Kibana 的“高级设置”中将 {quandlKeyField} 设置为\n 免费的 API 密钥。API 在没有密钥的情况下,会有非常低的速率限制。", "timelion.help.functions.range.args.maxHelpText": "新的最大值", "timelion.help.functions.range.args.minHelpText": "新的最小值", "timelion.help.functions.rangeHelpText": "保持形状不变的同时更改序列的最大值和最小值", @@ -5151,7 +5145,6 @@ "timelion.serverSideErrors.movingaverageFunction.notValidPositionErrorMessage": "有效位置为:{validPositions}", "timelion.serverSideErrors.movingstdFunction.notValidPositionErrorMessage": "有效位置为:{validPositions}", "timelion.serverSideErrors.pointsFunction.notValidSymbolErrorMessage": "有效符号为:{validSymbols}", - "timelion.serverSideErrors.quandlFunction.unsupportedIntervalErrorMessage": "quandl() 不支持的时间间隔:{interval}。quandl() 支持:{intervals}", "timelion.serverSideErrors.sheetParseErrorMessage": "应为:字符位置 {column} 的{expectedDescription}", "timelion.serverSideErrors.unknownArgumentErrorMessage": "{functionName} 的未知参数:{argumentName}", "timelion.serverSideErrors.unknownArgumentTypeErrorMessage": "不支持的参数类型:{argument}", @@ -5162,9 +5155,6 @@ "timelion.timelionDescription": "在图表上显示时间序列数据。", "timelion.uiSettings.defaultIndexDescription": "要使用 {esParam} 搜索的默认 Elasticsearch 索引", "timelion.uiSettings.defaultIndexLabel": "默认索引", - "timelion.uiSettings.experimentalLabel": "技术预览", - "timelion.uiSettings.graphiteURLDescription": "{experimentalLabel} Graphite 主机的 URL", - "timelion.uiSettings.graphiteURLLabel": "Graphite URL", "timelion.uiSettings.legacyChartsLibraryDeprication": "此设置已过时,在未来版本中将不受支持。", "timelion.uiSettings.legacyChartsLibraryDescription": "在 Visualize 中启用 timelion 图表的旧版图表库", "timelion.uiSettings.legacyChartsLibraryLabel": "Timelion 旧版图表库", @@ -5172,8 +5162,6 @@ "timelion.uiSettings.maximumBucketsLabel": "最大存储桶数", "timelion.uiSettings.minimumIntervalDescription": "使用“auto”时将计算的最小时间间隔", "timelion.uiSettings.minimumIntervalLabel": "最小时间间隔", - "timelion.uiSettings.quandlKeyDescription": "{experimentalLabel} 来自 www.quandl.com 的 API 密钥", - "timelion.uiSettings.quandlKeyLabel": "Quandl 密钥", "timelion.uiSettings.targetBucketsDescription": "使用自动时间间隔时想要的存储桶数目", "timelion.uiSettings.targetBucketsLabel": "目标存储桶", "timelion.uiSettings.timeFieldDescription": "使用 {esParam} 时包含时间戳的默认字段", diff --git a/x-pack/plugins/triggers_actions_ui/common/parse_interval.ts b/x-pack/plugins/triggers_actions_ui/common/parse_interval.ts index 21fd1b214c32f..39d425bbb9ddd 100644 --- a/x-pack/plugins/triggers_actions_ui/common/parse_interval.ts +++ b/x-pack/plugins/triggers_actions_ui/common/parse_interval.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx index 6eb6c732665e3..1c4dd438e180d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react'; import { i18n } from '@kbn/i18n'; -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { EuiFlexItem, EuiFlexGroup, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx index 852ad9e7c8024..7cc198c1bf58e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react'; import { i18n } from '@kbn/i18n'; -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { EuiDataGrid, EuiFlexItem, diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts index 3f831bc5c9057..fc4ce4c3d9625 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts @@ -7,7 +7,7 @@ import { create as createHandlebars, HelperDelegate, HelperOptions } from 'handlebars'; import { encode, RisonValue } from 'rison-node'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment, { Moment } from 'moment'; import numeral from '@elastic/numeral'; import { url } from '../../../../../../src/plugins/kibana_utils/public'; diff --git a/x-pack/plugins/uptime/common/lib/get_histogram_interval.ts b/x-pack/plugins/uptime/common/lib/get_histogram_interval.ts index 58b04bb041580..8d44fb594c03a 100644 --- a/x-pack/plugins/uptime/common/lib/get_histogram_interval.ts +++ b/x-pack/plugins/uptime/common/lib/get_histogram_interval.ts @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { QUERY } from '../constants'; export const parseRelativeDate = (dateStr: string, options = {}) => { diff --git a/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx index 7669ee29786f3..fee4143df11f9 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { DurationChartComponent } from './duration_chart'; import { MonitorDurationResult } from '../../../../common/types'; import { render } from '../../../lib/helper/rtl_helpers'; diff --git a/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.test.tsx index 602f1b2898a96..345d23ff22b45 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { PingHistogramComponent, PingHistogramComponentProps } from './ping_histogram'; import { render } from '../../../lib/helper/rtl_helpers'; import { mockDataPlugin, mockMoment, mockMomentTimezone } from '../../../lib/helper/test_helpers'; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx index 3f107581c1eea..5e3007ed36a17 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { MonitorCharts } from './monitor_charts'; import { shallowWithRouter } from '../../lib'; diff --git a/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx b/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx index c62f254afccb3..619946d21a263 100644 --- a/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import React, { useState, Fragment } from 'react'; import { useUrlParams, UptimeUrlParamsHook } from './use_url_params'; import { UptimeRefreshContext } from '../contexts'; diff --git a/x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.test.ts index e0ee5574b48d0..4771d864e0bf8 100644 --- a/x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.test.ts +++ b/x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import { getSupportedUrlParams } from './get_supported_url_params'; import { CLIENT_DEFAULTS } from '../../../../common/constants'; diff --git a/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.test.ts index 8f597bcd0912f..c9a5a3081b17a 100644 --- a/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.test.ts +++ b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; import moment from 'moment'; import { parseAbsoluteDate } from './parse_absolute_date'; diff --git a/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts index 5a3627c048860..54b555471451c 100644 --- a/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts +++ b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts @@ -5,7 +5,7 @@ * 2.0. */ -import DateMath from '@elastic/datemath'; +import DateMath from '@kbn/datemath'; export const parseAbsoluteDate = (date: string, defaultValue: number, options = {}): number => { const momentWrapper = DateMath.parse(date, options); diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index 6d9a0d23d9d32..007ad8672eb2f 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -6,7 +6,7 @@ */ import { min } from 'lodash'; -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { JsonObject } from '@kbn/utility-types'; diff --git a/x-pack/plugins/uptime/server/lib/saved_objects/migrations.test.ts b/x-pack/plugins/uptime/server/lib/saved_objects/migrations.test.ts new file mode 100644 index 0000000000000..172e549cc05fa --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/saved_objects/migrations.test.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { add820Indices } from './migrations'; +import { SavedObject, SavedObjectMigrationContext } from 'src/core/server'; +import { DynamicSettings } from '../../../common/runtime_types'; + +describe('add820Indices migration', () => { + const context = { log: { warning: () => {} } } as unknown as SavedObjectMigrationContext; + + const makeSettings = (heartbeatIndices: string): SavedObject => { + return { + id: '1', + type: 't', + references: [], + attributes: { + heartbeatIndices, + certAgeThreshold: 1, + certExpirationThreshold: 2, + defaultConnectors: ['example'], + }, + }; + }; + + it("adds the synthetics-* index if it's not in the indices settings", () => { + const doc = makeSettings('heartbeat-8*,something_else'); + const result = add820Indices(doc, context); + expect(result).toEqual({ + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: 'heartbeat-8*,something_else,synthetics-*', + }, + }); + }); + + it("adds the heartbeat-8* index if it's not in the indices settings", () => { + const doc = makeSettings('synthetics-*,something_else'); + const result = add820Indices(doc, context); + expect(result).toEqual({ + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: 'synthetics-*,something_else,heartbeat-8*', + }, + }); + }); + + it("adds both synthetics-* and heartbeat-8* index if they're not present in the indices", () => { + const doc = makeSettings('something-*,something_else'); + const result = add820Indices(doc, context); + expect(result).toEqual({ + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: 'something-*,something_else,synthetics-*,heartbeat-8*', + }, + }); + }); + + it('works for empty heartbeat indices fields', () => { + const doc = makeSettings(''); + const result = add820Indices(doc, context); + expect(result).toEqual({ + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: 'synthetics-*,heartbeat-8*', + }, + }); + }); + + it('works for undefined heartbeat indices fields', () => { + const doc = makeSettings(''); + + // We must TS ignore this so that we can delete this + // non-optional field and test that the migration still works + // when the field does not exist in the document + // @ts-expect-error + delete doc.attributes.heartbeatIndices; + const result = add820Indices(doc, context); + expect(result).toEqual({ + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: 'synthetics-*,heartbeat-8*', + }, + }); + }); +}); diff --git a/x-pack/plugins/uptime/server/lib/saved_objects/migrations.ts b/x-pack/plugins/uptime/server/lib/saved_objects/migrations.ts new file mode 100644 index 0000000000000..211e58db9784e --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/saved_objects/migrations.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectMigrationFn } from 'src/core/server'; +import { DynamicSettings } from '../../../common/runtime_types'; + +export const add820Indices: SavedObjectMigrationFn = (doc) => { + const heartbeatIndices = doc.attributes?.heartbeatIndices; + + const indicesArr = !heartbeatIndices ? [] : heartbeatIndices.split(','); + + if (!indicesArr.includes('synthetics-*')) { + indicesArr.push('synthetics-*'); + } + + if (!indicesArr.includes('heartbeat-8*')) { + indicesArr.push('heartbeat-8*'); + } + + const migratedObj = { + ...doc, + attributes: { + ...doc.attributes, + heartbeatIndices: indicesArr.join(','), + }, + }; + + return migratedObj; +}; diff --git a/x-pack/plugins/uptime/server/lib/saved_objects/uptime_settings.ts b/x-pack/plugins/uptime/server/lib/saved_objects/uptime_settings.ts index 0360b0ed11eb2..4ed7887049c9b 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects/uptime_settings.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects/uptime_settings.ts @@ -7,6 +7,8 @@ import { SavedObjectsType } from 'kibana/server'; import { i18n } from '@kbn/i18n'; +import { add820Indices } from './migrations'; + export const settingsObjectType = 'uptime-dynamic-settings'; export const settingsObjectId = 'uptime-dynamic-settings-singleton'; @@ -43,4 +45,8 @@ export const umDynamicSettings: SavedObjectsType = { defaultMessage: 'Uptime Settings - Index', }), }, + migrations: { + // Takes a pre 8.2.0 doc, and converts it to 8.2.0 + '8.2.0': add820Indices, + }, }; diff --git a/x-pack/plugins/ux/public/context/url_params_context/helpers.test.ts b/x-pack/plugins/ux/public/context/url_params_context/helpers.test.ts index 784b10b3f3ee1..b76b53551db08 100644 --- a/x-pack/plugins/ux/public/context/url_params_context/helpers.test.ts +++ b/x-pack/plugins/ux/public/context/url_params_context/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import moment from 'moment-timezone'; import * as helpers from './helpers'; diff --git a/x-pack/plugins/ux/public/context/url_params_context/helpers.ts b/x-pack/plugins/ux/public/context/url_params_context/helpers.ts index ee6ac43c1aeab..728b89eb2bad7 100644 --- a/x-pack/plugins/ux/public/context/url_params_context/helpers.ts +++ b/x-pack/plugins/ux/public/context/url_params_context/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import { compact, pickBy } from 'lodash'; import moment from 'moment'; import { UrlParams } from './types'; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx index fc6ad7ae4a7d8..23028075daa3b 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx @@ -16,7 +16,7 @@ import { ScaleType, Settings, } from '@elastic/charts'; -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import moment from 'moment-timezone'; import { IUiSettingsClient } from 'kibana/public'; import { EuiCallOut, EuiLoadingChart, EuiSpacer, EuiEmptyPrompt, EuiText } from '@elastic/eui'; diff --git a/x-pack/plugins/watcher/public/legacy/calc_es_interval.ts b/x-pack/plugins/watcher/public/legacy/calc_es_interval.ts index cae88b797ea4f..d60f8955bcbd6 100644 --- a/x-pack/plugins/watcher/public/legacy/calc_es_interval.ts +++ b/x-pack/plugins/watcher/public/legacy/calc_es_interval.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import { parseEsInterval } from './parse_es_interval'; diff --git a/x-pack/plugins/watcher/public/legacy/parse_es_interval/invalid_es_calendar_interval_error.ts b/x-pack/plugins/watcher/public/legacy/parse_es_interval/invalid_es_calendar_interval_error.ts index 6ff68a1254808..6c9ca8b4a95fe 100644 --- a/x-pack/plugins/watcher/public/legacy/parse_es_interval/invalid_es_calendar_interval_error.ts +++ b/x-pack/plugins/watcher/public/legacy/parse_es_interval/invalid_es_calendar_interval_error.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Unit } from '@elastic/datemath'; +import { Unit } from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; export class InvalidEsCalendarIntervalError extends Error { diff --git a/x-pack/plugins/watcher/public/legacy/parse_es_interval/parse_es_interval.ts b/x-pack/plugins/watcher/public/legacy/parse_es_interval/parse_es_interval.ts index 968ae01587523..a0cf6af6dd331 100644 --- a/x-pack/plugins/watcher/public/legacy/parse_es_interval/parse_es_interval.ts +++ b/x-pack/plugins/watcher/public/legacy/parse_es_interval/parse_es_interval.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath, { Unit } from '@elastic/datemath'; +import dateMath, { Unit } from '@kbn/datemath'; import { InvalidEsCalendarIntervalError } from './invalid_es_calendar_interval_error'; import { InvalidEsIntervalFormatError } from './invalid_es_interval_format_error'; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_rule_execution_events.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_rule_execution_events.ts index 555c16e206ab8..b8287c4433ba4 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_rule_execution_events.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_rule_execution_events.ts @@ -5,7 +5,7 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; +import dateMath from '@kbn/datemath'; import expect from '@kbn/expect'; import moment from 'moment'; import { set } from '@elastic/safer-lodash-set'; diff --git a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts index 14f2e53949cfc..43a3707a21963 100644 --- a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts @@ -148,7 +148,9 @@ export default function (providerContext: FtrProviderContext) { }) .expect(400); - expect(postResponse.message).match(/Invalid logstash host should not start with http\(s\)/); + expect(postResponse.message).match( + /Host address must begin with a domain name or IP address/ + ); }); it('should toggle default output when creating a new default output ', async function () { diff --git a/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js b/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js index 336a575454e72..04a6a848d3cbd 100644 --- a/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js +++ b/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import expect from '@kbn/expect'; import mockRolledUpData, { mockIndices } from './hybrid_index_helper'; diff --git a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js index 4f535ae3e3ef0..e88082e9f00a8 100644 --- a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js +++ b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js @@ -5,7 +5,7 @@ * 2.0. */ -import datemath from '@elastic/datemath'; +import datemath from '@kbn/datemath'; import expect from '@kbn/expect'; import { mockIndices } from './hybrid_index_helper'; diff --git a/x-pack/test/functional/services/cases/create.ts b/x-pack/test/functional/services/cases/create.ts index f1a54aec75438..5ed22ad51ad9f 100644 --- a/x-pack/test/functional/services/cases/create.ts +++ b/x-pack/test/functional/services/cases/create.ts @@ -12,6 +12,7 @@ export function CasesCreateViewServiceProvider({ getService, getPageObject }: Ft const testSubjects = getService('testSubjects'); const find = getService('find'); const comboBox = getService('comboBox'); + const config = getService('config'); return { /** @@ -57,7 +58,9 @@ export function CasesCreateViewServiceProvider({ getService, getPageObject }: Ft // save await testSubjects.click('create-case-submit'); - await testSubjects.existOrFail('case-view-title'); + await testSubjects.existOrFail('case-view-title', { + timeout: config.get('timeouts.waitFor'), + }); }, }; } diff --git a/x-pack/test/functional/services/cases/list.ts b/x-pack/test/functional/services/cases/list.ts index 87e2fdcb91edc..29fc34d3f0dd5 100644 --- a/x-pack/test/functional/services/cases/list.ts +++ b/x-pack/test/functional/services/cases/list.ts @@ -16,6 +16,7 @@ export function CasesTableServiceProvider({ getService, getPageObject }: FtrProv const find = getService('find'); const header = getPageObject('header'); const retry = getService('retry'); + const config = getService('config'); return { /** @@ -25,8 +26,27 @@ export function CasesTableServiceProvider({ getService, getPageObject }: FtrProv */ async goToFirstListedCase() { await testSubjects.existOrFail('cases-table'); + await testSubjects.existOrFail('case-details-link', { + timeout: config.get('timeouts.waitFor'), + }); await testSubjects.click('case-details-link'); - await testSubjects.existOrFail('case-view-title'); + await testSubjects.existOrFail('case-view-title', { + timeout: config.get('timeouts.waitFor'), + }); + }, + + async deleteFirstListedCase() { + await testSubjects.existOrFail('action-delete', { + timeout: config.get('timeouts.waitFor'), + }); + await testSubjects.click('action-delete'); + await testSubjects.existOrFail('confirmModalConfirmButton', { + timeout: config.get('timeouts.waitFor'), + }); + await testSubjects.click('confirmModalConfirmButton'); + await testSubjects.existOrFail('euiToastHeader', { + timeout: config.get('timeouts.waitFor'), + }); }, async bulkDeleteAllCases() { @@ -55,8 +75,8 @@ export function CasesTableServiceProvider({ getService, getPageObject }: FtrProv }, async validateCasesTableHasNthRows(nrRows: number) { - await retry.tryForTime(2000, async () => { - const rows = await find.allByCssSelector('[data-test-subj*="cases-table-row-"', 100); + await retry.tryForTime(3000, async () => { + const rows = await find.allByCssSelector('[data-test-subj*="cases-table-row-"'); expect(rows.length).equal(nrRows); }); }, @@ -66,6 +86,7 @@ export function CasesTableServiceProvider({ getService, getPageObject }: FtrProv this.refreshTable(); return await testSubjects.exists('case-details-link'); }); + await header.waitUntilLoadingHasFinished(); }, async waitForCasesToBeDeleted() { diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/list_view.ts b/x-pack/test/functional_with_es_ssl/apps/cases/list_view.ts index c1ec21b694b49..e1f06f8a33e9f 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/list_view.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/list_view.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import uuid from 'uuid'; import { FtrProviderContext } from '../../ftr_provider_context'; import { CaseStatuses } from '../../../../plugins/cases/common'; @@ -64,9 +63,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { }); it('deletes a case correctly from the list', async () => { - await testSubjects.click('action-delete'); - await testSubjects.click('confirmModalConfirmButton'); - await testSubjects.existOrFail('euiToastHeader'); + await cases.casesTable.deleteFirstListedCase(); await cases.casesTable.waitForTableToFinishLoading(); await retry.tryForTime(2000, async () => { @@ -83,13 +80,13 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { }); describe('filtering', () => { - const id = uuid.v4(); - const caseTitle = 'matchme-' + id; + const caseTitle = 'matchme'; before(async () => { - await cases.api.createNthRandomCases(2); await cases.api.createCase({ title: caseTitle, tags: ['one'] }); - await cases.api.createCase({ tags: ['two'] }); + await cases.api.createCase({ title: 'test2', tags: ['two'] }); + await cases.api.createCase({ title: 'test3' }); + await cases.api.createCase({ title: 'test4' }); await header.waitUntilLoadingHasFinished(); await cases.casesTable.waitForCasesToBeListed(); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts b/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts index 8fd5821ffdef1..8c14e7e1263ee 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts @@ -19,8 +19,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { const retry = getService('retry'); const comboBox = getService('comboBox'); - // Failing: See https://github.com/elastic/kibana/issues/129248 - describe.skip('View case', () => { + describe('View case', () => { describe('properties', () => { // create the case to test on before(async () => { diff --git a/yarn.lock b/yarn.lock index db4b0b07adf11..bf1639a09b849 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,15 +1228,23 @@ resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.16.2.tgz#05dd7f06659759fda30f87b15534f1e42f1201bb" integrity sha512-KgqAWMH0emL6f3xH6nqyTryoBMqlJ627LBIe9PT1PRRQPz2FtHib3FIHJPukp1slzF3hJYZvdiVwgPnHbaSOOA== -"@bazel/typescript@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-4.0.0.tgz#71a6f0f5e340c6b8516b21fbc0f0853e74055d0c" - integrity sha512-+Le9q+5IR9gEnSH8sXyxDB5dD6NJx2kbm6AL+cijYVat2MczpGV4sI1mu0mdLzYsEX5Tjt5iHkaNb7sFESjnYA== +"@bazel/typescript@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-5.3.1.tgz#f996abebfa57a29a170a83d0c84780286f06cb72" + integrity sha512-fP0fGzLbsOVdbAn6mlrX1LBAT0TJ+S0VVOap9SSSXCb2PknnKEHZupUww/raVSczy+cqcd/Vfpllzm/AcdOmyw== dependencies: + "@bazel/worker" "5.3.1" protobufjs "6.8.8" semver "5.6.0" source-map-support "0.5.9" - tsutils "2.27.2" + tsutils "3.21.0" + +"@bazel/worker@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@bazel/worker/-/worker-5.3.1.tgz#87d850fdfc22cde24f380961f66daa5cbfd4acf7" + integrity sha512-KB+Xs198NLhN01zhlOPr/VEmz/tzwGq/pI1gdnCTLDMTCspV6LnJaIeGgicXuKrzz0V1LhvlvsI5lqJt9yuGYw== + dependencies: + google-protobuf "^3.6.1" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" @@ -1471,9 +1479,12 @@ utility-types "^3.10.0" uuid "^3.3.2" -"@elastic/datemath@link:bazel-bin/packages/elastic-datemath": - version "0.0.0" - uid "" +"@elastic/datemath@5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@elastic/datemath/-/datemath-5.0.3.tgz#7baccdab672b9a3ecb7fe8387580670936b58573" + integrity sha512-8Hbr1Uyjm5OcYBfEB60K7sCP6U3IXuWDaLaQmYv3UxgI4jqBWbakoemwWvsqPVUvnwEjuX6z7ghPZbefs8xiaA== + dependencies: + tslib "^1.9.3" "@elastic/ecs-helpers@^1.1.0": version "1.1.0" @@ -2980,6 +2991,10 @@ version "0.0.0" uid "" +"@kbn/datemath@link:bazel-bin/packages/kbn-datemath": + version "0.0.0" + uid "" + "@kbn/dev-utils@link:bazel-bin/packages/kbn-dev-utils": version "0.0.0" uid "" @@ -5557,10 +5572,6 @@ version "0.0.0" uid "" -"@types/elastic__datemath@link:bazel-bin/packages/elastic-datemath/npm_module_types": - version "0.0.0" - uid "" - "@types/enzyme@^3.10.8": version "3.10.8" resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.8.tgz#ad7ac9d3af3de6fd0673773123fafbc63db50d42" @@ -6007,6 +6018,10 @@ version "0.0.0" uid "" +"@types/kbn__datemath@link:bazel-bin/packages/kbn-datemath/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__dev-utils@link:bazel-bin/packages/kbn-dev-utils/npm_module_types": version "0.0.0" uid "" @@ -8419,12 +8434,7 @@ async@^2.1.4, async@^2.6.2: dependencies: lodash "^4.17.14" -async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== - -async@^3.2.3: +async@^3.2.0, async@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== @@ -15452,6 +15462,11 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" +google-protobuf@^3.6.1: + version "3.19.4" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.19.4.tgz#8d32c3e34be9250956f28c0fb90955d13f311888" + integrity sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg== + got@11.8.2, got@^11.8.2: version "11.8.2" resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" @@ -20399,10 +20414,10 @@ moment-timezone@^0.5.27: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0", moment@>=1.6.0, moment@>=2.14.0, moment@^2.10.6, moment@^2.24.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.28.0.tgz#cdfe73ce01327cee6537b0fafac2e0f21a237d75" - integrity sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw== +"moment@>= 2.9.0", moment@>=1.6.0, moment@>=2.14.0, moment@^2.10.6, moment@^2.29.2: + version "2.29.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4" + integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg== monaco-editor@*, monaco-editor@^0.22.3: version "0.22.3" @@ -28154,14 +28169,7 @@ tslib@~2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== -tsutils@2.27.2: - version "2.27.2" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7" - integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg== - dependencies: - tslib "^1.8.1" - -tsutils@^3.21.0: +tsutils@3.21.0, tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==