diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ba468c5a2d98..eff8c58a48b0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,6 +87,7 @@ /src/dev/ @elastic/kibana-operations /src/setup_node_env/ @elastic/kibana-operations /src/optimize/ @elastic/kibana-operations +/src/es_archiver/ @elastic/kibana-operations /packages/*eslint*/ @elastic/kibana-operations /packages/*babel*/ @elastic/kibana-operations /packages/kbn-dev-utils*/ @elastic/kibana-operations @@ -112,6 +113,7 @@ /src/legacy/server/logging/ @elastic/kibana-platform /src/legacy/server/saved_objects/ @elastic/kibana-platform /src/legacy/server/status/ @elastic/kibana-platform +/src/dev/run_check_core_api_changes.ts @elastic/kibana-platform # Security /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-platform diff --git a/.i18nrc.json b/.i18nrc.json index f03ced2b8509..4c115296b5b3 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -12,6 +12,7 @@ "embeddableExamples": "examples/embeddable_examples", "share": "src/plugins/share", "home": "src/plugins/home", + "charts": "src/plugins/charts", "esUi": "src/plugins/es_ui_shared", "devTools": "src/plugins/dev_tools", "expressions": "src/plugins/expressions", diff --git a/NOTICE.txt b/NOTICE.txt index 955c3127fa95..e0c5d94eff6b 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -153,6 +153,40 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +--- +This product bundles rules based on https://github.com/BlueTeamLabs/sentinel-attack +which is available under a "MIT" license. The files based on this license are: + +- windows_defense_evasion_via_filter_manager.json +- windows_process_discovery_via_tasklist_command.json +- windows_priv_escalation_via_accessibility_features.json +- windows_persistence_via_application_shimming.json +- windows_execution_via_trusted_developer_utilities.json +- windows_execution_via_net_com_assemblies.json +- windows_execution_via_connection_manager.json + +MIT License + +Copyright (c) 2019 Edoardo Gerosa, Olaf Hartong + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + --- This product includes code that is adapted from mapbox-gl-js, which is available under a "BSD-3-Clause" license. diff --git a/docs/developer/add-data-guide.asciidoc b/docs/developer/add-data-guide.asciidoc index aec44a9537ee..e00e46868bb2 100644 --- a/docs/developer/add-data-guide.asciidoc +++ b/docs/developer/add-data-guide.asciidoc @@ -11,23 +11,24 @@ Each tutorial contains three sets of instructions: [float] === Creating a new tutorial -// TODO: update path to where the directory must be created on the new platform -1. Create a new directory in the link:https://github.com/elastic/kibana/tree/master/src/legacy/core_plugins/kibana/server/tutorials[tutorials directory]. -2. In the new directory, create a file called `index.js` that exports a function. -The function must return a JavaScript object that conforms to the link:https://github.com/elastic/kibana/blob/master/src/plugins/home/server/services/tutorials/lib/tutorial_schema.ts[tutorial schema]. -// TODO: update path to where the tutorial must be registered on the new platform -3. Register the tutorial in link:https://github.com/elastic/kibana/blob/master/src/legacy/core_plugins/kibana/server/tutorials/register.js[register.js] by calling `server.newPlatform.setup.plugins.home.tutorials.registerTutorial(myFuncImportedFromIndexJs)`. -// TODO: update path to where the image assets must be added on the new platform +1. Create a new directory in the link:https://github.com/elastic/kibana/tree/master/src/plugins/home/server/tutorials[tutorials directory]. +2. In the new directory, create a file called `index.ts` that exports a function. +The function must return a function object that conforms to the `TutorialSchema` interface link:https://github.com/elastic/kibana/blob/master/src/plugins/home/server/services/tutorials/lib/tutorial_schema.ts[tutorial schema]. +3. Register the tutorial in link:https://github.com/elastic/kibana/blob/master/src/plugins/home/server/tutorials/register.ts[register.ts] by adding it to the `builtInTutorials`. +// TODO update path once assets are migrated 4. Add image assets to the link:https://github.com/elastic/kibana/tree/master/src/legacy/core_plugins/kibana/public/home/tutorial_resources[tutorial_resources directory]. 5. Run Kibana locally to preview the tutorial. 6. Create a PR and go through the review process to get the changes approved. +If you are creating a new plugin and the tutorial is only related to that plugin, you can also place the `TutorialSchema` object into your plugin folder. Add `home` to the `requiredPlugins` list in your `kibana.json` file. +Then register the tutorial object by calling `home.tutorials.registerTutorial(tutorialObject)` in the `setup` lifecycle of your server plugin. + [float] ==== Variables String values can contain variables that are substituted when rendered. Variables are specified by `{}`. For example: `{config.docs.version}` is rendered as `6.2` when running the tutorial in Kibana 6.2. -link:https://github.com/elastic/kibana/blob/master/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js#L23[Provided variables] +link:https://github.com/elastic/kibana/blob/master/src/legacy/core_plugins/kibana/public/home/np_ready/components/tutorial/replace_template_strings.js#L23[Provided variables] [float] ==== Markdown diff --git a/docs/development/core/public/kibana-plugin-public.chromenavlink.disablesuburltracking.md b/docs/development/core/public/kibana-plugin-public.chromenavlink.disablesuburltracking.md new file mode 100644 index 000000000000..0054adc693dc --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.chromenavlink.disablesuburltracking.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeNavLink](./kibana-plugin-public.chromenavlink.md) > [disableSubUrlTracking](./kibana-plugin-public.chromenavlink.disablesuburltracking.md) + +## ChromeNavLink.disableSubUrlTracking property + +> Warning: This API is now obsolete. +> +> + +A flag that tells legacy chrome to ignore the link when tracking sub-urls + +Signature: + +```typescript +readonly disableSubUrlTracking?: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-public.chromenavlink.md b/docs/development/core/public/kibana-plugin-public.chromenavlink.md index 7e7849b1a135..810e520badf4 100644 --- a/docs/development/core/public/kibana-plugin-public.chromenavlink.md +++ b/docs/development/core/public/kibana-plugin-public.chromenavlink.md @@ -1,32 +1,33 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeNavLink](./kibana-plugin-public.chromenavlink.md) - -## ChromeNavLink interface - - -Signature: - -```typescript -export interface ChromeNavLink -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [active](./kibana-plugin-public.chromenavlink.active.md) | boolean | Indicates whether or not this app is currently on the screen. | -| [baseUrl](./kibana-plugin-public.chromenavlink.baseurl.md) | string | The base route used to open the root of an application. | -| [category](./kibana-plugin-public.chromenavlink.category.md) | AppCategory | The category the app lives in | -| [disabled](./kibana-plugin-public.chromenavlink.disabled.md) | boolean | Disables a link from being clickable. | -| [euiIconType](./kibana-plugin-public.chromenavlink.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precendence over the icon property. | -| [hidden](./kibana-plugin-public.chromenavlink.hidden.md) | boolean | Hides a link from the navigation. | -| [icon](./kibana-plugin-public.chromenavlink.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | -| [id](./kibana-plugin-public.chromenavlink.id.md) | string | A unique identifier for looking up links. | -| [linkToLastSubUrl](./kibana-plugin-public.chromenavlink.linktolastsuburl.md) | boolean | Whether or not the subUrl feature should be enabled. | -| [order](./kibana-plugin-public.chromenavlink.order.md) | number | An ordinal used to sort nav links relative to one another for display. | -| [subUrlBase](./kibana-plugin-public.chromenavlink.suburlbase.md) | string | A url base that legacy apps can set to match deep URLs to an application. | -| [title](./kibana-plugin-public.chromenavlink.title.md) | string | The title of the application. | -| [tooltip](./kibana-plugin-public.chromenavlink.tooltip.md) | string | A tooltip shown when hovering over an app link. | -| [url](./kibana-plugin-public.chromenavlink.url.md) | string | A url that legacy apps can set to deep link into their applications. | - + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeNavLink](./kibana-plugin-public.chromenavlink.md) + +## ChromeNavLink interface + + +Signature: + +```typescript +export interface ChromeNavLink +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [active](./kibana-plugin-public.chromenavlink.active.md) | boolean | Indicates whether or not this app is currently on the screen. | +| [baseUrl](./kibana-plugin-public.chromenavlink.baseurl.md) | string | The base route used to open the root of an application. | +| [category](./kibana-plugin-public.chromenavlink.category.md) | AppCategory | The category the app lives in | +| [disabled](./kibana-plugin-public.chromenavlink.disabled.md) | boolean | Disables a link from being clickable. | +| [disableSubUrlTracking](./kibana-plugin-public.chromenavlink.disablesuburltracking.md) | boolean | A flag that tells legacy chrome to ignore the link when tracking sub-urls | +| [euiIconType](./kibana-plugin-public.chromenavlink.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precendence over the icon property. | +| [hidden](./kibana-plugin-public.chromenavlink.hidden.md) | boolean | Hides a link from the navigation. | +| [icon](./kibana-plugin-public.chromenavlink.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | +| [id](./kibana-plugin-public.chromenavlink.id.md) | string | A unique identifier for looking up links. | +| [linkToLastSubUrl](./kibana-plugin-public.chromenavlink.linktolastsuburl.md) | boolean | Whether or not the subUrl feature should be enabled. | +| [order](./kibana-plugin-public.chromenavlink.order.md) | number | An ordinal used to sort nav links relative to one another for display. | +| [subUrlBase](./kibana-plugin-public.chromenavlink.suburlbase.md) | string | A url base that legacy apps can set to match deep URLs to an application. | +| [title](./kibana-plugin-public.chromenavlink.title.md) | string | The title of the application. | +| [tooltip](./kibana-plugin-public.chromenavlink.tooltip.md) | string | A tooltip shown when hovering over an app link. | +| [url](./kibana-plugin-public.chromenavlink.url.md) | string | A url that legacy apps can set to deep link into their applications. | + diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc index a36a93ce3182..df4d8a0b65ee 100644 --- a/docs/migration/migrate_8_0.asciidoc +++ b/docs/migration/migrate_8_0.asciidoc @@ -80,4 +80,15 @@ specified explicitly. *Impact:* Any workflow that involved manually clearing generated bundles will have to be updated with the new path. + +[float] +[[breaking_80_reporting_changes]] +=== Reporting changes + +[float] +==== Legacy job parameters are no longer supported +*Details:* POST URL snippets that were copied in Kibana 6.2 or below are no longer supported. These logs have +been deprecated with warnings that have been logged throughout 7.x. Please use Kibana UI to re-generate the +POST URL snippets if you depend on these for automated PDF reports. + // end::notable-breaking-changes[] diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 63e542b0127e..17fdfc627187 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -229,6 +229,7 @@ export interface LegacyApp extends AppBase { appUrl: string; subUrlBase?: string; linkToLastSubUrl?: boolean; + disableSubUrlTracking?: boolean; } /** diff --git a/src/core/public/chrome/nav_links/nav_link.ts b/src/core/public/chrome/nav_links/nav_link.ts index 4d3a1e9ecd19..d0ef2aeb265f 100644 --- a/src/core/public/chrome/nav_links/nav_link.ts +++ b/src/core/public/chrome/nav_links/nav_link.ts @@ -78,6 +78,17 @@ export interface ChromeNavLink { */ readonly subUrlBase?: string; + /** + * A flag that tells legacy chrome to ignore the link when + * tracking sub-urls + * + * @internalRemarks + * This should be removed once legacy apps are gone. + * + * @deprecated + */ + readonly disableSubUrlTracking?: boolean; + /** * Whether or not the subUrl feature should be enabled. * diff --git a/src/core/public/legacy/legacy_service.ts b/src/core/public/legacy/legacy_service.ts index cc3210771eec..e4788e686dd4 100644 --- a/src/core/public/legacy/legacy_service.ts +++ b/src/core/public/legacy/legacy_service.ts @@ -75,6 +75,7 @@ export class LegacyPlatformService { subUrlBase: navLink.subUrlBase, linkToLastSubUrl: navLink.linkToLastSubUrl, category: navLink.category, + disableSubUrlTracking: navLink.disableSubUrlTracking, }) ); diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 5e36638516e5..8517166ee00e 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -264,6 +264,8 @@ export interface ChromeNavLink { readonly category?: AppCategory; // @deprecated readonly disabled?: boolean; + // @deprecated + readonly disableSubUrlTracking?: boolean; readonly euiIconType?: string; readonly hidden?: boolean; readonly icon?: string; diff --git a/src/core/server/config/object_to_config_adapter.test.ts b/src/core/server/config/object_to_config_adapter.test.ts new file mode 100644 index 000000000000..af41741e6208 --- /dev/null +++ b/src/core/server/config/object_to_config_adapter.test.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ObjectToConfigAdapter } from './object_to_config_adapter'; + +describe('ObjectToConfigAdapter', () => { + describe('#getFlattenedPaths()', () => { + it('considers arrays as final values', () => { + const data = { + string: 'string', + array: ['an', 'array'], + }; + const config = new ObjectToConfigAdapter(data); + + expect(config.getFlattenedPaths()).toEqual(['string', 'array']); + }); + + it('handles nested arrays', () => { + const data = { + string: 'string', + array: ['an', 'array'], + nested: { + number: 12, + array: [{ key: 1 }, { key: 2 }], + }, + }; + const config = new ObjectToConfigAdapter(data); + + expect(config.getFlattenedPaths()).toEqual([ + 'string', + 'array', + 'nested.number', + 'nested.array', + ]); + }); + }); +}); diff --git a/src/core/server/config/object_to_config_adapter.ts b/src/core/server/config/object_to_config_adapter.ts index b6ec77260356..d4c2f7336406 100644 --- a/src/core/server/config/object_to_config_adapter.ts +++ b/src/core/server/config/object_to_config_adapter.ts @@ -19,6 +19,7 @@ import { cloneDeep, get, has, set } from 'lodash'; +import { getFlattenedObject } from '../../utils'; import { Config, ConfigPath } from './'; /** @@ -41,24 +42,10 @@ export class ObjectToConfigAdapter implements Config { } public getFlattenedPaths() { - return [...flattenObjectKeys(this.rawConfig)]; + return Object.keys(getFlattenedObject(this.rawConfig)); } public toRaw() { return cloneDeep(this.rawConfig); } } - -function* flattenObjectKeys( - obj: { [key: string]: any }, - path: string = '' -): IterableIterator { - if (typeof obj !== 'object' || obj === null) { - yield path; - } else { - for (const [key, value] of Object.entries(obj)) { - const newPath = path !== '' ? `${path}.${key}` : key; - yield* flattenObjectKeys(value, newPath); - } - } -} diff --git a/src/core/server/legacy/config/get_unused_config_keys.test.ts b/src/core/server/legacy/config/get_unused_config_keys.test.ts index c4452fc6a120..2106a0748d81 100644 --- a/src/core/server/legacy/config/get_unused_config_keys.test.ts +++ b/src/core/server/legacy/config/get_unused_config_keys.test.ts @@ -200,6 +200,24 @@ describe('getUnusedConfigKeys', () => { ).toEqual(['foo.dolly']); }); + it('handles array values', async () => { + expect( + await getUnusedConfigKeys({ + coreHandledConfigPaths: ['core', 'array'], + pluginSpecs: [], + disabledPluginSpecs: [], + settings: { + core: { + prop: 'value', + array: [1, 2, 3], + }, + array: ['some', 'values'], + }, + legacyConfig: getConfig({}), + }) + ).toEqual([]); + }); + describe('using deprecation', () => { it('should use the plugin deprecations provider', async () => { expect( diff --git a/src/core/server/legacy/logging/appenders/legacy_appender.ts b/src/core/server/legacy/logging/appenders/legacy_appender.ts index 6d82d929e7da..0c2f4ce93c3b 100644 --- a/src/core/server/legacy/logging/appenders/legacy_appender.ts +++ b/src/core/server/legacy/logging/appenders/legacy_appender.ts @@ -33,6 +33,12 @@ export class LegacyAppender implements DisposableAppender { legacyLoggingConfig: schema.any(), }); + /** + * Sets {@link Appender.receiveAllLevels} because legacy does its own filtering based on the legacy logging + * configuration. + */ + public readonly receiveAllLevels = true; + private readonly loggingServer: LegacyLoggingServer; constructor(legacyLoggingConfig: Readonly) { diff --git a/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts b/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts index a19133c30659..1c6ab91a3927 100644 --- a/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts +++ b/src/core/server/legacy/plugins/find_legacy_plugin_specs.ts @@ -85,6 +85,7 @@ function getNavLinks(uiExports: LegacyUiExports, pluginSpecs: LegacyPluginSpec[] order: typeof spec.order === 'number' ? spec.order : 0, url: spec.url, subUrlBase: spec.subUrlBase || spec.url, + disableSubUrlTracking: spec.disableSubUrlTracking, icon: spec.icon, euiIconType: spec.euiIconType, linkToLastSub: 'linkToLastSubUrl' in spec ? spec.linkToLastSubUrl : false, diff --git a/src/core/server/logging/appenders/appenders.ts b/src/core/server/logging/appenders/appenders.ts index 3aa86495e4d8..871acb8c465c 100644 --- a/src/core/server/logging/appenders/appenders.ts +++ b/src/core/server/logging/appenders/appenders.ts @@ -42,6 +42,12 @@ export type AppenderConfigType = TypeOf; */ export interface Appender { append(record: LogRecord): void; + + /** + * Used to signal to `Logger` that log level filtering should be ignored for this appender. Defaults to `false`. + * @deprecated Should be removed once the `LegacyAppender` is removed. + */ + receiveAllLevels?: boolean; } /** diff --git a/src/core/server/logging/logger.test.ts b/src/core/server/logging/logger.test.ts index 026e24fc5df5..eeebb8ad5a0f 100644 --- a/src/core/server/logging/logger.test.ts +++ b/src/core/server/logging/logger.test.ts @@ -410,3 +410,85 @@ test('passes log record to appenders only if log level is supported.', () => { }); } }); + +test('passes log record to appender with receiveAllLevels: true, regardless if log level is supported', () => { + const receiveAllAppender = { append: jest.fn(), receiveAllLevels: true }; + const warnLogger = new BaseLogger(context, LogLevel.Warn, [receiveAllAppender], factory); + + warnLogger.trace('trace-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(1); + expect(receiveAllAppender.append.mock.calls[0][0]).toMatchObject({ + level: LogLevel.Trace, + message: 'trace-message', + }); + + warnLogger.debug('debug-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(2); + expect(receiveAllAppender.append.mock.calls[1][0]).toMatchObject({ + level: LogLevel.Debug, + message: 'debug-message', + }); + + warnLogger.info('info-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(3); + expect(receiveAllAppender.append.mock.calls[2][0]).toMatchObject({ + level: LogLevel.Info, + message: 'info-message', + }); + + warnLogger.warn('warn-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(4); + expect(receiveAllAppender.append.mock.calls[3][0]).toMatchObject({ + level: LogLevel.Warn, + message: 'warn-message', + }); + + warnLogger.error('error-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(5); + expect(receiveAllAppender.append.mock.calls[4][0]).toMatchObject({ + level: LogLevel.Error, + message: 'error-message', + }); + + warnLogger.fatal('fatal-message'); + expect(receiveAllAppender.append).toHaveBeenCalledTimes(6); + expect(receiveAllAppender.append.mock.calls[5][0]).toMatchObject({ + level: LogLevel.Fatal, + message: 'fatal-message', + }); +}); + +test('passes log record to appender with receiveAllLevels: false, only if log level is supported', () => { + const notReceiveAllAppender = { append: jest.fn(), receiveAllLevels: false }; + const warnLogger = new BaseLogger(context, LogLevel.Warn, [notReceiveAllAppender], factory); + + warnLogger.trace('trace-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(0); + + warnLogger.debug('debug-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(0); + + warnLogger.info('info-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(0); + + warnLogger.warn('warn-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(1); + expect(notReceiveAllAppender.append.mock.calls[0][0]).toMatchObject({ + level: LogLevel.Warn, + message: 'warn-message', + }); + + warnLogger.error('error-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(2); + expect(notReceiveAllAppender.append.mock.calls[1][0]).toMatchObject({ + level: LogLevel.Error, + message: 'error-message', + }); + + warnLogger.fatal('fatal-message'); + expect(notReceiveAllAppender.append).toHaveBeenCalledTimes(3); + expect(notReceiveAllAppender.append.mock.calls[2][0]).toMatchObject({ + level: LogLevel.Fatal, + message: 'fatal-message', + }); +}); diff --git a/src/core/server/logging/logger.ts b/src/core/server/logging/logger.ts index ac79c1916c07..ab6906ff5d68 100644 --- a/src/core/server/logging/logger.ts +++ b/src/core/server/logging/logger.ts @@ -136,12 +136,12 @@ export class BaseLogger implements Logger { } public log(record: LogRecord) { - if (!this.level.supports(record.level)) { - return; - } + const supportedLevel = this.level.supports(record.level); for (const appender of this.appenders) { - appender.append(record); + if (supportedLevel || appender.receiveAllLevels) { + appender.append(record); + } } } diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts index 9a3449b65a94..fafa04447ddf 100644 --- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts +++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts @@ -108,8 +108,6 @@ describe('getSortedObjectsForExport()', () => { "namespace": undefined, "perPage": 500, "search": undefined, - "sortField": "_id", - "sortOrder": "asc", "type": Array [ "index-pattern", "search", @@ -256,8 +254,6 @@ describe('getSortedObjectsForExport()', () => { "namespace": undefined, "perPage": 500, "search": "foo", - "sortField": "_id", - "sortOrder": "asc", "type": Array [ "index-pattern", "search", @@ -345,8 +341,6 @@ describe('getSortedObjectsForExport()', () => { "namespace": "foo", "perPage": 500, "search": undefined, - "sortField": "_id", - "sortOrder": "asc", "type": Array [ "index-pattern", "search", @@ -399,6 +393,79 @@ describe('getSortedObjectsForExport()', () => { ).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't export more than 1 objects"`); }); + test('sorts objects within type', async () => { + savedObjectsClient.find.mockResolvedValueOnce({ + total: 3, + per_page: 10000, + page: 1, + saved_objects: [ + { + id: '3', + type: 'index-pattern', + attributes: { + name: 'baz', + }, + references: [], + }, + { + id: '1', + type: 'index-pattern', + attributes: { + name: 'foo', + }, + references: [], + }, + { + id: '2', + type: 'index-pattern', + attributes: { + name: 'bar', + }, + references: [], + }, + ], + }); + const exportStream = await getSortedObjectsForExport({ + exportSizeLimit: 10000, + savedObjectsClient, + types: ['index-pattern'], + }); + const response = await readStreamToCompletion(exportStream); + expect(response).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "name": "foo", + }, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object { + "name": "bar", + }, + "id": "2", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object { + "name": "baz", + }, + "id": "3", + "references": Array [], + "type": "index-pattern", + }, + Object { + "exportedCount": 3, + "missingRefCount": 0, + "missingReferences": Array [], + }, + ] + `); + }); + test('exports selected objects and sorts them', async () => { savedObjectsClient.bulkGet.mockResolvedValueOnce({ saved_objects: [ diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts index e1a705a36db7..a4dfacfd9e34 100644 --- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts +++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts @@ -19,7 +19,7 @@ import Boom from 'boom'; import { createListStream } from '../../../../legacy/utils/streams'; -import { SavedObjectsClientContract } from '../types'; +import { SavedObjectsClientContract, SavedObject } from '../types'; import { fetchNestedDependencies } from './inject_nested_depdendencies'; import { sortObjects } from './sort_objects'; @@ -105,15 +105,17 @@ async function fetchObjectsToExport({ const findResponse = await savedObjectsClient.find({ type: types, search, - sortField: '_id', - sortOrder: 'asc', perPage: exportSizeLimit, namespace, }); if (findResponse.total > exportSizeLimit) { throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`); } - return findResponse.saved_objects; + + // sorts server-side by _id, since it's only available in fielddata + return findResponse.saved_objects.sort((a: SavedObject, b: SavedObject) => + a.id > b.id ? 1 : -1 + ); } else { throw Boom.badRequest('Either `type` or `objects` are required.'); } @@ -137,14 +139,17 @@ export async function getSortedObjectsForExport({ exportSizeLimit, namespace, }); - let exportedObjects = [...rootObjects]; + let exportedObjects = []; let missingReferences: SavedObjectsExportResultDetails['missingReferences'] = []; + if (includeReferencesDeep) { const fetchResult = await fetchNestedDependencies(rootObjects, savedObjectsClient, namespace); - exportedObjects = fetchResult.objects; + exportedObjects = sortObjects(fetchResult.objects); missingReferences = fetchResult.missingRefs; + } else { + exportedObjects = sortObjects(rootObjects); } - exportedObjects = sortObjects(exportedObjects); + const exportDetails: SavedObjectsExportResultDetails = { exportedCount: exportedObjects.length, missingRefCount: missingReferences.length, diff --git a/src/dev/run_check_lockfile_symlinks.js b/src/dev/run_check_lockfile_symlinks.js index c1ba22d3a7a4..e7fd7e883140 100644 --- a/src/dev/run_check_lockfile_symlinks.js +++ b/src/dev/run_check_lockfile_symlinks.js @@ -17,7 +17,7 @@ * under the License. */ -import { existsSync, lstatSync, readFileSync } from 'fs'; +import { existsSync, lstatSync, readFileSync, readlinkSync } from 'fs'; import globby from 'globby'; import { dirname } from 'path'; @@ -63,6 +63,7 @@ async function checkLockfileSymlinks(log, files) { await checkOnlyLockfileAtProjectRoot(filtered); await checkSuperfluousSymlinks(log, filtered); await checkMissingSymlinks(log, filtered); + await checkIncorrectSymlinks(log, filtered); } async function checkOnlyLockfileAtProjectRoot(files) { @@ -157,8 +158,9 @@ async function checkMissingSymlinks(log, files) { try { const json = JSON.parse(manifest); if (json.dependencies && Object.keys(json.dependencies).length) { + const correctSymlink = getCorrectSymlink(lockfilePath); log.warning( - `Manifest at '${path}' has dependencies, but did not find an adjacent 'yarn.lock' symlink.` + `Manifest at '${path}' has dependencies, but did not find an adjacent 'yarn.lock' symlink to '${correctSymlink}'.` ); errorPaths.push(`${parent}/yarn.lock`); } @@ -177,6 +179,42 @@ async function checkMissingSymlinks(log, files) { } } +async function checkIncorrectSymlinks(log, files) { + const errorPaths = []; + + files + .filter(file => matchesAnyGlob(file.getRelativePath(), LOCKFILE_GLOBS)) + .forEach(file => { + const path = file.getRelativePath(); + const stats = lstatSync(path); + if (!stats.isSymbolicLink()) { + return; + } + + const symlink = readlinkSync(path); + const correctSymlink = getCorrectSymlink(path); + if (symlink !== correctSymlink) { + log.warning( + `Symlink at '${path}' points to '${symlink}', but it should point to '${correctSymlink}'.` + ); + errorPaths.push(path); + } + }); + + if (errorPaths.length) { + throw createFailError( + `These symlinks do NOT point to the 'yarn.lock' file in the project root:\n${listPaths( + errorPaths + )}` + ); + } +} + +function getCorrectSymlink(path) { + const count = path.split('/').length - 1; + return `${'../'.repeat(count)}yarn.lock`; +} + function listPaths(paths) { return paths.map(path => ` - ${path}`).join('\n'); } diff --git a/src/legacy/core_plugins/kibana/public/discover/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/build_services.ts index bc2436ecdf5e..f9265323b2dc 100644 --- a/src/legacy/core_plugins/kibana/public/discover/build_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/build_services.ts @@ -32,10 +32,10 @@ import { } from 'src/plugins/data/public'; import { createSavedSearchesLoader } from './saved_searches'; import { DiscoverStartPlugins } from './plugin'; -import { EuiUtilsStart } from '../../../../../plugins/eui_utils/public'; import { SharePluginStart } from '../../../../../plugins/share/public'; import { SavedSearch } from './np_ready/types'; import { DocViewsRegistry } from './np_ready/doc_views/doc_views_registry'; +import { ChartsPluginStart } from '../../../../../plugins/charts/public'; export interface DiscoverServices { addBasePath: (path: string) => string; @@ -45,7 +45,7 @@ export interface DiscoverServices { data: DataPublicPluginStart; docLinks: DocLinksStart; docViewsRegistry: DocViewsRegistry; - eui_utils: EuiUtilsStart; + theme: ChartsPluginStart['theme']; filterManager: FilterManager; indexPatterns: IndexPatternsContract; inspector: unknown; @@ -77,7 +77,7 @@ export async function buildServices( data: plugins.data, docLinks: core.docLinks, docViewsRegistry, - eui_utils: plugins.eui_utils, + theme: plugins.charts.theme, filterManager: plugins.data.query.filterManager, getSavedSearchById: async (id: string) => savedObjectService.get(id), getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id), diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 27aa920c98aa..58406c74e9f3 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -62,8 +62,6 @@ export { getRequestInspectorStats, getResponseInspectorStats } from '../../../da export { intervalOptions } from 'ui/agg_types/buckets/_interval_options'; // @ts-ignore export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; -// @ts-ignore -export { RequestAdapter } from 'ui/inspector/adapters'; export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal'; export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory'; @@ -92,7 +90,6 @@ export { SortDirection, } from '../../../../../plugins/data/public'; export { ElasticSearchHit } from './np_ready/doc_views/doc_views_types'; -export { Adapters } from 'ui/inspector/types'; export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; export { FieldName } from 'ui/directives/field_name/field_name'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx index b83ac5b4a779..4d387f44c3d5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx @@ -114,13 +114,13 @@ export class DiscoverHistogram extends Component this.setState({ chartsTheme })); + this.subscription = getServices().theme.chartsTheme$.subscribe( + (chartsTheme: EuiChartThemeType['theme']) => this.setState({ chartsTheme }) + ); } componentWillUnmount() { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index dd782f97b075..3f3333b7caec 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -25,6 +25,7 @@ import dateMath from '@elastic/datemath'; import { i18n } from '@kbn/i18n'; import '../components/field_chooser/field_chooser'; +import { RequestAdapter } from '../../../../../../../plugins/inspector/public'; // doc table import './doc_table'; import { getSort } from './doc_table/lib/get_sort'; @@ -46,7 +47,6 @@ import { hasSearchStategyForIndexPattern, intervalOptions, migrateLegacyQuery, - RequestAdapter, showSaveModal, unhashUrl, stateMonitorFactory, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts index c840f1fbd87e..f47cf52c756a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts @@ -21,6 +21,7 @@ import * as Rx from 'rxjs'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public'; +import { RequestAdapter, Adapters } from '../../../../../../../plugins/inspector/public'; import { esFilters, TimeRange, @@ -43,13 +44,11 @@ import { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; import { SortOrder } from '../angular/doc_table/components/table_header/helpers'; import { getSortForSearchSource } from '../angular/doc_table/lib/get_sort_for_search_source'; import { - Adapters, angular, getRequestInspectorStats, getResponseInspectorStats, getServices, IndexPattern, - RequestAdapter, ISearchSource, } from '../../kibana_services'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index 0897f62574e9..77135f6a9817 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -27,7 +27,7 @@ import { IEmbeddableStart, IEmbeddableSetup } from '../../../../../plugins/embed import { getInnerAngularModule, getInnerAngularModuleEmbeddable } from './get_inner_angular'; import { setAngularModule, setServices } from './kibana_services'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; -import { EuiUtilsStart } from '../../../../../plugins/eui_utils/public'; +import { ChartsPluginStart } from '../../../../../plugins/charts/public'; import { buildServices } from './build_services'; import { SharePluginStart } from '../../../../../plugins/share/public'; import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public'; @@ -56,7 +56,7 @@ export interface DiscoverStartPlugins { uiActions: IUiActionsStart; embeddable: IEmbeddableStart; navigation: NavigationStart; - eui_utils: EuiUtilsStart; + charts: ChartsPluginStart; data: DataPublicPluginStart; share: SharePluginStart; inspector: any; diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index bd947b9cb9d7..50f1702a2a6d 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -52,7 +52,6 @@ import './visualize/legacy'; import './dashboard/legacy'; import './management'; import './dev_tools'; -import 'ui/color_maps'; import 'ui/agg_response'; import 'ui/agg_types'; import { showAppRedirectNotification } from 'ui/notify'; diff --git a/src/legacy/core_plugins/region_map/public/choropleth_layer.js b/src/legacy/core_plugins/region_map/public/choropleth_layer.js index 8132976fcbc6..e637a217bfbc 100644 --- a/src/legacy/core_plugins/region_map/public/choropleth_layer.js +++ b/src/legacy/core_plugins/region_map/public/choropleth_layer.js @@ -23,11 +23,12 @@ import _ from 'lodash'; import d3 from 'd3'; import { i18n } from '@kbn/i18n'; import { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; -import { truncatedColorMaps } from 'ui/color_maps'; import * as topojson from 'topojson-client'; import { toastNotifications } from 'ui/notify'; import * as colorUtil from 'ui/vis/map/color_util'; +import { truncatedColorMaps } from '../../../../plugins/charts/public'; + const EMPTY_STYLE = { weight: 1, opacity: 0.6, diff --git a/src/legacy/core_plugins/region_map/public/region_map_type.js b/src/legacy/core_plugins/region_map/public/region_map_type.js index 39353a379ce5..c6c345782d5f 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_type.js +++ b/src/legacy/core_plugins/region_map/public/region_map_type.js @@ -19,11 +19,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { truncatedColorSchemas as colorSchemas } from 'ui/color_maps'; import { mapToLayerWithId } from './util'; import { createRegionMapVisualization } from './region_map_visualization'; import { Status } from '../../visualizations/public'; import { RegionMapOptions } from './components/region_map_options'; +import { truncatedColorSchemas } from '../../../../plugins/charts/public'; // TODO: reference to TILE_MAP plugin should be removed import { ORIGIN } from '../../tile_map/common/origin'; @@ -60,7 +60,7 @@ provided base maps, or add your own. Darker colors represent higher values.', editorConfig: { optionsTemplate: props => , collections: { - colorSchemas, + colorSchemas: truncatedColorSchemas, vectorLayers: [], tmsLayers: [], }, diff --git a/src/legacy/core_plugins/region_map/public/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/region_map_visualization.js index f9a5793ca813..8b5812052a39 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/region_map_visualization.js @@ -19,11 +19,11 @@ import { i18n } from '@kbn/i18n'; import ChoroplethLayer from './choropleth_layer'; -import { truncatedColorMaps } from 'ui/color_maps'; import { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { toastNotifications } from 'ui/notify'; import { TileMapTooltipFormatter } from './tooltip_formatter'; +import { truncatedColorMaps } from '../../../../plugins/charts/public'; // TODO: reference to TILE_MAP plugin should be removed import { BaseMapsVisualizationProvider } from '../../tile_map/public/base_maps_visualization'; diff --git a/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js b/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js index fe29d9b6aad2..88d6db82946c 100644 --- a/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js +++ b/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js @@ -22,9 +22,10 @@ import _ from 'lodash'; import d3 from 'd3'; import $ from 'jquery'; import { EventEmitter } from 'events'; -import { truncatedColorMaps } from 'ui/color_maps'; import * as colorUtil from 'ui/vis/map/color_util'; +import { truncatedColorMaps } from '../../../../../plugins/charts/public'; + export class ScaledCirclesMarkers extends EventEmitter { constructor( featureCollection, @@ -87,7 +88,7 @@ export class ScaledCirclesMarkers extends EventEmitter { const quantizeDomain = min !== max ? [min, max] : d3.scale.quantize().domain(); - this._legendColors = makeLegendColors(this._colorRamp); + this._legendColors = this.getLegendColors(); this._legendQuantizer = d3.scale .quantize() .domain(quantizeDomain) @@ -222,11 +223,11 @@ export class ScaledCirclesMarkers extends EventEmitter { getBounds() { return this._leafletLayer.getBounds(); } -} -function makeLegendColors(colorRampKey) { - const colorRamp = _.get(truncatedColorMaps[colorRampKey], 'value'); - return colorUtil.getLegendColors(colorRamp); + getLegendColors() { + const colorRamp = _.get(truncatedColorMaps[this._colorRamp], 'value'); + return colorUtil.getLegendColors(colorRamp); + } } function makeColorDarker(color) { diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_type.js b/src/legacy/core_plugins/tile_map/public/tile_map_type.js index c58c226f0aba..b4fca3009352 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_type.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_type.js @@ -21,7 +21,6 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { truncatedColorSchemas as colorSchemas } from 'ui/color_maps'; import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson'; import { createTileMapVisualization } from './tile_map_visualization'; @@ -29,6 +28,7 @@ import { Status } from '../../visualizations/public'; import { TileMapOptions } from './components/tile_map_options'; import { MapTypes } from './map_types'; import { supportsCssFilters } from './css_filters'; +import { truncatedColorSchemas } from '../../../../plugins/charts/public'; export function createTileMapTypeDefinition(dependencies) { const CoordinateMapsVisualization = createTileMapVisualization(dependencies); @@ -63,7 +63,7 @@ export function createTileMapTypeDefinition(dependencies) { responseHandler: convertToGeoJson, editorConfig: { collections: { - colorSchemas, + colorSchemas: truncatedColorSchemas, legendPositions: [ { value: 'bottomleft', diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx index 901273ccbeb9..ada9e8c248a0 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx @@ -20,12 +20,12 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { MetricVisComponent } from './metric_vis_component'; import { Vis } from '../legacy_imports'; +import { MetricVisComponent, MetricVisComponentProps } from './metric_vis_component'; jest.mock('ui/new_platform'); -type Props = MetricVisComponent['props']; +type Props = MetricVisComponentProps; const baseVisData = { columns: [{ id: 'col-0', name: 'Count' }], diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx index 3a6d60a89e61..df563306ef83 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx @@ -22,15 +22,16 @@ import React, { Component } from 'react'; import { isColorDark } from '@elastic/eui'; -import { getHeatmapColors, getFormat, Vis } from '../legacy_imports'; +import { getFormat, Vis } from '../legacy_imports'; import { MetricVisValue } from './metric_vis_value'; import { fieldFormats } from '../../../../../plugins/data/public'; import { Context } from '../metric_vis_fn'; import { KibanaDatatable } from '../../../../../plugins/expressions/public'; +import { getHeatmapColors } from '../../../../../plugins/charts/public'; import { VisParams, MetricVisMetric } from '../types'; import { SchemaConfig } from '../../../visualizations/public'; -interface MetricVisComponentProps { +export interface MetricVisComponentProps { visParams: VisParams; visData: Context; vis: Vis; @@ -50,7 +51,6 @@ export class MetricVisComponent extends Component { const to = isPercentageMode ? Math.round((100 * range.to) / max) : range.to; labels.push(`${from} - ${to}`); }); - return labels; } diff --git a/src/legacy/core_plugins/vis_type_metric/public/legacy.ts b/src/legacy/core_plugins/vis_type_metric/public/legacy.ts index 65179ae1315c..87355c57926b 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/legacy.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/legacy.ts @@ -27,6 +27,7 @@ import { plugin } from '.'; const plugins: Readonly = { expressions: npSetup.plugins.expressions, visualizations: visualizationsSetup, + charts: npSetup.plugins.charts, }; const pluginInstance = plugin({} as PluginInitializerContext); diff --git a/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts index 93dfd76e16b1..6f02407919ba 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts @@ -18,8 +18,6 @@ */ export { Vis, VisParams } from 'ui/vis'; -export { vislibColorMaps, colorSchemas, ColorSchemas } from 'ui/color_maps'; -export { getHeatmapColors } from 'ui/color_maps'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; export { VisOptionsProps } from 'ui/vis/editors/default'; // @ts-ignore diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts index cdd8c2e5b05b..389b0f53916d 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts @@ -18,8 +18,7 @@ */ import { createMetricVisFn } from './metric_vis_fn'; - -// eslint-disable-next-line +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { functionWrapper } from '../../../../plugins/expressions/public/functions/tests/utils'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts index 4ebd8bf97c55..644de88021c1 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts @@ -19,7 +19,6 @@ import { i18n } from '@kbn/i18n'; -import { vislibColorMaps, ColorSchemas } from './legacy_imports'; import { ExpressionFunction, KibanaDatatable, @@ -29,6 +28,7 @@ import { } from '../../../../plugins/expressions/public'; import { ColorModes } from '../../vis_type_vislib/public'; import { visType, DimensionsVisParam, VisParams } from './types'; +import { ColorSchemas, vislibColorMaps } from '../../../../plugins/charts/public'; export type Context = KibanaDatatable; diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index c2b7e6da3f7b..4f535c62f56a 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -29,7 +29,7 @@ import { setup as visualizationsSetup, start as visualizationsStart, } from '../../visualizations/public/np_ready/public/legacy'; -import { metricVisTypeDefinition } from './metric_vis_type'; +import { createMetricVisTypeDefinition } from './metric_vis_type'; jest.mock('ui/new_platform'); @@ -37,7 +37,7 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { let vis: Vis; beforeAll(() => { - visualizationsSetup.types.createReactVisualization(metricVisTypeDefinition); + visualizationsSetup.types.createReactVisualization(createMetricVisTypeDefinition()); (npStart.plugins.data.fieldFormats.getType as jest.Mock).mockImplementation(() => { return fieldFormats.UrlFormat; }); diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts index ee7ead0b7331..0b8d9b17659f 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts @@ -22,9 +22,10 @@ import { i18n } from '@kbn/i18n'; import { MetricVisComponent } from './components/metric_vis_component'; import { MetricVisOptions } from './components/metric_vis_options'; import { ColorModes } from '../../vis_type_vislib/public'; -import { Schemas, AggGroupNames, colorSchemas, ColorSchemas } from './legacy_imports'; +import { Schemas, AggGroupNames } from './legacy_imports'; +import { ColorSchemas, colorSchemas } from '../../../../plugins/charts/public'; -export const metricVisTypeDefinition = { +export const createMetricVisTypeDefinition = () => ({ name: 'metric', title: i18n.translate('visTypeMetric.metricTitle', { defaultMessage: 'Metric' }), icon: 'visMetric', @@ -121,4 +122,4 @@ export const metricVisTypeDefinition = { }, ]), }, -}; +}); diff --git a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts index 413f846d7899..082fab47e573 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts @@ -22,12 +22,14 @@ import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressio import { VisualizationsSetup } from '../../visualizations/public'; import { createMetricVisFn } from './metric_vis_fn'; -import { metricVisTypeDefinition } from './metric_vis_type'; +import { createMetricVisTypeDefinition } from './metric_vis_type'; +import { ChartsPluginSetup } from '../../../../plugins/charts/public'; /** @internal */ export interface MetricVisPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; + charts: ChartsPluginSetup; } /** @internal */ @@ -38,9 +40,12 @@ export class MetricVisPlugin implements Plugin { this.initializerContext = initializerContext; } - public setup(core: CoreSetup, { expressions, visualizations }: MetricVisPluginSetupDependencies) { + public setup( + core: CoreSetup, + { expressions, visualizations, charts }: MetricVisPluginSetupDependencies + ) { expressions.registerFunction(createMetricVisFn); - visualizations.types.createReactVisualization(metricVisTypeDefinition); + visualizations.types.createReactVisualization(createMetricVisTypeDefinition()); } public start(core: CoreStart) { diff --git a/src/legacy/core_plugins/vis_type_metric/public/types.ts b/src/legacy/core_plugins/vis_type_metric/public/types.ts index 34cb1b209a3a..298eebf23027 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/types.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/types.ts @@ -17,10 +17,10 @@ * under the License. */ -import { ColorSchemas } from './legacy_imports'; import { Range } from '../../../../plugins/expressions/public'; import { SchemaConfig } from '../../visualizations/public'; import { ColorModes, Labels, Style } from '../../vis_type_vislib/public'; +import { ColorSchemas } from '../../../../plugins/charts/public'; export const visType = 'metric'; diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js index 4d4363377563..136fe51674bf 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js @@ -26,6 +26,14 @@ import { fromNode, delay } from 'bluebird'; import { ImageComparator } from 'test_utils/image_comparator'; import simpleloadPng from './simpleload.png'; +// Replace with mock when converting to jest tests +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { seedColors } from '../../../../../../plugins/charts/public/services/colors/seed_colors'; + +const colors = { + seedColors, +}; + describe('tag cloud tests', function() { const minValue = 1; const maxValue = 9; @@ -124,7 +132,7 @@ describe('tag cloud tests', function() { )}`, function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(test.data); tagCloud.setOptions(test.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -156,7 +164,7 @@ describe('tag cloud tests', function() { //TagCloud takes at least 600ms to complete (due to d3 animation) //renderComplete should only notify at the last one - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); @@ -188,7 +196,7 @@ describe('tag cloud tests', function() { describe('should use the latest state before notifying (when modifying options multiple times)', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); tagCloud.setOptions(logScaleTest.options); @@ -215,7 +223,7 @@ describe('tag cloud tests', function() { describe('should use the latest state before notifying (when modifying data multiple times)', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); tagCloud.setData(trimDataTest.data); @@ -245,7 +253,7 @@ describe('tag cloud tests', function() { counter = 0; setupDOM(); return new Promise((resolve, reject) => { - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); @@ -291,7 +299,7 @@ describe('tag cloud tests', function() { describe('should show correct data when state-updates are interleaved with resize event', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(logScaleTest.data); tagCloud.setOptions(logScaleTest.options); @@ -329,7 +337,7 @@ describe('tag cloud tests', function() { setupDOM(); domNode.style.width = '1px'; domNode.style.height = '1px'; - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -355,7 +363,7 @@ describe('tag cloud tests', function() { domNode.style.width = '1px'; domNode.style.height = '1px'; - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -380,7 +388,7 @@ describe('tag cloud tests', function() { describe(`tags should no longer fit after making container smaller`, function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -412,7 +420,7 @@ describe('tag cloud tests', function() { }); it('should render simple image', async function() { - tagCloud = new TagCloud(domNode); + tagCloud = new TagCloud(domNode, colors); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js index 0cd1fdf1d710..75cad3bc167b 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js @@ -22,11 +22,15 @@ import ngMock from 'ng_mock'; import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern'; import { Vis } from 'ui/vis'; import { ImageComparator } from 'test_utils/image_comparator'; -import { TagCloudVisualization } from '../tag_cloud_visualization'; +import { createTagCloudVisualization } from '../tag_cloud_visualization'; import basicdrawPng from './basicdraw.png'; import afterresizePng from './afterresize.png'; import afterparamChange from './afterparamchange.png'; +// Replace with mock when converting to jest tests +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { seedColors } from '../../../../../../plugins/charts/public/services/colors/seed_colors'; + const THRESHOLD = 0.65; const PIXEL_DIFF = 64; @@ -55,6 +59,11 @@ describe('TagCloudVisualizationTest', function() { { 'col-0': 'BR', 'col-1': 3 }, ], }; + const TagCloudVisualization = createTagCloudVisualization({ + colors: { + seedColors, + }, + }); beforeEach(ngMock.module('kibana')); beforeEach( diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js index 5bd64ec000a6..f5084fd92cfe 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js @@ -19,7 +19,6 @@ import d3 from 'd3'; import d3TagCloud from 'd3-cloud'; -import { seedColors } from 'ui/vis/components/color/seed_colors'; import { EventEmitter } from 'events'; const ORIENTATIONS = { @@ -38,7 +37,7 @@ const D3_SCALING_FUNCTIONS = { }; export class TagCloud extends EventEmitter { - constructor(domNode) { + constructor(domNode, colors) { super(); //DOM @@ -55,6 +54,7 @@ export class TagCloud extends EventEmitter { this._spiral = 'archimedean'; //layout shape this._timeInterval = 1000; //time allowed for layout algorithm this._padding = 5; + this._seedColors = colors.seedColors; //OPTIONS this._orientation = 'single'; @@ -208,7 +208,7 @@ export class TagCloud extends EventEmitter { enteringTags.style('font-style', this._fontStyle); enteringTags.style('font-weight', () => this._fontWeight); enteringTags.style('font-family', () => this._fontFamily); - enteringTags.style('fill', getFill); + enteringTags.style('fill', this.getFill.bind(this)); enteringTags.attr('text-anchor', () => 'middle'); enteringTags.attr('transform', affineTransform); enteringTags.attr('data-test-subj', getDisplayText); @@ -369,6 +369,11 @@ export class TagCloud extends EventEmitter { }; return debug; } + + getFill(tag) { + const colorScale = d3.scale.ordinal().range(this._seedColors); + return colorScale(tag.text); + } } TagCloud.STATUS = { COMPLETE: 0, INCOMPLETE: 1 }; @@ -402,11 +407,6 @@ function getSizeInPixels(tag) { return `${tag.size}px`; } -const colorScale = d3.scale.ordinal().range(seedColors); -function getFill(tag) { - return colorScale(tag.text); -} - function hashWithinRange(str, max) { str = JSON.stringify(str); let hash = 0; diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js index 7d6e8252d86d..f2163abbbc72 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js @@ -31,130 +31,132 @@ import { FeedbackMessage } from './feedback_message'; const MAX_TAG_COUNT = 200; -export class TagCloudVisualization { - constructor(node, vis) { - this._containerNode = node; - - const cloudRelativeContainer = document.createElement('div'); - cloudRelativeContainer.classList.add('tgcVis'); - cloudRelativeContainer.setAttribute('style', 'position: relative'); - const cloudContainer = document.createElement('div'); - cloudContainer.classList.add('tgcVis'); - cloudContainer.setAttribute('data-test-subj', 'tagCloudVisualization'); - this._containerNode.classList.add('visChart--vertical'); - cloudRelativeContainer.appendChild(cloudContainer); - this._containerNode.appendChild(cloudRelativeContainer); - - this._vis = vis; - this._truncated = false; - this._tagCloud = new TagCloud(cloudContainer); - this._tagCloud.on('select', event => { - if (!this._visParams.bucket) { - return; - } - this._vis.API.events.filter({ - table: event.meta.data, - column: 0, - row: event.meta.rowIndex, +export function createTagCloudVisualization({ colors }) { + return class TagCloudVisualization { + constructor(node, vis) { + this._containerNode = node; + + const cloudRelativeContainer = document.createElement('div'); + cloudRelativeContainer.classList.add('tgcVis'); + cloudRelativeContainer.setAttribute('style', 'position: relative'); + const cloudContainer = document.createElement('div'); + cloudContainer.classList.add('tgcVis'); + cloudContainer.setAttribute('data-test-subj', 'tagCloudVisualization'); + this._containerNode.classList.add('visChart--vertical'); + cloudRelativeContainer.appendChild(cloudContainer); + this._containerNode.appendChild(cloudRelativeContainer); + + this._vis = vis; + this._truncated = false; + this._tagCloud = new TagCloud(cloudContainer, colors); + this._tagCloud.on('select', event => { + if (!this._visParams.bucket) { + return; + } + this._vis.API.events.filter({ + table: event.meta.data, + column: 0, + row: event.meta.rowIndex, + }); }); - }); - this._renderComplete$ = Rx.fromEvent(this._tagCloud, 'renderComplete'); - - this._feedbackNode = document.createElement('div'); - this._containerNode.appendChild(this._feedbackNode); - this._feedbackMessage = React.createRef(); - render( - - - , - this._feedbackNode - ); - - this._labelNode = document.createElement('div'); - this._containerNode.appendChild(this._labelNode); - this._label = React.createRef(); - render(