From 35a5b770d3262f79645d88509b373444604195a2 Mon Sep 17 00:00:00 2001 From: Ahmad Bamieh Date: Wed, 13 Nov 2019 09:18:57 +0200 Subject: [PATCH 01/59] [Telemetry] Server side fetcher (#50015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial push * self code review * ignore node-fetch type * usageFetcher api * user agent metric * telemetry plugin collector * remove extra unused method * remove unused import * type check * fix collections tests * pass kfetch as dep * add ui metrics integration test for user agent * dont start ui metrics when not authenticated * user agent count always 1 * fix broken ui-metric integration tests * try using config.get * avoid fetching configs if sending * type unknown -> string * check if fetcher is causing the issue * disable ui_metric from functional tests * enable ui_metric back again * ignore keyword above 256 * check requesting app first * clean up after all the debugging :) * fix tests * always return 200 for ui metric reporting * remove boom import * logout after removing role/user * undo some changes in tests * inside try catch * prevent potential race conditions in priorities with = * use snake_case for telemetry plugin collection * usageFetcher -> sendUsageFrom * more replacements * remove extra unused route * config() -> config * Update src/legacy/core_plugins/telemetry/index.ts Co-Authored-By: Mike Côté * Update src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts Co-Authored-By: Mike Côté * config() -> config * fix SO update logic given the current changes * fix opt in check * triple check * check for non boolean * take into account older settings * import TelemetryOptInProvider * update test case --- packages/kbn-analytics/package.json | 2 +- packages/kbn-analytics/src/index.ts | 2 +- packages/kbn-analytics/src/metrics/index.ts | 16 +- .../kbn-analytics/src/metrics/ui_stats.ts | 28 ++-- .../kbn-analytics/src/metrics/user_agent.ts | 35 +++++ packages/kbn-analytics/src/report.ts | 61 ++++++-- packages/kbn-analytics/src/reporter.ts | 44 +++--- .../resources/bin/kibana-docker | 1 + .../telemetry/common/constants.ts | 6 + src/legacy/core_plugins/telemetry/index.ts | 56 +++---- .../core_plugins/telemetry/mappings.json | 8 + .../telemetry/public/hacks/telemetry_init.ts | 10 +- .../welcome_banner/handle_old_settings.js | 24 ++- .../public/services/telemetry_opt_in.ts | 3 + .../telemetry/server/collection_manager.ts | 66 +++++++- .../telemetry/server/collectors/index.ts | 1 + .../collectors/telemetry_plugin/index.ts | 20 +++ .../telemetry_plugin_collector.ts | 75 +++++++++ .../core_plugins/telemetry/server/fetcher.ts | 148 ++++++++++++++++++ .../core_plugins/telemetry/server/index.ts | 3 +- .../core_plugins/telemetry/server/plugin.ts | 2 +- .../telemetry/server/routes/index.ts | 4 +- .../routes/{opt_in.ts => telemetry_config.ts} | 42 +++-- .../server/routes/telemetry_stats.ts | 15 +- .../__tests__/get_local_stats.js | 57 ++----- .../telemetry_collection/get_local_stats.js | 18 +-- .../server/telemetry_collection/get_stats.ts | 29 +--- .../server/telemetry_collection/index.ts | 2 - ..._telemetry_allow_changing_opt_in_status.ts | 39 +++++ .../get_telemetry_opt_in.test.ts | 108 ++++--------- .../get_telemetry_opt_in.ts | 64 +++----- .../get_telemetry_usage_fetcher.test.ts | 85 ++++++++++ .../get_telemetry_usage_fetcher.ts | 39 +++++ .../server/telemetry_config/index.ts | 23 +++ .../telemetry_config/replace_injected_vars.ts | 63 ++++++++ .../get_telemetry_saved_object.test.ts | 104 ++++++++++++ .../get_telemetry_saved_object.ts | 43 +++++ .../server/telemetry_repository/index.ts | 29 ++++ .../update_telemetry_saved_object.ts | 38 +++++ src/legacy/core_plugins/ui_metric/index.ts | 2 +- .../ui_metric/public/hacks/ui_metric_init.ts | 21 ++- .../core_plugins/ui_metric/public/index.ts | 4 +- .../public/services/telemetry_analytics.ts | 32 ++-- .../ui_metric/server/routes/api/ui_metric.ts | 83 ++++++---- .../apis/ui_metric/ui_metric.js | 66 ++++---- test/common/config.js | 1 - .../infra/public/hooks/use_track_metric.tsx | 5 +- .../__tests__/get_all_stats.js | 28 +--- .../telemetry_collection/get_all_stats.js | 19 +-- .../get_stats_with_monitoring.ts | 31 ++-- .../get_stats_with_xpack.ts | 33 +--- .../advanced_settings_security.ts | 2 - yarn.lock | 2 +- 53 files changed, 1237 insertions(+), 505 deletions(-) create mode 100644 packages/kbn-analytics/src/metrics/user_agent.ts create mode 100644 src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/index.ts create mode 100644 src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/telemetry_plugin_collector.ts create mode 100644 src/legacy/core_plugins/telemetry/server/fetcher.ts rename src/legacy/core_plugins/telemetry/server/routes/{opt_in.ts => telemetry_config.ts} (56%) create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_allow_changing_opt_in_status.ts rename src/legacy/core_plugins/telemetry/server/{ => telemetry_config}/get_telemetry_opt_in.test.ts (63%) rename src/legacy/core_plugins/telemetry/server/{ => telemetry_config}/get_telemetry_opt_in.ts (58%) create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.test.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_repository/update_telemetry_saved_object.ts diff --git a/packages/kbn-analytics/package.json b/packages/kbn-analytics/package.json index e2f3a59e95a47c..b0ac86b465a621 100644 --- a/packages/kbn-analytics/package.json +++ b/packages/kbn-analytics/package.json @@ -17,6 +17,6 @@ "@babel/cli": "7.5.5", "@kbn/dev-utils": "1.0.0", "@kbn/babel-preset": "1.0.0", - "typescript": "3.5.1" + "typescript": "3.5.3" } } diff --git a/packages/kbn-analytics/src/index.ts b/packages/kbn-analytics/src/index.ts index 63fd115fa75945..6514347b0b1272 100644 --- a/packages/kbn-analytics/src/index.ts +++ b/packages/kbn-analytics/src/index.ts @@ -17,6 +17,6 @@ * under the License. */ -export { createReporter, ReportHTTP, Reporter, ReporterConfig } from './reporter'; +export { ReportHTTP, Reporter, ReporterConfig } from './reporter'; export { UiStatsMetricType, METRIC_TYPE } from './metrics'; export { Report, ReportManager } from './report'; diff --git a/packages/kbn-analytics/src/metrics/index.ts b/packages/kbn-analytics/src/metrics/index.ts index 13b9e5dc59e4e2..ceaf53cbc97536 100644 --- a/packages/kbn-analytics/src/metrics/index.ts +++ b/packages/kbn-analytics/src/metrics/index.ts @@ -17,21 +17,17 @@ * under the License. */ -import { UiStatsMetric, UiStatsMetricType } from './ui_stats'; +import { UiStatsMetric } from './ui_stats'; +import { UserAgentMetric } from './user_agent'; -export { - UiStatsMetric, - createUiStatsMetric, - UiStatsMetricReport, - UiStatsMetricType, -} from './ui_stats'; +export { UiStatsMetric, createUiStatsMetric, UiStatsMetricType } from './ui_stats'; export { Stats } from './stats'; +export { trackUsageAgent } from './user_agent'; -export type Metric = UiStatsMetric; -export type MetricType = keyof typeof METRIC_TYPE; - +export type Metric = UiStatsMetric | UserAgentMetric; export enum METRIC_TYPE { COUNT = 'count', LOADED = 'loaded', CLICK = 'click', + USER_AGENT = 'user_agent', } diff --git a/packages/kbn-analytics/src/metrics/ui_stats.ts b/packages/kbn-analytics/src/metrics/ui_stats.ts index 7615fd20645e28..dc8cdcd3e4a1e9 100644 --- a/packages/kbn-analytics/src/metrics/ui_stats.ts +++ b/packages/kbn-analytics/src/metrics/ui_stats.ts @@ -17,37 +17,33 @@ * under the License. */ -import { Stats } from './stats'; import { METRIC_TYPE } from './'; export type UiStatsMetricType = METRIC_TYPE.CLICK | METRIC_TYPE.LOADED | METRIC_TYPE.COUNT; -export interface UiStatsMetricConfig { - type: T; +export interface UiStatsMetricConfig { + type: UiStatsMetricType; appName: string; eventName: string; count?: number; } -export interface UiStatsMetric { - type: T; +export interface UiStatsMetric { + type: UiStatsMetricType; appName: string; eventName: string; count: number; } -export function createUiStatsMetric({ +export function createUiStatsMetric({ type, appName, eventName, count = 1, -}: UiStatsMetricConfig): UiStatsMetric { - return { type, appName, eventName, count }; -} - -export interface UiStatsMetricReport { - key: string; - appName: string; - eventName: string; - type: UiStatsMetricType; - stats: Stats; +}: UiStatsMetricConfig): UiStatsMetric { + return { + type, + appName, + eventName, + count, + }; } diff --git a/packages/kbn-analytics/src/metrics/user_agent.ts b/packages/kbn-analytics/src/metrics/user_agent.ts new file mode 100644 index 00000000000000..32282dc54bde6d --- /dev/null +++ b/packages/kbn-analytics/src/metrics/user_agent.ts @@ -0,0 +1,35 @@ +/* + * 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 { METRIC_TYPE } from './'; + +export interface UserAgentMetric { + type: METRIC_TYPE.USER_AGENT; + appName: string; + userAgent: string; +} + +export function trackUsageAgent(appName: string): UserAgentMetric { + const userAgent = (window && window.navigator && window.navigator.userAgent) || ''; + + return { + type: METRIC_TYPE.USER_AGENT, + appName, + userAgent, + }; +} diff --git a/packages/kbn-analytics/src/report.ts b/packages/kbn-analytics/src/report.ts index 6187455fa60a55..333bc05d28f9be 100644 --- a/packages/kbn-analytics/src/report.ts +++ b/packages/kbn-analytics/src/report.ts @@ -17,28 +17,47 @@ * under the License. */ -import { UnreachableCaseError } from './util'; -import { Metric, Stats, UiStatsMetricReport, METRIC_TYPE } from './metrics'; +import { UnreachableCaseError, wrapArray } from './util'; +import { Metric, Stats, UiStatsMetricType, METRIC_TYPE } from './metrics'; +const REPORT_VERSION = 1; export interface Report { + reportVersion: typeof REPORT_VERSION; uiStatsMetrics: { - [key: string]: UiStatsMetricReport; + [key: string]: { + key: string; + appName: string; + eventName: string; + type: UiStatsMetricType; + stats: Stats; + }; + }; + userAgent?: { + [key: string]: { + userAgent: string; + key: string; + type: METRIC_TYPE.USER_AGENT; + appName: string; + }; }; } export class ReportManager { + static REPORT_VERSION = REPORT_VERSION; public report: Report; constructor(report?: Report) { this.report = report || ReportManager.createReport(); } - static createReport() { - return { uiStatsMetrics: {} }; + static createReport(): Report { + return { reportVersion: REPORT_VERSION, uiStatsMetrics: {} }; } public clearReport() { this.report = ReportManager.createReport(); } public isReportEmpty(): boolean { - return Object.keys(this.report.uiStatsMetrics).length === 0; + const noUiStats = Object.keys(this.report.uiStatsMetrics).length === 0; + const noUserAgent = !this.report.userAgent || Object.keys(this.report.userAgent).length === 0; + return noUiStats && noUserAgent; } private incrementStats(count: number, stats?: Stats): Stats { const { min = 0, max = 0, sum = 0 } = stats || {}; @@ -54,28 +73,46 @@ export class ReportManager { sum: newSum, }; } - assignReports(newMetrics: Metric[]) { - newMetrics.forEach(newMetric => this.assignReport(this.report, newMetric)); + assignReports(newMetrics: Metric | Metric[]) { + wrapArray(newMetrics).forEach(newMetric => this.assignReport(this.report, newMetric)); } static createMetricKey(metric: Metric): string { switch (metric.type) { + case METRIC_TYPE.USER_AGENT: { + const { appName, type } = metric; + return `${appName}-${type}`; + } case METRIC_TYPE.CLICK: case METRIC_TYPE.LOADED: case METRIC_TYPE.COUNT: { - const { appName, type, eventName } = metric; + const { appName, eventName, type } = metric; return `${appName}-${type}-${eventName}`; } default: - throw new UnreachableCaseError(metric.type); + throw new UnreachableCaseError(metric); } } private assignReport(report: Report, metric: Metric) { + const key = ReportManager.createMetricKey(metric); switch (metric.type) { + case METRIC_TYPE.USER_AGENT: { + const { appName, type, userAgent } = metric; + if (userAgent) { + this.report.userAgent = { + [key]: { + key, + appName, + type, + userAgent: metric.userAgent, + }, + }; + } + return; + } case METRIC_TYPE.CLICK: case METRIC_TYPE.LOADED: case METRIC_TYPE.COUNT: { const { appName, type, eventName, count } = metric; - const key = ReportManager.createMetricKey(metric); const existingStats = (report.uiStatsMetrics[key] || {}).stats; this.report.uiStatsMetrics[key] = { key, @@ -87,7 +124,7 @@ export class ReportManager { return; } default: - throw new UnreachableCaseError(metric.type); + throw new UnreachableCaseError(metric); } } } diff --git a/packages/kbn-analytics/src/reporter.ts b/packages/kbn-analytics/src/reporter.ts index 37d23aa4430902..98e29c1e4329eb 100644 --- a/packages/kbn-analytics/src/reporter.ts +++ b/packages/kbn-analytics/src/reporter.ts @@ -18,7 +18,7 @@ */ import { wrapArray } from './util'; -import { Metric, UiStatsMetric, createUiStatsMetric } from './metrics'; +import { Metric, createUiStatsMetric, trackUsageAgent, UiStatsMetricType } from './metrics'; import { Storage, ReportStorageManager } from './storage'; import { Report, ReportManager } from './report'; @@ -40,10 +40,11 @@ export class Reporter { private reportManager: ReportManager; private storageManager: ReportStorageManager; private debug: boolean; + private retryCount = 0; + private readonly maxRetries = 3; constructor(config: ReporterConfig) { - const { http, storage, debug, checkInterval = 10000, storageKey = 'analytics' } = config; - + const { http, storage, debug, checkInterval = 90000, storageKey = 'analytics' } = config; this.http = http; this.checkInterval = checkInterval; this.interval = null; @@ -59,18 +60,19 @@ export class Reporter { } private flushReport() { + this.retryCount = 0; this.reportManager.clearReport(); this.storageManager.store(this.reportManager.report); } - public start() { + public start = () => { if (!this.interval) { this.interval = setTimeout(() => { this.interval = null; this.sendReports(); }, this.checkInterval); } - } + }; private log(message: any) { if (this.debug) { @@ -79,36 +81,42 @@ export class Reporter { } } - public reportUiStats( + public reportUiStats = ( appName: string, - type: UiStatsMetric['type'], + type: UiStatsMetricType, eventNames: string | string[], count?: number - ) { + ) => { const metrics = wrapArray(eventNames).map(eventName => { - if (this) this.log(`${type} Metric -> (${appName}:${eventName}):`); + this.log(`${type} Metric -> (${appName}:${eventName}):`); const report = createUiStatsMetric({ type, appName, eventName, count }); this.log(report); return report; }); this.saveToReport(metrics); - } + }; + + public reportUserAgent = (appName: string) => { + this.log(`Reporting user-agent.`); + const report = trackUsageAgent(appName); + this.saveToReport([report]); + }; - public async sendReports() { + public sendReports = async () => { if (!this.reportManager.isReportEmpty()) { try { await this.http(this.reportManager.report); this.flushReport(); } catch (err) { this.log(`Error Sending Metrics Report ${err}`); + this.retryCount = this.retryCount + 1; + const versionMismatch = + this.reportManager.report.reportVersion !== ReportManager.REPORT_VERSION; + if (versionMismatch || this.retryCount > this.maxRetries) { + this.flushReport(); + } } } this.start(); - } -} - -export function createReporter(reportedConf: ReporterConfig) { - const reporter = new Reporter(reportedConf); - reporter.start(); - return reporter; + }; } diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker index 0926ef365c894c..6609b905b81eca 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker @@ -181,6 +181,7 @@ kibana_vars=( xpack.security.secureCookies xpack.security.sessionTimeout telemetry.enabled + telemetry.sendUsageFrom ) longopts='' diff --git a/src/legacy/core_plugins/telemetry/common/constants.ts b/src/legacy/core_plugins/telemetry/common/constants.ts index d7f34d1f8f8eb0..7b0c62276f2902 100644 --- a/src/legacy/core_plugins/telemetry/common/constants.ts +++ b/src/legacy/core_plugins/telemetry/common/constants.ts @@ -59,6 +59,12 @@ export const PRIVACY_STATEMENT_URL = `https://www.elastic.co/legal/privacy-state */ export const KIBANA_LOCALIZATION_STATS_TYPE = 'localization'; +/** + * The type name used to publish telemetry plugin stats. + * @type {string} + */ +export const TELEMETRY_STATS_TYPE = 'telemetry'; + /** * UI metric usage type * @type {string} diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 50a25423b5eb82..149fa99938563c 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -27,12 +27,13 @@ import { i18n } from '@kbn/i18n'; import mappings from './mappings.json'; import { CONFIG_TELEMETRY, getConfigTelemetryDesc } from './common/constants'; import { getXpackConfigWithDeprecated } from './common/get_xpack_config_with_deprecated'; -import { telemetryPlugin, getTelemetryOptIn } from './server'; +import { telemetryPlugin, replaceTelemetryInjectedVars, FetcherTask } from './server'; import { createLocalizationUsageCollector, createTelemetryUsageCollector, createUiMetricUsageCollector, + createTelemetryPluginUsageCollector, } from './server/collectors'; const ENDPOINT_VERSION = 'v2'; @@ -46,20 +47,18 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), + allowChangingOptInStatus: Joi.boolean().default(true), optIn: Joi.when('allowChangingOptInStatus', { is: false, - then: Joi.valid(true), + then: Joi.valid(true).required(), otherwise: Joi.boolean() .allow(null) .default(null), }), - allowChangingOptInStatus: Joi.boolean().default(true), + // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), banner: Joi.boolean().default(true), - lastVersionChecked: Joi.string() - .allow('') - .default(''), url: Joi.when('$dev', { is: true, then: Joi.string().default( @@ -69,6 +68,9 @@ const telemetry = (kibana: any) => { `https://telemetry.elastic.co/xpack/${ENDPOINT_VERSION}/send` ), }), + sendUsageFrom: Joi.string() + .allow(['server', 'browser']) + .default('browser'), }).default(); }, uiExports: { @@ -89,30 +91,8 @@ const telemetry = (kibana: any) => { }, }, async replaceInjectedVars(originalInjectedVars: any, request: any) { - const config = request.server.config(); - const optIn = config.get('telemetry.optIn'); - const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); - const currentKibanaVersion = getCurrentKibanaVersion(request.server); - let telemetryOptedIn: boolean | null; - - if (typeof optIn === 'boolean' && !allowChangingOptInStatus) { - // When not allowed to change optIn status and an optIn value is set, we'll overwrite with that - telemetryOptedIn = optIn; - } else { - telemetryOptedIn = await getTelemetryOptIn({ - request, - currentKibanaVersion, - }); - if (telemetryOptedIn === null) { - // In the senario there's no value set in telemetryOptedIn, we'll return optIn value - telemetryOptedIn = optIn; - } - } - - return { - ...originalInjectedVars, - telemetryOptedIn, - }; + const telemetryInjectedVars = await replaceTelemetryInjectedVars(request); + return Object.assign({}, originalInjectedVars, telemetryInjectedVars); }, injectDefaultVars(server: Server) { const config = server.config(); @@ -124,16 +104,21 @@ const telemetry = (kibana: any) => { getXpackConfigWithDeprecated(config, 'telemetry.banner'), telemetryOptedIn: config.get('telemetry.optIn'), allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), + telemetrySendUsageFrom: config.get('telemetry.sendUsageFrom'), }; }, hacks: ['plugins/telemetry/hacks/telemetry_init', 'plugins/telemetry/hacks/telemetry_opt_in'], mappings, }, - async init(server: Server) { + postInit(server: Server) { + const fetcherTask = new FetcherTask(server); + fetcherTask.start(); + }, + init(server: Server) { const initializerContext = { env: { packageInfo: { - version: getCurrentKibanaVersion(server), + version: server.config().get('pkg.version'), }, }, config: { @@ -156,9 +141,10 @@ const telemetry = (kibana: any) => { log: server.log, } as any) as CoreSetup; - await telemetryPlugin(initializerContext).setup(coreSetup); + telemetryPlugin(initializerContext).setup(coreSetup); // register collectors + server.usage.collectorSet.register(createTelemetryPluginUsageCollector(server)); server.usage.collectorSet.register(createLocalizationUsageCollector(server)); server.usage.collectorSet.register(createTelemetryUsageCollector(server)); server.usage.collectorSet.register(createUiMetricUsageCollector(server)); @@ -168,7 +154,3 @@ const telemetry = (kibana: any) => { // eslint-disable-next-line import/no-default-export export default telemetry; - -function getCurrentKibanaVersion(server: Server): string { - return server.config().get('pkg.version'); -} diff --git a/src/legacy/core_plugins/telemetry/mappings.json b/src/legacy/core_plugins/telemetry/mappings.json index 1245ef88f58929..95c6ebfc7dc793 100644 --- a/src/legacy/core_plugins/telemetry/mappings.json +++ b/src/legacy/core_plugins/telemetry/mappings.json @@ -4,7 +4,15 @@ "enabled": { "type": "boolean" }, + "sendUsageFrom": { + "ignore_above": 256, + "type": "keyword" + }, + "lastReported": { + "type": "date" + }, "lastVersionChecked": { + "ignore_above": 256, "type": "keyword" } } diff --git a/src/legacy/core_plugins/telemetry/public/hacks/telemetry_init.ts b/src/legacy/core_plugins/telemetry/public/hacks/telemetry_init.ts index 364871380a529c..1930d65d5c09b9 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/telemetry_init.ts +++ b/src/legacy/core_plugins/telemetry/public/hacks/telemetry_init.ts @@ -25,13 +25,21 @@ import { isUnauthenticated } from '../services'; import { Telemetry } from './telemetry'; // @ts-ignore import { fetchTelemetry } from './fetch_telemetry'; +// @ts-ignore +import { isOptInHandleOldSettings } from './welcome_banner/handle_old_settings'; +import { TelemetryOptInProvider } from '../services'; function telemetryInit($injector: any) { const $http = $injector.get('$http'); + const Private = $injector.get('Private'); + const config = $injector.get('config'); + const telemetryOptInProvider = Private(TelemetryOptInProvider); const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled'); + const telemetryOptedIn = isOptInHandleOldSettings(config, telemetryOptInProvider); + const sendUsageFrom = npStart.core.injectedMetadata.getInjectedVar('telemetrySendUsageFrom'); - if (telemetryEnabled) { + if (telemetryEnabled && telemetryOptedIn && sendUsageFrom === 'browser') { // no telemetry for non-logged in users if (isUnauthenticated()) { return; diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.js index 31091e19520533..4f0f2983477e07 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.js @@ -27,8 +27,9 @@ import { CONFIG_TELEMETRY } from '../../../common/constants'; * @param {Object} config The advanced settings config object. * @return {Boolean} {@code true} if the banner should still be displayed. {@code false} if the banner should not be displayed. */ +const CONFIG_ALLOW_REPORT = 'xPackMonitoring:allowReport'; + export async function handleOldSettings(config, telemetryOptInProvider) { - const CONFIG_ALLOW_REPORT = 'xPackMonitoring:allowReport'; const CONFIG_SHOW_BANNER = 'xPackMonitoring:showBanner'; const oldAllowReportSetting = config.get(CONFIG_ALLOW_REPORT, null); const oldTelemetrySetting = config.get(CONFIG_TELEMETRY, null); @@ -62,3 +63,24 @@ export async function handleOldSettings(config, telemetryOptInProvider) { return true; } + + +export async function isOptInHandleOldSettings(config, telemetryOptInProvider) { + const currentOptInSettting = telemetryOptInProvider.getOptIn(); + + if (typeof currentOptInSettting === 'boolean') { + return currentOptInSettting; + } + + const oldTelemetrySetting = config.get(CONFIG_TELEMETRY, null); + if (typeof oldTelemetrySetting === 'boolean') { + return oldTelemetrySetting; + } + + const oldAllowReportSetting = config.get(CONFIG_ALLOW_REPORT, null); + if (typeof oldAllowReportSetting === 'boolean') { + return oldAllowReportSetting; + } + + return null; +} diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts index 4d27bad352cd4d..f7b09b1befafaf 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts @@ -41,6 +41,9 @@ export function TelemetryOptInProvider($injector: any, chrome: any) { bannerId = id; }, setOptIn: async (enabled: boolean) => { + if (!allowChangingOptInStatus) { + return; + } setCanTrackUiMetrics(enabled); const $http = $injector.get('$http'); diff --git a/src/legacy/core_plugins/telemetry/server/collection_manager.ts b/src/legacy/core_plugins/telemetry/server/collection_manager.ts index fef0a9b0f9f40b..19bc735b9a965d 100644 --- a/src/legacy/core_plugins/telemetry/server/collection_manager.ts +++ b/src/legacy/core_plugins/telemetry/server/collection_manager.ts @@ -17,20 +17,72 @@ * under the License. */ -class TelemetryCollectionManager { - private getterMethod?: any; +import { encryptTelemetry } from './collectors'; + +export type EncryptedStatsGetterConfig = { unencrypted: false } & { + server: any; + start: any; + end: any; + isDev: boolean; +}; + +export type UnencryptedStatsGetterConfig = { unencrypted: true } & { + req: any; + start: any; + end: any; + isDev: boolean; +}; + +export interface StatsCollectionConfig { + callCluster: any; + server: any; + start: any; + end: any; +} + +export type StatsGetterConfig = UnencryptedStatsGetterConfig | EncryptedStatsGetterConfig; + +export type StatsGetter = (config: StatsGetterConfig) => Promise; + +export const getStatsCollectionConfig = ( + config: StatsGetterConfig, + esClustser: string +): StatsCollectionConfig => { + const { start, end } = config; + const server = config.unencrypted ? config.req.server : config.server; + const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster( + esClustser + ); + const callCluster = config.unencrypted + ? (...args: any[]) => callWithRequest(config.req, ...args) + : callWithInternalUser; + + return { server, callCluster, start, end }; +}; + +export class TelemetryCollectionManager { + private getterMethod?: StatsGetter; private collectionTitle?: string; - private getterMethodPriority = 0; + private getterMethodPriority = -1; - public setStatsGetter = (statsGetter: any, title: string, priority = 0) => { - if (priority >= this.getterMethodPriority) { + public setStatsGetter = (statsGetter: StatsGetter, title: string, priority = 0) => { + if (priority > this.getterMethodPriority) { this.getterMethod = statsGetter; this.collectionTitle = title; this.getterMethodPriority = priority; } }; - getCollectionTitle = () => { + private getStats = async (config: StatsGetterConfig) => { + if (!this.getterMethod) { + throw Error('Stats getter method not set.'); + } + const usageData = await this.getterMethod(config); + + if (config.unencrypted) return usageData; + return encryptTelemetry(usageData, config.isDev); + }; + public getCollectionTitle = () => { return this.collectionTitle; }; @@ -39,7 +91,7 @@ class TelemetryCollectionManager { throw Error('Stats getter method not set.'); } return { - getStats: this.getterMethod, + getStats: this.getStats, priority: this.getterMethodPriority, title: this.collectionTitle, }; diff --git a/src/legacy/core_plugins/telemetry/server/collectors/index.ts b/src/legacy/core_plugins/telemetry/server/collectors/index.ts index 0bc1d50fab1be6..f963ecec0477cf 100644 --- a/src/legacy/core_plugins/telemetry/server/collectors/index.ts +++ b/src/legacy/core_plugins/telemetry/server/collectors/index.ts @@ -21,3 +21,4 @@ export { encryptTelemetry } from './encryption'; export { createTelemetryUsageCollector } from './usage'; export { createUiMetricUsageCollector } from './ui_metric'; export { createLocalizationUsageCollector } from './localization'; +export { createTelemetryPluginUsageCollector } from './telemetry_plugin'; diff --git a/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/index.ts b/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/index.ts new file mode 100644 index 00000000000000..e96c47741f79c9 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { createTelemetryPluginUsageCollector } from './telemetry_plugin_collector'; diff --git a/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/telemetry_plugin_collector.ts b/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/telemetry_plugin_collector.ts new file mode 100644 index 00000000000000..e092ceb5e85932 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/collectors/telemetry_plugin/telemetry_plugin_collector.ts @@ -0,0 +1,75 @@ +/* + * 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 { TELEMETRY_STATS_TYPE } from '../../../common/constants'; +import { getTelemetrySavedObject, TelemetrySavedObject } from '../../telemetry_repository'; +import { getTelemetryOptIn, getTelemetryUsageFetcher } from '../../telemetry_config'; +export interface TelemetryUsageStats { + opt_in_status?: boolean | null; + usage_fetcher?: 'browser' | 'server'; + last_reported?: number; +} + +export function createCollectorFetch(server: any) { + return async function fetchUsageStats(): Promise { + const config = server.config(); + const configTelemetrySendUsageFrom = config.get('telemetry.sendUsageFrom'); + const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); + const configTelemetryOptIn = config.get('telemetry.optIn'); + const currentKibanaVersion = config.get('pkg.version'); + + let telemetrySavedObject: TelemetrySavedObject = {}; + + try { + const { getSavedObjectsRepository } = server.savedObjects; + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); + const internalRepository = getSavedObjectsRepository(callWithInternalUser); + telemetrySavedObject = await getTelemetrySavedObject(internalRepository); + } catch (err) { + // no-op + } + + return { + opt_in_status: getTelemetryOptIn({ + currentKibanaVersion, + telemetrySavedObject, + allowChangingOptInStatus, + configTelemetryOptIn, + }), + last_reported: telemetrySavedObject ? telemetrySavedObject.lastReported : undefined, + usage_fetcher: getTelemetryUsageFetcher({ + telemetrySavedObject, + configTelemetrySendUsageFrom, + }), + }; + }; +} + +/* + * @param {Object} server + * @return {Object} kibana usage stats type collection object + */ +export function createTelemetryPluginUsageCollector(server: any) { + const { collectorSet } = server.usage; + return collectorSet.makeUsageCollector({ + type: TELEMETRY_STATS_TYPE, + isReady: () => true, + fetch: createCollectorFetch(server), + }); +} diff --git a/src/legacy/core_plugins/telemetry/server/fetcher.ts b/src/legacy/core_plugins/telemetry/server/fetcher.ts new file mode 100644 index 00000000000000..43883395eac99c --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/fetcher.ts @@ -0,0 +1,148 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; +// @ts-ignore +import fetch from 'node-fetch'; +import { telemetryCollectionManager } from './collection_manager'; +import { getTelemetryOptIn, getTelemetryUsageFetcher } from './telemetry_config'; +import { getTelemetrySavedObject, updateTelemetrySavedObject } from './telemetry_repository'; +import { REPORT_INTERVAL_MS } from '../common/constants'; +import { getXpackConfigWithDeprecated } from '../common/get_xpack_config_with_deprecated'; + +export class FetcherTask { + private readonly checkDurationMs = 60 * 1000 * 5; + private intervalId?: NodeJS.Timeout; + private lastReported?: number; + private isSending = false; + private server: any; + + constructor(server: any) { + this.server = server; + } + + private getInternalRepository = () => { + const { getSavedObjectsRepository } = this.server.savedObjects; + const { callWithInternalUser } = this.server.plugins.elasticsearch.getCluster('admin'); + const internalRepository = getSavedObjectsRepository(callWithInternalUser); + return internalRepository; + }; + + private getCurrentConfigs = async () => { + const internalRepository = this.getInternalRepository(); + const telemetrySavedObject = await getTelemetrySavedObject(internalRepository); + const config = this.server.config(); + const currentKibanaVersion = config.get('pkg.version'); + const configTelemetrySendUsageFrom = config.get('telemetry.sendUsageFrom'); + const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); + const configTelemetryOptIn = config.get('telemetry.optIn'); + const telemetryUrl = getXpackConfigWithDeprecated(config, 'telemetry.url') as string; + + return { + telemetryOptIn: getTelemetryOptIn({ + currentKibanaVersion, + telemetrySavedObject, + allowChangingOptInStatus, + configTelemetryOptIn, + }), + telemetrySendUsageFrom: getTelemetryUsageFetcher({ + telemetrySavedObject, + configTelemetrySendUsageFrom, + }), + telemetryUrl, + }; + }; + + private updateLastReported = async () => { + const internalRepository = this.getInternalRepository(); + this.lastReported = Date.now(); + updateTelemetrySavedObject(internalRepository, { + lastReported: this.lastReported, + }); + }; + + private shouldSendReport = ({ telemetryOptIn, telemetrySendUsageFrom }: any) => { + if (telemetryOptIn && telemetrySendUsageFrom === 'server') { + if (!this.lastReported || Date.now() - this.lastReported > REPORT_INTERVAL_MS) { + return true; + } + } + return false; + }; + + private fetchTelemetry = async () => { + const { getStats, title } = telemetryCollectionManager.getStatsGetter(); + this.server.log(['debug', 'telemetry', 'fetcher'], `Fetching usage using ${title} getter.`); + const config = this.server.config(); + + return await getStats({ + unencrypted: false, + server: this.server, + start: moment() + .subtract(20, 'minutes') + .toISOString(), + end: moment().toISOString(), + isDev: config.get('env.dev'), + }); + }; + + private sendTelemetry = async (url: string, cluster: any): Promise => { + this.server.log(['debug', 'telemetry', 'fetcher'], `Sending usage stats.`); + await fetch(url, { + method: 'post', + body: cluster, + }); + }; + + private sendIfDue = async () => { + if (this.isSending) { + return; + } + try { + const telemetryConfig = await this.getCurrentConfigs(); + if (!this.shouldSendReport(telemetryConfig)) { + return; + } + + // mark that we are working so future requests are ignored until we're done + this.isSending = true; + const clusters = await this.fetchTelemetry(); + for (const cluster of clusters) { + await this.sendTelemetry(telemetryConfig.telemetryUrl, cluster); + } + + await this.updateLastReported(); + } catch (err) { + this.server.log( + ['warning', 'telemetry', 'fetcher'], + `Error sending telemetry usage data: ${err}` + ); + } + this.isSending = false; + }; + + public start = () => { + this.intervalId = setInterval(() => this.sendIfDue(), this.checkDurationMs); + }; + public stop = () => { + if (this.intervalId) { + clearInterval(this.intervalId); + } + }; +} diff --git a/src/legacy/core_plugins/telemetry/server/index.ts b/src/legacy/core_plugins/telemetry/server/index.ts index aa13fab9a5f819..02752ca773488e 100644 --- a/src/legacy/core_plugins/telemetry/server/index.ts +++ b/src/legacy/core_plugins/telemetry/server/index.ts @@ -21,7 +21,8 @@ import { PluginInitializerContext } from 'src/core/server'; import { TelemetryPlugin } from './plugin'; import * as constants from '../common/constants'; -export { getTelemetryOptIn } from './get_telemetry_opt_in'; +export { FetcherTask } from './fetcher'; +export { replaceTelemetryInjectedVars } from './telemetry_config'; export { telemetryCollectionManager } from './collection_manager'; export const telemetryPlugin = (initializerContext: PluginInitializerContext) => diff --git a/src/legacy/core_plugins/telemetry/server/plugin.ts b/src/legacy/core_plugins/telemetry/server/plugin.ts index 813aa0df09e8c8..a5f0f1234799a4 100644 --- a/src/legacy/core_plugins/telemetry/server/plugin.ts +++ b/src/legacy/core_plugins/telemetry/server/plugin.ts @@ -29,7 +29,7 @@ export class TelemetryPlugin { this.currentKibanaVersion = initializerContext.env.packageInfo.version; } - public async setup(core: CoreSetup) { + public setup(core: CoreSetup) { const currentKibanaVersion = this.currentKibanaVersion; telemetryCollectionManager.setStatsGetter(getStats, 'local'); registerRoutes({ core, currentKibanaVersion }); diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 549b3ef6068ec4..93654f64705552 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -18,7 +18,7 @@ */ import { CoreSetup } from 'src/core/server'; -import { registerOptInRoutes } from './opt_in'; +import { registerTelemetryConfigRoutes } from './telemetry_config'; import { registerTelemetryDataRoutes } from './telemetry_stats'; interface RegisterRoutesParams { @@ -27,6 +27,6 @@ interface RegisterRoutesParams { } export function registerRoutes({ core, currentKibanaVersion }: RegisterRoutesParams) { + registerTelemetryConfigRoutes({ core, currentKibanaVersion }); registerTelemetryDataRoutes(core); - registerOptInRoutes({ core, currentKibanaVersion }); } diff --git a/src/legacy/core_plugins/telemetry/server/routes/opt_in.ts b/src/legacy/core_plugins/telemetry/server/routes/telemetry_config.ts similarity index 56% rename from src/legacy/core_plugins/telemetry/server/routes/opt_in.ts rename to src/legacy/core_plugins/telemetry/server/routes/telemetry_config.ts index 3a7194890b5700..440f83277340ab 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/opt_in.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/telemetry_config.ts @@ -20,18 +20,21 @@ import Joi from 'joi'; import { boomify } from 'boom'; import { CoreSetup } from 'src/core/server'; +import { getTelemetryAllowChangingOptInStatus } from '../telemetry_config'; +import { + TelemetrySavedObjectAttributes, + updateTelemetrySavedObject, +} from '../telemetry_repository'; interface RegisterOptInRoutesParams { core: CoreSetup; currentKibanaVersion: string; } -export interface SavedObjectAttributes { - enabled?: boolean; - lastVersionChecked: string; -} - -export function registerOptInRoutes({ core, currentKibanaVersion }: RegisterOptInRoutesParams) { +export function registerTelemetryConfigRoutes({ + core, + currentKibanaVersion, +}: RegisterOptInRoutesParams) { const { server } = core.http as any; server.route({ @@ -45,17 +48,24 @@ export function registerOptInRoutes({ core, currentKibanaVersion }: RegisterOptI }, }, handler: async (req: any, h: any) => { - const savedObjectsClient = req.getSavedObjectsClient(); - const savedObject: SavedObjectAttributes = { - enabled: req.payload.enabled, - lastVersionChecked: currentKibanaVersion, - }; - const options = { - id: 'telemetry', - overwrite: true, - }; try { - await savedObjectsClient.create('telemetry', savedObject, options); + const attributes: TelemetrySavedObjectAttributes = { + enabled: req.payload.enabled, + lastVersionChecked: currentKibanaVersion, + }; + const config = req.server.config(); + const savedObjectsClient = req.getSavedObjectsClient(); + const configTelemetryAllowChangingOptInStatus = config.get( + 'telemetry.allowChangingOptInStatus' + ); + const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({ + telemetrySavedObject: savedObjectsClient, + configTelemetryAllowChangingOptInStatus, + }); + if (!allowChangingOptInStatus) { + return h.response({ error: 'Not allowed to change Opt-in Status.' }).code(400); + } + await updateTelemetrySavedObject(savedObjectsClient, attributes); } catch (err) { return boomify(err); } diff --git a/src/legacy/core_plugins/telemetry/server/routes/telemetry_stats.ts b/src/legacy/core_plugins/telemetry/server/routes/telemetry_stats.ts index 8a91d24b34ed21..e87c041a263a5e 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/telemetry_stats.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/telemetry_stats.ts @@ -20,7 +20,6 @@ import Joi from 'joi'; import { boomify } from 'boom'; import { CoreSetup } from 'src/core/server'; -import { encryptTelemetry } from '../collectors'; import { telemetryCollectionManager } from '../collection_manager'; export function registerTelemetryDataRoutes(core: CoreSetup) { @@ -49,12 +48,16 @@ export function registerTelemetryDataRoutes(core: CoreSetup) { try { const { getStats, title } = telemetryCollectionManager.getStatsGetter(); - server.log(['debug', 'telemetry'], `Using Stats Getter: ${title}`); + server.log(['debug', 'telemetry', 'fetcher'], `Fetching usage using ${title} getter.`); - const usageData = await getStats(req, config, start, end, unencrypted); - - if (unencrypted) return usageData; - return encryptTelemetry(usageData, isDev); + return await getStats({ + unencrypted, + server, + req, + start, + end, + isDev, + }); } catch (err) { if (isDev) { // don't ignore errors when running in dev mode diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js b/src/legacy/core_plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js index d0de9cc365a712..261012e594b1c0 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js @@ -26,7 +26,6 @@ import { mockGetClusterStats } from './get_cluster_stats'; import { omit } from 'lodash'; import { getLocalStats, - getLocalStatsWithCaller, handleLocalStats, } from '../get_local_stats'; @@ -153,7 +152,7 @@ describe('get_local_stats', () => { }); }); - describe('getLocalStatsWithCaller', () => { + describe('getLocalStats', () => { it('returns expected object without xpack data when X-Pack fails to respond', async () => { const callClusterUsageFailed = sinon.stub(); @@ -162,8 +161,10 @@ describe('get_local_stats', () => { Promise.resolve(clusterInfo), Promise.resolve(clusterStats), ); - - const result = await getLocalStatsWithCaller(getMockServer(), callClusterUsageFailed); + const result = await getLocalStats({ + server: getMockServer(), + callCluster: callClusterUsageFailed, + }); expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid); expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name); expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats); @@ -184,51 +185,13 @@ describe('get_local_stats', () => { Promise.resolve(clusterStats), ); - const result = await getLocalStatsWithCaller(getMockServer(callCluster, kibana), callCluster); + const result = await getLocalStats({ + server: getMockServer(callCluster, kibana), + callCluster, + }); + expect(result.stack_stats.xpack).to.eql(combinedStatsResult.stack_stats.xpack); expect(result.stack_stats.kibana).to.eql(combinedStatsResult.stack_stats.kibana); }); }); - - describe('getLocalStats', () => { - it('uses callWithInternalUser from data cluster', async () => { - const getCluster = sinon.stub(); - const req = { server: getMockServer(getCluster) }; - const callWithInternalUser = sinon.stub(); - - getCluster.withArgs('data').returns({ callWithInternalUser }); - - mockGetLocalStats( - callWithInternalUser, - Promise.resolve(clusterInfo), - Promise.resolve(clusterStats), - ); - - const result = await getLocalStats(req, { useInternalUser: true }); - expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid); - expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name); - expect(result.version).to.eql(combinedStatsResult.version); - expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats); - }); - it('uses callWithRequest from data cluster', async () => { - const getCluster = sinon.stub(); - const req = { server: getMockServer(getCluster) }; - const callWithRequest = sinon.stub(); - - getCluster.withArgs('data').returns({ callWithRequest }); - - mockGetLocalStats( - callWithRequest, - Promise.resolve(clusterInfo), - Promise.resolve(clusterStats), - req - ); - - const result = await getLocalStats(req, { useInternalUser: false }); - expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid); - expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name); - expect(result.version).to.eql(combinedStatsResult.version); - expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats); - }); - }); }); diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.js b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.js index 67fc721306c213..6125dadc3646f4 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.js +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.js @@ -51,7 +51,7 @@ export function handleLocalStats(server, clusterInfo, clusterStats, kibana) { * @param {function} callCluster The callWithInternalUser handler (exposed for testing) * @return {Promise} The object containing the current Elasticsearch cluster's telemetry. */ -export async function getLocalStatsWithCaller(server, callCluster) { +export async function getLocalStats({ server, callCluster }) { const [ clusterInfo, clusterStats, kibana ] = await Promise.all([ getClusterInfo(callCluster), // cluster info getClusterStats(callCluster), // cluster stats (not to be confused with cluster _state_) @@ -60,19 +60,3 @@ export async function getLocalStatsWithCaller(server, callCluster) { return handleLocalStats(server, clusterInfo, clusterStats, kibana); } - - -/** - * Get statistics for the connected Elasticsearch cluster. - * - * @param {Object} req The incoming request - * @param {Boolean} useRequestUser callWithRequest, otherwise callWithInternalUser - * @return {Promise} The cluster object containing telemetry. - */ -export async function getLocalStats(req, { useInternalUser = false } = {}) { - const { server } = req; - const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster('data'); - const callCluster = useInternalUser ? callWithInternalUser : (...args) => callWithRequest(req, ...args); - - return await getLocalStatsWithCaller(server, callCluster); -} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_stats.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_stats.ts index 024272e0f805ca..b739b20545678a 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_stats.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_stats.ts @@ -19,27 +19,10 @@ // @ts-ignore import { getLocalStats } from './get_local_stats'; +import { StatsGetter, getStatsCollectionConfig } from '../collection_manager'; -/** - * Get the telemetry data. - * - * @param {Object} req The incoming request. - * @param {Object} config Kibana config. - * @param {String} start The start time of the request (likely 20m ago). - * @param {String} end The end time of the request. - * @param {Boolean} unencrypted Is the request payload going to be unencrypted. - * @return {Promise} An array of telemetry objects. - */ -export async function getStats( - req: any, - config: any, - start: string, - end: string, - unencrypted: boolean -) { - return [ - await getLocalStats(req, { - useInternalUser: !unencrypted, - }), - ]; -} +export const getStats: StatsGetter = async function(config) { + const { callCluster, server } = getStatsCollectionConfig(config, 'data'); + + return [await getLocalStats({ callCluster, server })]; +}; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts index f33727d82f44ce..f54aaf0ce1bc04 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts @@ -19,6 +19,4 @@ // @ts-ignore export { getLocalStats } from './get_local_stats'; - -// @ts-ignore export { getStats } from './get_stats'; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_allow_changing_opt_in_status.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_allow_changing_opt_in_status.ts new file mode 100644 index 00000000000000..9fa4fbc5e0227c --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_allow_changing_opt_in_status.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; + +interface GetTelemetryAllowChangingOptInStatus { + configTelemetryAllowChangingOptInStatus: boolean; + telemetrySavedObject: TelemetrySavedObject; +} + +export function getTelemetryAllowChangingOptInStatus({ + telemetrySavedObject, + configTelemetryAllowChangingOptInStatus, +}: GetTelemetryAllowChangingOptInStatus) { + if (!telemetrySavedObject) { + return configTelemetryAllowChangingOptInStatus; + } + + if (typeof telemetrySavedObject.telemetryAllowChangingOptInStatus === 'undefined') { + return configTelemetryAllowChangingOptInStatus; + } + + return telemetrySavedObject.telemetryAllowChangingOptInStatus; +} diff --git a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.test.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.test.ts similarity index 63% rename from src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.test.ts rename to src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.test.ts index 67ad3aaae427d9..efc4a020e0ff05 100644 --- a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.test.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.test.ts @@ -18,72 +18,47 @@ */ import { getTelemetryOptIn } from './get_telemetry_opt_in'; +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; -describe('get_telemetry_opt_in', () => { - it('returns false when request path is not /app*', async () => { - const params = getCallGetTelemetryOptInParams({ - requestPath: '/foo/bar', - }); - - const result = await callGetTelemetryOptIn(params); - - expect(result).toBe(false); - }); - - it('returns null when saved object not found', async () => { +describe('getTelemetryOptIn', () => { + it('returns null when saved object not found', () => { const params = getCallGetTelemetryOptInParams({ savedObjectNotFound: true, }); - const result = await callGetTelemetryOptIn(params); + const result = callGetTelemetryOptIn(params); expect(result).toBe(null); }); - it('returns false when saved object forbidden', async () => { + it('returns false when saved object forbidden', () => { const params = getCallGetTelemetryOptInParams({ savedObjectForbidden: true, }); - const result = await callGetTelemetryOptIn(params); + const result = callGetTelemetryOptIn(params); expect(result).toBe(false); }); - it('throws an error on unexpected saved object error', async () => { - const params = getCallGetTelemetryOptInParams({ - savedObjectOtherError: true, - }); - - let threw = false; - try { - await callGetTelemetryOptIn(params); - } catch (err) { - threw = true; - expect(err.message).toBe(SavedObjectOtherErrorMessage); - } - - expect(threw).toBe(true); - }); - - it('returns null if enabled is null or undefined', async () => { + it('returns null if enabled is null or undefined', () => { for (const enabled of [null, undefined]) { const params = getCallGetTelemetryOptInParams({ enabled, }); - const result = await callGetTelemetryOptIn(params); + const result = callGetTelemetryOptIn(params); expect(result).toBe(null); } }); - it('returns true when enabled is true', async () => { + it('returns true when enabled is true', () => { const params = getCallGetTelemetryOptInParams({ enabled: true, }); - const result = await callGetTelemetryOptIn(params); + const result = callGetTelemetryOptIn(params); expect(result).toBe(true); }); @@ -146,24 +121,24 @@ describe('get_telemetry_opt_in', () => { }); interface CallGetTelemetryOptInParams { - requestPath: string; savedObjectNotFound: boolean; savedObjectForbidden: boolean; - savedObjectOtherError: boolean; - enabled: boolean | null | undefined; lastVersionChecked?: any; // should be a string, but test with non-strings currentKibanaVersion: string; result?: boolean | null; + enabled: boolean | null | undefined; + configTelemetryOptIn: boolean | null; + allowChangingOptInStatus: boolean; } const DefaultParams = { - requestPath: '/app/something', savedObjectNotFound: false, savedObjectForbidden: false, - savedObjectOtherError: false, enabled: true, lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.0', + configTelemetryOptIn: null, + allowChangingOptInStatus: true, }; function getCallGetTelemetryOptInParams( @@ -172,43 +147,28 @@ function getCallGetTelemetryOptInParams( return { ...DefaultParams, ...overrides }; } -async function callGetTelemetryOptIn(params: CallGetTelemetryOptInParams): Promise { - const { currentKibanaVersion } = params; - const request = getMockRequest(params); - return await getTelemetryOptIn({ request, currentKibanaVersion }); -} - -function getMockRequest(params: CallGetTelemetryOptInParams): any { - return { - path: params.requestPath, - getSavedObjectsClient() { - return getMockSavedObjectsClient(params); - }, - }; +function callGetTelemetryOptIn(params: CallGetTelemetryOptInParams) { + const { currentKibanaVersion, configTelemetryOptIn, allowChangingOptInStatus } = params; + const telemetrySavedObject = getMockTelemetrySavedObject(params); + return getTelemetryOptIn({ + currentKibanaVersion, + telemetrySavedObject, + allowChangingOptInStatus, + configTelemetryOptIn, + }); } -const SavedObjectNotFoundMessage = 'savedObjectNotFound'; -const SavedObjectForbiddenMessage = 'savedObjectForbidden'; -const SavedObjectOtherErrorMessage = 'savedObjectOtherError'; +function getMockTelemetrySavedObject(params: CallGetTelemetryOptInParams): TelemetrySavedObject { + const { savedObjectNotFound, savedObjectForbidden } = params; + if (savedObjectForbidden) { + return false; + } + if (savedObjectNotFound) { + return null; + } -function getMockSavedObjectsClient(params: CallGetTelemetryOptInParams) { return { - async get(type: string, id: string) { - if (params.savedObjectNotFound) throw new Error(SavedObjectNotFoundMessage); - if (params.savedObjectForbidden) throw new Error(SavedObjectForbiddenMessage); - if (params.savedObjectOtherError) throw new Error(SavedObjectOtherErrorMessage); - - const enabled = params.enabled; - const lastVersionChecked = params.lastVersionChecked; - return { attributes: { enabled, lastVersionChecked } }; - }, - errors: { - isNotFoundError(error: any) { - return error.message === SavedObjectNotFoundMessage; - }, - isForbiddenError(error: any) { - return error.message === SavedObjectForbiddenMessage; - }, - }, + enabled: params.enabled, + lastVersionChecked: params.lastVersionChecked, }; } diff --git a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.ts similarity index 58% rename from src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts rename to src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.ts index c8bd4a4b6dfbd4..057a8b0c47958c 100644 --- a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_opt_in.ts @@ -18,67 +18,51 @@ */ import semver from 'semver'; +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; -import { SavedObjectAttributes } from './routes/opt_in'; - -interface GetTelemetryOptIn { - request: any; +interface GetTelemetryOptInConfig { + telemetrySavedObject: TelemetrySavedObject; currentKibanaVersion: string; + allowChangingOptInStatus: boolean; + configTelemetryOptIn: boolean | null; } -// Returns whether telemetry has been opt'ed into or not. -// Returns null not set, meaning Kibana should prompt in the UI. -export async function getTelemetryOptIn({ - request, +type GetTelemetryOptIn = (config: GetTelemetryOptInConfig) => null | boolean; + +export const getTelemetryOptIn: GetTelemetryOptIn = ({ + telemetrySavedObject, currentKibanaVersion, -}: GetTelemetryOptIn): Promise { - const isRequestingApplication = request.path.startsWith('/app'); + allowChangingOptInStatus, + configTelemetryOptIn, +}) => { + if (typeof configTelemetryOptIn === 'boolean' && !allowChangingOptInStatus) { + return configTelemetryOptIn; + } - // Prevent interstitial screens (such as the space selector) from prompting for telemetry - if (!isRequestingApplication) { + if (telemetrySavedObject === false) { return false; } - const savedObjectsClient = request.getSavedObjectsClient(); - - let savedObject; - try { - savedObject = await savedObjectsClient.get('telemetry', 'telemetry'); - } catch (error) { - if (savedObjectsClient.errors.isNotFoundError(error)) { - return null; - } - - // if we aren't allowed to get the telemetry document, we can assume that we won't - // be able to opt into telemetry either, so we're returning `false` here instead of null - if (savedObjectsClient.errors.isForbiddenError(error)) { - return false; - } - - throw error; + if (telemetrySavedObject === null || typeof telemetrySavedObject.enabled !== 'boolean') { + return null; } - const { attributes }: { attributes: SavedObjectAttributes } = savedObject; - - // if enabled is already null, return null - if (attributes.enabled == null) return null; - - const enabled = !!attributes.enabled; + const savedOptIn = telemetrySavedObject.enabled; // if enabled is true, return it - if (enabled === true) return enabled; + if (savedOptIn === true) return savedOptIn; // Additional check if they've already opted out (enabled: false): // - if the Kibana version has changed by at least a minor version, // return null to re-prompt. - const lastKibanaVersion = attributes.lastVersionChecked; + const lastKibanaVersion = telemetrySavedObject.lastVersionChecked; // if the last kibana version isn't set, or is somehow not a string, return null if (typeof lastKibanaVersion !== 'string') return null; // if version hasn't changed, just return enabled value - if (lastKibanaVersion === currentKibanaVersion) return enabled; + if (lastKibanaVersion === currentKibanaVersion) return savedOptIn; const lastSemver = parseSemver(lastKibanaVersion); const currentSemver = parseSemver(currentKibanaVersion); @@ -93,8 +77,8 @@ export async function getTelemetryOptIn({ } // current version X.Y is not greater than last version X.Y, return enabled - return enabled; -} + return savedOptIn; +}; function parseSemver(version: string): semver.SemVer | null { // semver functions both return nulls AND throw exceptions: "it depends!" diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.test.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.test.ts new file mode 100644 index 00000000000000..f2f99104433a39 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.test.ts @@ -0,0 +1,85 @@ +/* + * 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 { getTelemetryUsageFetcher } from './get_telemetry_usage_fetcher'; +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; + +describe('getTelemetryUsageFetcher', () => { + it('returns kibana.yml config when saved object not found', () => { + const params: CallGetTelemetryUsageFetcherParams = { + savedObjectNotFound: true, + configSendUsageFrom: 'browser', + }; + + const result = callGetTelemetryUsageFetcher(params); + + expect(result).toBe('browser'); + }); + + it('returns kibana.yml config when saved object forbidden', () => { + const params: CallGetTelemetryUsageFetcherParams = { + savedObjectForbidden: true, + configSendUsageFrom: 'browser', + }; + + const result = callGetTelemetryUsageFetcher(params); + + expect(result).toBe('browser'); + }); + + it('returns kibana.yml config when saved object sendUsageFrom is undefined', () => { + const params: CallGetTelemetryUsageFetcherParams = { + savedSendUsagefrom: undefined, + configSendUsageFrom: 'server', + }; + + const result = callGetTelemetryUsageFetcher(params); + + expect(result).toBe('server'); + }); +}); + +interface CallGetTelemetryUsageFetcherParams { + savedObjectNotFound?: boolean; + savedObjectForbidden?: boolean; + savedSendUsagefrom?: 'browser' | 'server'; + configSendUsageFrom: 'browser' | 'server'; +} + +function callGetTelemetryUsageFetcher(params: CallGetTelemetryUsageFetcherParams) { + const telemetrySavedObject = getMockTelemetrySavedObject(params); + const configTelemetrySendUsageFrom = params.configSendUsageFrom; + return getTelemetryUsageFetcher({ configTelemetrySendUsageFrom, telemetrySavedObject }); +} + +function getMockTelemetrySavedObject( + params: CallGetTelemetryUsageFetcherParams +): TelemetrySavedObject { + const { savedObjectNotFound, savedObjectForbidden } = params; + if (savedObjectForbidden) { + return false; + } + if (savedObjectNotFound) { + return null; + } + + return { + sendUsageFrom: params.savedSendUsagefrom, + }; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.ts new file mode 100644 index 00000000000000..98f2d6b0c7bbfe --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_usage_fetcher.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; + +interface GetTelemetryUsageFetcherConfig { + configTelemetrySendUsageFrom: 'browser' | 'server'; + telemetrySavedObject: TelemetrySavedObject; +} + +export function getTelemetryUsageFetcher({ + telemetrySavedObject, + configTelemetrySendUsageFrom, +}: GetTelemetryUsageFetcherConfig) { + if (!telemetrySavedObject) { + return configTelemetrySendUsageFrom; + } + + if (typeof telemetrySavedObject.sendUsageFrom === 'undefined') { + return configTelemetrySendUsageFrom; + } + + return telemetrySavedObject.sendUsageFrom; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts new file mode 100644 index 00000000000000..25b588b99a3b86 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { replaceTelemetryInjectedVars } from './replace_injected_vars'; +export { getTelemetryOptIn } from './get_telemetry_opt_in'; +export { getTelemetryUsageFetcher } from './get_telemetry_usage_fetcher'; +export { getTelemetryAllowChangingOptInStatus } from './get_telemetry_allow_changing_opt_in_status'; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts new file mode 100644 index 00000000000000..c9b4f4ebcd6503 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts @@ -0,0 +1,63 @@ +/* + * 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 { getTelemetrySavedObject } from '../telemetry_repository'; +import { getTelemetryOptIn } from './get_telemetry_opt_in'; +import { getTelemetryUsageFetcher } from './get_telemetry_usage_fetcher'; +import { getTelemetryAllowChangingOptInStatus } from './get_telemetry_allow_changing_opt_in_status'; + +export async function replaceTelemetryInjectedVars(request: any) { + const config = request.server.config(); + const configTelemetrySendUsageFrom = config.get('telemetry.sendUsageFrom'); + const configTelemetryOptIn = config.get('telemetry.optIn'); + const configTelemetryAllowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); + const isRequestingApplication = request.path.startsWith('/app'); + + // Prevent interstitial screens (such as the space selector) from prompting for telemetry + if (!isRequestingApplication) { + return { + telemetryOptedIn: false, + }; + } + + const currentKibanaVersion = config.get('pkg.version'); + const savedObjectsClient = request.getSavedObjectsClient(); + const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsClient); + const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({ + configTelemetryAllowChangingOptInStatus, + telemetrySavedObject, + }); + + const telemetryOptedIn = getTelemetryOptIn({ + configTelemetryOptIn, + allowChangingOptInStatus, + telemetrySavedObject, + currentKibanaVersion, + }); + + const telemetrySendUsageFrom = getTelemetryUsageFetcher({ + configTelemetrySendUsageFrom, + telemetrySavedObject, + }); + + return { + telemetryOptedIn, + telemetrySendUsageFrom, + }; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts new file mode 100644 index 00000000000000..7cc177878de4d0 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { getTelemetrySavedObject } from './get_telemetry_saved_object'; +import { SavedObjectsErrorHelpers } from '../../../../../core/server'; + +describe('getTelemetrySavedObject', () => { + it('returns null when saved object not found', async () => { + const params = getCallGetTelemetrySavedObjectParams({ + savedObjectNotFound: true, + }); + + const result = await callGetTelemetrySavedObject(params); + + expect(result).toBe(null); + }); + + it('returns false when saved object forbidden', async () => { + const params = getCallGetTelemetrySavedObjectParams({ + savedObjectForbidden: true, + }); + + const result = await callGetTelemetrySavedObject(params); + + expect(result).toBe(false); + }); + + it('throws an error on unexpected saved object error', async () => { + const params = getCallGetTelemetrySavedObjectParams({ + savedObjectOtherError: true, + }); + + let threw = false; + try { + await callGetTelemetrySavedObject(params); + } catch (err) { + threw = true; + expect(err.message).toBe(SavedObjectOtherErrorMessage); + } + + expect(threw).toBe(true); + }); +}); + +interface CallGetTelemetrySavedObjectParams { + savedObjectNotFound: boolean; + savedObjectForbidden: boolean; + savedObjectOtherError: boolean; + result?: any; +} + +const DefaultParams = { + savedObjectNotFound: false, + savedObjectForbidden: false, + savedObjectOtherError: false, +}; + +function getCallGetTelemetrySavedObjectParams( + overrides: Partial +): CallGetTelemetrySavedObjectParams { + return { ...DefaultParams, ...overrides }; +} + +async function callGetTelemetrySavedObject(params: CallGetTelemetrySavedObjectParams) { + const savedObjectsClient = getMockSavedObjectsClient(params); + return await getTelemetrySavedObject(savedObjectsClient); +} + +const SavedObjectForbiddenMessage = 'savedObjectForbidden'; +const SavedObjectOtherErrorMessage = 'savedObjectOtherError'; + +function getMockSavedObjectsClient(params: CallGetTelemetrySavedObjectParams) { + return { + async get(type: string, id: string) { + if (params.savedObjectNotFound) throw SavedObjectsErrorHelpers.createGenericNotFoundError(); + if (params.savedObjectForbidden) + throw SavedObjectsErrorHelpers.decorateForbiddenError( + new Error(SavedObjectForbiddenMessage) + ); + if (params.savedObjectOtherError) + throw SavedObjectsErrorHelpers.decorateGeneralError( + new Error(SavedObjectOtherErrorMessage) + ); + + return { attributes: { enabled: null } }; + }, + }; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.ts new file mode 100644 index 00000000000000..91965ef201ecb5 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.ts @@ -0,0 +1,43 @@ +/* + * 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 { TelemetrySavedObjectAttributes } from './'; +import { SavedObjectsErrorHelpers } from '../../../../../core/server'; + +export type TelemetrySavedObject = TelemetrySavedObjectAttributes | null | false; +type GetTelemetrySavedObject = (repository: any) => Promise; + +export const getTelemetrySavedObject: GetTelemetrySavedObject = async (repository: any) => { + try { + const { attributes } = await repository.get('telemetry', 'telemetry'); + return attributes; + } catch (error) { + if (SavedObjectsErrorHelpers.isNotFoundError(error)) { + return null; + } + + // if we aren't allowed to get the telemetry document, we can assume that we won't + // be able to opt into telemetry either, so we're returning `false` here instead of null + if (SavedObjectsErrorHelpers.isForbiddenError(error)) { + return false; + } + + throw error; + } +}; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts new file mode 100644 index 00000000000000..f3629abc1620cc --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { getTelemetrySavedObject, TelemetrySavedObject } from './get_telemetry_saved_object'; +export { updateTelemetrySavedObject } from './update_telemetry_saved_object'; + +export interface TelemetrySavedObjectAttributes { + enabled?: boolean | null; + lastVersionChecked?: string; + sendUsageFrom?: 'browser' | 'server'; + lastReported?: number; + telemetryAllowChangingOptInStatus?: boolean; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/update_telemetry_saved_object.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/update_telemetry_saved_object.ts new file mode 100644 index 00000000000000..b66e01faaa6bc7 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/update_telemetry_saved_object.ts @@ -0,0 +1,38 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { TelemetrySavedObjectAttributes } from './'; +import { SavedObjectsErrorHelpers } from '../../../../../core/server'; + +export async function updateTelemetrySavedObject( + savedObjectsClient: any, + savedObjectAttributes: TelemetrySavedObjectAttributes +) { + try { + return await savedObjectsClient.update('telemetry', 'telemetry', savedObjectAttributes); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return await savedObjectsClient.create('telemetry', savedObjectAttributes, { + id: 'telemetry', + overwrite: true, + }); + } + throw err; + } +} diff --git a/src/legacy/core_plugins/ui_metric/index.ts b/src/legacy/core_plugins/ui_metric/index.ts index 6c957f23b5c40d..964e3497accba7 100644 --- a/src/legacy/core_plugins/ui_metric/index.ts +++ b/src/legacy/core_plugins/ui_metric/index.ts @@ -39,13 +39,13 @@ export default function(kibana: any) { injectDefaultVars(server: Server) { const config = server.config(); return { + uiMetricEnabled: config.get('ui_metric.enabled'), debugUiMetric: config.get('ui_metric.debug'), }; }, mappings: require('./mappings.json'), hacks: ['plugins/ui_metric/hacks/ui_metric_init'], }, - init(server: Legacy.Server) { registerUiMetricRoute(server); }, diff --git a/src/legacy/core_plugins/ui_metric/public/hacks/ui_metric_init.ts b/src/legacy/core_plugins/ui_metric/public/hacks/ui_metric_init.ts index 7aafc82cfe4c63..983434f09922b3 100644 --- a/src/legacy/core_plugins/ui_metric/public/hacks/ui_metric_init.ts +++ b/src/legacy/core_plugins/ui_metric/public/hacks/ui_metric_init.ts @@ -20,15 +20,26 @@ // @ts-ignore import { uiModules } from 'ui/modules'; import chrome from 'ui/chrome'; -import { createAnalyticsReporter, setTelemetryReporter } from '../services/telemetry_analytics'; +import { kfetch } from 'ui/kfetch'; +import { + createAnalyticsReporter, + setTelemetryReporter, + trackUserAgent, +} from '../services/telemetry_analytics'; +import { isUnauthenticated } from '../../../telemetry/public/services'; function telemetryInit($injector: any) { - const localStorage = $injector.get('localStorage'); + const uiMetricEnabled = chrome.getInjected('uiMetricEnabled'); const debug = chrome.getInjected('debugUiMetric'); - const $http = $injector.get('$http'); - const basePath = chrome.getBasePath(); - const uiReporter = createAnalyticsReporter({ localStorage, $http, basePath, debug }); + if (!uiMetricEnabled || isUnauthenticated()) { + return; + } + const localStorage = $injector.get('localStorage'); + + const uiReporter = createAnalyticsReporter({ localStorage, debug, kfetch }); setTelemetryReporter(uiReporter); + uiReporter.start(); + trackUserAgent('kibana'); } uiModules.get('kibana').run(telemetryInit); diff --git a/src/legacy/core_plugins/ui_metric/public/index.ts b/src/legacy/core_plugins/ui_metric/public/index.ts index b1e78b56d05d0a..5c327234b1e7cd 100644 --- a/src/legacy/core_plugins/ui_metric/public/index.ts +++ b/src/legacy/core_plugins/ui_metric/public/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export { createUiStatsReporter } from './services/telemetry_analytics'; -export { METRIC_TYPE } from '@kbn/analytics'; +export { createUiStatsReporter, trackUserAgent } from './services/telemetry_analytics'; +export { METRIC_TYPE, UiStatsMetricType } from '@kbn/analytics'; diff --git a/src/legacy/core_plugins/ui_metric/public/services/telemetry_analytics.ts b/src/legacy/core_plugins/ui_metric/public/services/telemetry_analytics.ts index 7310ee5b5f1720..ee928b8a1d9ee8 100644 --- a/src/legacy/core_plugins/ui_metric/public/services/telemetry_analytics.ts +++ b/src/legacy/core_plugins/ui_metric/public/services/telemetry_analytics.ts @@ -17,7 +17,9 @@ * under the License. */ -import { createReporter, Reporter, UiStatsMetricType } from '@kbn/analytics'; +import { Reporter, UiStatsMetricType } from '@kbn/analytics'; +// @ts-ignore +import { addSystemApiHeader } from 'ui/system_api'; let telemetryReporter: Reporter; @@ -39,28 +41,36 @@ export const createUiStatsReporter = (appName: string) => ( } }; +export const trackUserAgent = (appName: string) => { + if (telemetryReporter) { + return telemetryReporter.reportUserAgent(appName); + } +}; + interface AnalyicsReporterConfig { localStorage: any; - basePath: string; debug: boolean; - $http: ng.IHttpService; + kfetch: any; } export function createAnalyticsReporter(config: AnalyicsReporterConfig) { - const { localStorage, basePath, debug } = config; + const { localStorage, debug, kfetch } = config; - return createReporter({ + return new Reporter({ debug, storage: localStorage, async http(report) { - const url = `${basePath}/api/telemetry/report`; - await fetch(url, { + const response = await kfetch({ method: 'POST', - headers: { - 'kbn-xsrf': 'true', - }, - body: JSON.stringify({ report }), + pathname: '/api/telemetry/report', + body: JSON.stringify(report), + headers: addSystemApiHeader({}), }); + + if (response.status !== 'ok') { + throw Error('Unable to store report.'); + } + return response; }, }); } diff --git a/src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts b/src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts index 8a7950c46fa317..e2de23ea806e44 100644 --- a/src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts +++ b/src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts @@ -18,7 +18,6 @@ */ import Joi from 'joi'; -import Boom from 'boom'; import { Report } from '@kbn/analytics'; import { Server } from 'hapi'; @@ -27,15 +26,27 @@ export async function storeReport(server: any, report: Report) { const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); const internalRepository = getSavedObjectsRepository(callWithInternalUser); - const metricKeys = Object.keys(report.uiStatsMetrics); - return Promise.all( - metricKeys.map(async key => { - const metric = report.uiStatsMetrics[key]; + const uiStatsMetrics = report.uiStatsMetrics ? Object.entries(report.uiStatsMetrics) : []; + const userAgents = report.userAgent ? Object.entries(report.userAgent) : []; + return Promise.all([ + ...userAgents.map(async ([key, metric]) => { + const { userAgent } = metric; + const savedObjectId = `${key}:${userAgent}`; + return await internalRepository.create( + 'ui-metric', + { count: 1 }, + { + id: savedObjectId, + overwrite: true, + } + ); + }), + ...uiStatsMetrics.map(async ([key, metric]) => { const { appName, eventName } = metric; const savedObjectId = `${appName}:${eventName}`; - return internalRepository.incrementCounter('ui-metric', savedObjectId, 'count'); - }) - ); + return await internalRepository.incrementCounter('ui-metric', savedObjectId, 'count'); + }), + ]); } export function registerUiMetricRoute(server: Server) { @@ -45,36 +56,46 @@ export function registerUiMetricRoute(server: Server) { options: { validate: { payload: Joi.object({ - report: Joi.object({ - uiStatsMetrics: Joi.object() - .pattern( - /.*/, - Joi.object({ - key: Joi.string().required(), - type: Joi.string().required(), - appName: Joi.string().required(), - eventName: Joi.string().required(), - stats: Joi.object({ - min: Joi.number(), - sum: Joi.number(), - max: Joi.number(), - avg: Joi.number(), - }).allow(null), - }) - ) - .allow(null), - }), + reportVersion: Joi.number().optional(), + userAgent: Joi.object() + .pattern( + /.*/, + Joi.object({ + key: Joi.string().required(), + type: Joi.string().required(), + appName: Joi.string().required(), + userAgent: Joi.string().required(), + }) + ) + .allow(null) + .optional(), + uiStatsMetrics: Joi.object() + .pattern( + /.*/, + Joi.object({ + key: Joi.string().required(), + type: Joi.string().required(), + appName: Joi.string().required(), + eventName: Joi.string().required(), + stats: Joi.object({ + min: Joi.number(), + sum: Joi.number(), + max: Joi.number(), + avg: Joi.number(), + }).allow(null), + }) + ) + .allow(null), }), }, }, handler: async (req: any, h: any) => { - const { report } = req.payload; - try { + const report = req.payload; await storeReport(server, report); - return {}; + return { status: 'ok' }; } catch (error) { - return new Boom('Something went wrong', { statusCode: error.status }); + return { status: 'fail' }; } }, }); diff --git a/test/api_integration/apis/ui_metric/ui_metric.js b/test/api_integration/apis/ui_metric/ui_metric.js index efa6be47b50c9b..f0c86f2904638c 100644 --- a/test/api_integration/apis/ui_metric/ui_metric.js +++ b/test/api_integration/apis/ui_metric/ui_metric.js @@ -18,48 +18,59 @@ */ import expect from '@kbn/expect'; -import { ReportManager } from '@kbn/analytics'; +import { ReportManager, METRIC_TYPE } from '@kbn/analytics'; export default function ({ getService }) { const supertest = getService('supertest'); const es = getService('es'); - const createMetric = (eventName) => ({ - key: ReportManager.createMetricKey({ appName: 'myApp', type: 'click', eventName }), + const createStatsMetric = (eventName) => ({ + key: ReportManager.createMetricKey({ appName: 'myApp', type: METRIC_TYPE.CLICK, eventName }), eventName, appName: 'myApp', - type: 'click', + type: METRIC_TYPE.CLICK, stats: { sum: 1, avg: 1, min: 1, max: 1 }, }); + const createUserAgentMetric = (appName) => ({ + key: ReportManager.createMetricKey({ appName, type: METRIC_TYPE.USER_AGENT }), + appName, + type: METRIC_TYPE.USER_AGENT, + userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36', + }); + describe('ui_metric API', () => { - const uiStatsMetric = createMetric('myEvent'); - const report = { - uiStatsMetrics: { - [uiStatsMetric.key]: uiStatsMetric, - } - }; + it('increments the count field in the document defined by the {app}/{action_type} path', async () => { + const uiStatsMetric = createStatsMetric('myEvent'); + const report = { + uiStatsMetrics: { + [uiStatsMetric.key]: uiStatsMetric, + } + }; await supertest .post('/api/telemetry/report') .set('kbn-xsrf', 'kibana') .set('content-type', 'application/json') - .send({ report }) + .send(report) .expect(200); - return es.search({ - index: '.kibana', - q: 'type:user-action', - }).then(response => { - const ids = response.hits.hits.map(({ _id }) => _id); - expect(ids.includes('user-action:myApp:myEvent')); - }); + const response = await es.search({ index: '.kibana', q: 'type:ui-metric' }); + const ids = response.hits.hits.map(({ _id }) => _id); + expect(ids.includes('ui-metric:myApp:myEvent')).to.eql(true); }); it('supports multiple events', async () => { - const uiStatsMetric1 = createMetric('myEvent1'); - const uiStatsMetric2 = createMetric('myEvent2'); + const userAgentMetric = createUserAgentMetric('kibana'); + const uiStatsMetric1 = createStatsMetric('myEvent'); + const hrTime = process.hrtime(); + const nano = hrTime[0] * 1000000000 + hrTime[1]; + const uniqueEventName = `myEvent${nano}`; + const uiStatsMetric2 = createStatsMetric(uniqueEventName); const report = { + userAgent: { + [userAgentMetric.key]: userAgentMetric, + }, uiStatsMetrics: { [uiStatsMetric1.key]: uiStatsMetric1, [uiStatsMetric2.key]: uiStatsMetric2, @@ -69,17 +80,14 @@ export default function ({ getService }) { .post('/api/telemetry/report') .set('kbn-xsrf', 'kibana') .set('content-type', 'application/json') - .send({ report }) + .send(report) .expect(200); - return es.search({ - index: '.kibana', - q: 'type:user-action', - }).then(response => { - const ids = response.hits.hits.map(({ _id }) => _id); - expect(ids.includes('user-action:myApp:myEvent1')); - expect(ids.includes('user-action:myApp:myEvent2')); - }); + const response = await es.search({ index: '.kibana', q: 'type:ui-metric' }); + const ids = response.hits.hits.map(({ _id }) => _id); + expect(ids.includes('ui-metric:myApp:myEvent')).to.eql(true); + expect(ids.includes(`ui-metric:myApp:${uniqueEventName}`)).to.eql(true); + expect(ids.includes(`ui-metric:kibana-user_agent:${userAgentMetric.userAgent}`)).to.eql(true); }); }); } diff --git a/test/common/config.js b/test/common/config.js index 44e4bef99bf620..cd29b593cdadbd 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -59,7 +59,6 @@ export default function () { `--server.maxPayloadBytes=1679958`, ], }, - services }; } diff --git a/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx b/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx index 4d9ca3704873cb..379b3af3f10637 100644 --- a/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx +++ b/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx @@ -7,6 +7,7 @@ import { useEffect } from 'react'; import { createUiStatsReporter, + UiStatsMetricType, METRIC_TYPE, } from '../../../../../../src/legacy/core_plugins/ui_metric/public'; @@ -36,7 +37,7 @@ function getTrackerForApp(app: string) { interface TrackOptions { app: ObservabilityApp; - metricType?: METRIC_TYPE; + metricType?: UiStatsMetricType; delay?: number; // in ms } type EffectDeps = unknown[]; @@ -76,7 +77,7 @@ export function useTrackPageview( interface TrackEventProps { app: ObservabilityApp; name: string; - metricType?: METRIC_TYPE; + metricType?: UiStatsMetricType; } export function trackEvent({ app, name, metricType = METRIC_TYPE.CLICK }: TrackEventProps) { diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js index 0d147b747f2d04..c1425de20d1465 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js @@ -12,8 +12,7 @@ describe('get_all_stats', () => { const size = 123; const start = 0; const end = 1; - const callWithRequest = sinon.stub(); - const callWithInternalUser = sinon.stub(); + const callCluster = sinon.stub(); const server = { config: sinon.stub().returns({ get: sinon.stub().withArgs('xpack.monitoring.elasticsearch.index_pattern').returns('.monitoring-es-N-*') @@ -21,16 +20,8 @@ describe('get_all_stats', () => { .withArgs('xpack.monitoring.logstash.index_pattern').returns('.monitoring-logstash-N-*') .withArgs('xpack.monitoring.max_bucket_size').returns(size) }), - plugins: { - elasticsearch: { - getCluster: sinon.stub().withArgs('monitoring').returns({ - callWithInternalUser, - callWithRequest - }) - } - } }; - const req = { server }; + const esClusters = [ { cluster_uuid: 'a' }, { cluster_uuid: 'b', random_setting_not_removed: false }, @@ -188,19 +179,13 @@ describe('get_all_stats', () => { } ]; - callWithRequest.withArgs(req, 'search') - .onCall(0).returns(Promise.resolve(clusterUuidsResponse)) - .onCall(1).returns(Promise.resolve(esStatsResponse)) - .onCall(2).returns(Promise.resolve(kibanaStatsResponse)) - .onCall(3).returns(Promise.resolve(logstashStatsResponse)); - - callWithInternalUser.withArgs('search') + callCluster.withArgs('search') .onCall(0).returns(Promise.resolve(clusterUuidsResponse)) .onCall(1).returns(Promise.resolve(esStatsResponse)) .onCall(2).returns(Promise.resolve(kibanaStatsResponse)) .onCall(3).returns(Promise.resolve(logstashStatsResponse)); - expect(await getAllStats(req, start, end)).to.eql(allClusters); + expect(await getAllStats({ callCluster, server, start, end })).to.eql(allClusters); }); it('returns empty clusters', async () => { @@ -208,10 +193,9 @@ describe('get_all_stats', () => { aggregations: { cluster_uuids: { buckets: [ ] } } }; - callWithRequest.withArgs(req, 'search').returns(Promise.resolve(clusterUuidsResponse)); - callWithInternalUser.withArgs('search').returns(Promise.resolve(clusterUuidsResponse)); + callCluster.withArgs('search').returns(Promise.resolve(clusterUuidsResponse)); - expect(await getAllStats(req, start, end)).to.eql([]); + expect(await getAllStats({ callCluster, server, start, end })).to.eql([]); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.js index b1e8db1b96005d..ce33068725d9ce 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.js @@ -17,23 +17,6 @@ import { getKibanaStats } from './get_kibana_stats'; import { getBeatsStats } from './get_beats_stats'; import { getHighLevelStats } from './get_high_level_stats'; - -/** - * Get statistics for all products joined by Elasticsearch cluster. - * - * @param {Object} req The incoming request - * @param {Date} start The starting range to request data - * @param {Date} end The ending range to request data - * @return {Promise} The array of clusters joined with the Kibana and Logstash instances. - */ -export function getAllStats(req, start, end, { useInternalUser = false } = {}) { - const server = req.server; - const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster('monitoring'); - const callCluster = useInternalUser ? callWithInternalUser : (...args) => callWithRequest(req, ...args); - - return getAllStatsWithCaller(server, callCluster, start, end); -} - /** * Get statistics for all products joined by Elasticsearch cluster. * @@ -43,7 +26,7 @@ export function getAllStats(req, start, end, { useInternalUser = false } = {}) { * @param {Date} end The ending range to request data * @return {Promise} The array of clusters joined with the Kibana and Logstash instances. */ -function getAllStatsWithCaller(server, callCluster, start, end) { +export function getAllStats({ server, callCluster, start, end } = {}) { return getClusterUuids(server, callCluster, start, end) .then(clusterUuids => { // don't bother doing a further lookup diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_stats_with_monitoring.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_stats_with_monitoring.ts index fdf46122f13b76..f784457b46bc3f 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_stats_with_monitoring.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_stats_with_monitoring.ts @@ -7,37 +7,24 @@ // @ts-ignore import { getAllStats } from './get_all_stats'; import { getStatsWithXpack } from '../../../xpack_main/server/telemetry_collection'; +import { + StatsGetter, + getStatsCollectionConfig, +} from '../../../../../../src/legacy/core_plugins/telemetry/server/collection_manager'; -/** - * Get the telemetry data. - * - * @param {Object} req The incoming request. - * @param {Object} config Kibana config. - * @param {String} start The start time of the request (likely 20m ago). - * @param {String} end The end time of the request. - * @param {Boolean} unencrypted Is the request payload going to be unencrypted. - * @return {Promise} An array of telemetry objects. - */ -export async function getStatsWithMonitoring( - req: any, - config: any, - start: string, - end: string, - unencrypted: boolean -) { +export const getStatsWithMonitoring: StatsGetter = async function(config) { let response = []; - const useInternalUser = !unencrypted; try { - // attempt to collect stats from multiple clusters in monitoring data - response = await getAllStats(req, start, end, { useInternalUser }); + const { start, end, server, callCluster } = getStatsCollectionConfig(config, 'monitoring'); + response = await getAllStats({ server, callCluster, start, end }); } catch (err) { // no-op } if (!Array.isArray(response) || response.length === 0) { - response = await getStatsWithXpack(req, config, start, end, unencrypted); + response = await getStatsWithXpack(config); } return response; -} +}; diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts index f19695ca065257..6915da52636242 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts @@ -7,36 +7,19 @@ // @ts-ignore import { getXPack } from './get_xpack'; import { getLocalStats } from '../../../../../../src/legacy/core_plugins/telemetry/server/telemetry_collection'; +import { + StatsGetter, + getStatsCollectionConfig, +} from '../../../../../../src/legacy/core_plugins/telemetry/server/collection_manager'; -/** - * Get the telemetry data. - * - * @param {Object} req The incoming request. - * @param {Object} config Kibana config. - * @param {String} start The start time of the request (likely 20m ago). - * @param {String} end The end time of the request. - * @param {Boolean} unencrypted Is the request payload going to be unencrypted. - * @return {Promise} An array of telemetry objects. - */ -export async function getStatsWithXpack( - req: any, - config: any, - start: string, - end: string, - unencrypted: boolean -) { - const useInternalUser = !unencrypted; - const { server } = req; - const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster('data'); - const callCluster = useInternalUser - ? callWithInternalUser - : (...args: any[]) => callWithRequest(req, ...args); +export const getStatsWithXpack: StatsGetter = async function(config) { + const { server, callCluster } = getStatsCollectionConfig(config, 'data'); - const localStats = await getLocalStats(req, { useInternalUser }); + const localStats = await getLocalStats({ server, callCluster }); const { license, xpack } = await getXPack(callCluster); localStats.license = license; localStats.stack_stats.xpack = xpack; return [localStats]; -} +}; diff --git a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts index 0834ff11ced58f..d60b286e3337ae 100644 --- a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts +++ b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts @@ -47,7 +47,6 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); await PageObjects.security.logout(); - await PageObjects.security.login( 'global_advanced_settings_all_user', 'global_advanced_settings_all_user-password', @@ -55,7 +54,6 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { expectSpaceSelector: false, } ); - await kibanaServer.uiSettings.replace({}); await PageObjects.settings.navigateTo(); }); diff --git a/yarn.lock b/yarn.lock index 71f032cf720dc6..d0ebd30d701369 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27891,7 +27891,7 @@ typescript-fsa@^2.0.0, typescript-fsa@^2.5.0: resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-2.5.0.tgz#1baec01b5e8f5f34c322679d1327016e9e294faf" integrity sha1-G67AG16PXzTDImedEycBbp4pT68= -typescript@3.5.1, typescript@3.5.3, typescript@^3.0.1, typescript@^3.0.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.4.5, typescript@~3.3.3333, typescript@~3.5.3: +typescript@3.5.3, typescript@^3.0.1, typescript@^3.0.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.4.5, typescript@~3.3.3333, typescript@~3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== From 6c3ee583c8ccb40ddbc3373abbedd9d35d9291c2 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 13 Nov 2019 08:54:18 +0100 Subject: [PATCH 02/59] =?UTF-8?q?[APM]=20Document=20`apm=5Foss.metricsIndi?= =?UTF-8?q?ces`=20and=20`apm=5Foss.sourcemap=E2=80=A6=20(#50312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #49847. --- docs/settings/apm-settings.asciidoc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index e47326a1d20687..8cbbcdcbca3efc 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -23,8 +23,6 @@ xpack.apm.ui.transactionGroupBucketSize:: Number of top transaction groups displ xpack.apm.ui.maxTraceItems:: Max number of child items displayed when viewing trace details. Defaults to `1000`. -apm_oss.apmAgentConfigurationIndex:: Index containing agent configuration settings. Defaults to `.apm-agent-configuration`. - apm_oss.indexPattern:: Index pattern is used for integrations with Machine Learning and Kuery Bar. It must match all apm indices. Defaults to `apm-*`. apm_oss.errorIndices:: Matcher for indices containing error documents. Defaults to `apm-*`. @@ -34,3 +32,8 @@ apm_oss.onboardingIndices:: Matcher for indices containing onboarding documents. apm_oss.spanIndices:: Matcher for indices containing span documents. Defaults to `apm-*`. apm_oss.transactionIndices:: Matcher for indices containing transaction documents. Defaults to `apm-*`. + +apm_oss.metricsIndices:: Matcher for indices containing metric documents. Defaults to `apm-*`. + +apm_oss.sourcemapIndices:: Matcher for indices containing sourcemap documents. Defaults to `apm-*`. + From e6ea2bf16bcb2c8caf502d3227f656b120b3bb61 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 13 Nov 2019 09:30:38 +0100 Subject: [PATCH 03/59] Remove internal platform types exports (#50427) * remove exports of internal core types * updates documentation * rename internal types file --- .../kibana-plugin-server.basepath.get.md | 2 +- .../server/kibana-plugin-server.basepath.md | 4 +- .../kibana-plugin-server.basepath.set.md | 2 +- src/core/server/index.ts | 32 ++------------- src/core/server/internal_types.ts | 39 +++++++++++++++++++ src/core/server/legacy/legacy_service.ts | 3 +- src/core/server/plugins/plugins_service.ts | 2 +- src/core/server/server.api.md | 38 ++---------------- src/core/server/server.ts | 3 +- x-pack/legacy/plugins/apm/index.ts | 20 +++++----- .../apm_telemetry/make_apm_usage_collector.ts | 24 ++++++------ .../create_agent_config_index.ts | 7 ++-- .../plugins/apm/server/new-platform/plugin.ts | 17 +++++--- .../server/routes/create_api/index.test.ts | 31 ++++++++------- .../apm/server/routes/create_api/index.ts | 9 +++-- .../apm/server/routes/index_pattern.ts | 7 +--- .../plugins/apm/server/routes/services.ts | 3 +- .../apm/server/routes/settings/apm_indices.ts | 9 ++--- .../plugins/apm/server/routes/typings.ts | 10 +++-- 19 files changed, 126 insertions(+), 136 deletions(-) create mode 100644 src/core/server/internal_types.ts diff --git a/docs/development/core/server/kibana-plugin-server.basepath.get.md b/docs/development/core/server/kibana-plugin-server.basepath.get.md index 04feca7ccc5a87..2b3b6c899e8ded 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.get.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.get.md @@ -9,5 +9,5 @@ returns `basePath` value, specific for an incoming request. Signature: ```typescript -get: (request: LegacyRequest | KibanaRequest) => string; +get: (request: KibanaRequest | LegacyRequest) => string; ``` diff --git a/docs/development/core/server/kibana-plugin-server.basepath.md b/docs/development/core/server/kibana-plugin-server.basepath.md index da833c71bf93b6..478e29696966cd 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.md @@ -16,11 +16,11 @@ export declare class BasePath | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [get](./kibana-plugin-server.basepath.get.md) | | (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown>) => string | returns basePath value, specific for an incoming request. | +| [get](./kibana-plugin-server.basepath.get.md) | | (request: KibanaRequest<unknown, unknown, unknown> | LegacyRequest) => string | returns basePath value, specific for an incoming request. | | [prepend](./kibana-plugin-server.basepath.prepend.md) | | (path: string) => string | Prepends path with the basePath. | | [remove](./kibana-plugin-server.basepath.remove.md) | | (path: string) => string | Removes the prepended basePath from the path. | | [serverBasePath](./kibana-plugin-server.basepath.serverbasepath.md) | | string | returns the server's basePathSee [BasePath.get](./kibana-plugin-server.basepath.get.md) for getting the basePath value for a specific request | -| [set](./kibana-plugin-server.basepath.set.md) | | (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown>, requestSpecificBasePath: string) => void | sets basePath value, specific for an incoming request. | +| [set](./kibana-plugin-server.basepath.set.md) | | (request: KibanaRequest<unknown, unknown, unknown> | LegacyRequest, requestSpecificBasePath: string) => void | sets basePath value, specific for an incoming request. | ## Remarks diff --git a/docs/development/core/server/kibana-plugin-server.basepath.set.md b/docs/development/core/server/kibana-plugin-server.basepath.set.md index cec70ee853bfa4..1272a134ef5c44 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.set.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.set.md @@ -9,5 +9,5 @@ sets `basePath` value, specific for an incoming request. Signature: ```typescript -set: (request: LegacyRequest | KibanaRequest, requestSpecificBasePath: string) => void; +set: (request: KibanaRequest | LegacyRequest, requestSpecificBasePath: string) => void; ``` diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 35e83da4ef30c8..2a5631ad1c3801 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -39,21 +39,11 @@ * @packageDocumentation */ -import { - ElasticsearchServiceSetup, - InternalElasticsearchServiceSetup, - IScopedClusterClient, -} from './elasticsearch'; -import { InternalHttpServiceSetup, HttpServiceSetup } from './http'; +import { ElasticsearchServiceSetup, IScopedClusterClient } from './elasticsearch'; +import { HttpServiceSetup } from './http'; import { PluginsServiceSetup, PluginsServiceStart, PluginOpaqueId } from './plugins'; import { ContextSetup } from './context'; -import { SavedObjectsServiceStart } from './saved_objects'; - -import { - InternalUiSettingsServiceSetup, - IUiSettingsClient, - UiSettingsServiceSetup, -} from './ui_settings'; +import { IUiSettingsClient, UiSettingsServiceSetup } from './ui_settings'; import { SavedObjectsClientContract } from './saved_objects/types'; export { bootstrap } from './bootstrap'; @@ -177,7 +167,6 @@ export { export { IUiSettingsClient, UiSettingsParams, - InternalUiSettingsServiceSetup, UiSettingsType, UiSettingsServiceSetup, UserProvidedValues, @@ -251,19 +240,4 @@ export interface CoreSetup { */ export interface CoreStart {} // eslint-disable-line @typescript-eslint/no-empty-interface -/** @internal */ -export interface InternalCoreSetup { - context: ContextSetup; - http: InternalHttpServiceSetup; - elasticsearch: InternalElasticsearchServiceSetup; - uiSettings: InternalUiSettingsServiceSetup; -} - -/** - * @internal - */ -export interface InternalCoreStart { - savedObjects: SavedObjectsServiceStart; -} - export { ContextSetup, PluginsServiceSetup, PluginsServiceStart, PluginOpaqueId }; diff --git a/src/core/server/internal_types.ts b/src/core/server/internal_types.ts new file mode 100644 index 00000000000000..1330c5aee64fd7 --- /dev/null +++ b/src/core/server/internal_types.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { InternalElasticsearchServiceSetup } from './elasticsearch'; +import { InternalHttpServiceSetup } from './http'; +import { InternalUiSettingsServiceSetup } from './ui_settings'; +import { ContextSetup } from './context'; +import { SavedObjectsServiceStart } from './saved_objects'; + +/** @internal */ +export interface InternalCoreSetup { + context: ContextSetup; + http: InternalHttpServiceSetup; + elasticsearch: InternalElasticsearchServiceSetup; + uiSettings: InternalUiSettingsServiceSetup; +} + +/** + * @internal + */ +export interface InternalCoreStart { + savedObjects: SavedObjectsServiceStart; +} diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index b7c55a8af7c18d..99963ad9ce3e89 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -20,7 +20,8 @@ import { combineLatest, ConnectableObservable, EMPTY, Observable, Subscription } from 'rxjs'; import { first, map, publishReplay, tap } from 'rxjs/operators'; import { CoreService } from '../../types'; -import { InternalCoreSetup, InternalCoreStart, CoreSetup, CoreStart } from '../'; +import { CoreSetup, CoreStart } from '../'; +import { InternalCoreSetup, InternalCoreStart } from '../internal_types'; import { SavedObjectsLegacyUiExports } from '../types'; import { Config } from '../config'; import { CoreContext } from '../core_context'; diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 2964e34c370b1c..38fe519567a635 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -28,7 +28,7 @@ import { PluginWrapper } from './plugin'; import { DiscoveredPlugin, DiscoveredPluginInternal, PluginName } from './types'; import { PluginsConfig, PluginsConfigType } from './plugins_config'; import { PluginsSystem } from './plugins_system'; -import { InternalCoreSetup } from '..'; +import { InternalCoreSetup } from '../internal_types'; /** @public */ export interface PluginsServiceSetup { diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 73626775381d7d..97a04a4a4efaba 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -449,11 +449,11 @@ export interface AuthToolkit { export class BasePath { // @internal constructor(serverBasePath?: string); - get: (request: LegacyRequest | KibanaRequest) => string; + get: (request: KibanaRequest | LegacyRequest) => string; prepend: (path: string) => string; remove: (path: string) => string; readonly serverBasePath: string; - set: (request: LegacyRequest | KibanaRequest, requestSpecificBasePath: string) => void; + set: (request: KibanaRequest | LegacyRequest, requestSpecificBasePath: string) => void; } // Warning: (ae-forgotten-export) The symbol "BootstrapArgs" needs to be exported by the entry point index.d.ts @@ -712,36 +712,6 @@ export interface IndexSettingsDeprecationInfo { [indexName: string]: DeprecationInfo[]; } -// @internal (undocumented) -export interface InternalCoreSetup { - // (undocumented) - context: ContextSetup; - // Warning: (ae-forgotten-export) The symbol "InternalElasticsearchServiceSetup" needs to be exported by the entry point index.d.ts - // - // (undocumented) - elasticsearch: InternalElasticsearchServiceSetup; - // Warning: (ae-forgotten-export) The symbol "InternalHttpServiceSetup" needs to be exported by the entry point index.d.ts - // - // (undocumented) - http: InternalHttpServiceSetup; - // (undocumented) - uiSettings: InternalUiSettingsServiceSetup; -} - -// @internal (undocumented) -export interface InternalCoreStart { - // Warning: (ae-forgotten-export) The symbol "SavedObjectsServiceStart" needs to be exported by the entry point index.d.ts - // - // (undocumented) - savedObjects: SavedObjectsServiceStart; -} - -// @internal (undocumented) -export interface InternalUiSettingsServiceSetup { - asScopedToClient(savedObjectsClient: SavedObjectsClientContract): IUiSettingsClient; - register(settings: Record): void; -} - // @public export interface IRouter { delete:

(route: RouteConfig, handler: RequestHandler) => void; @@ -839,7 +809,7 @@ export interface LegacyRequest extends Request { // @public @deprecated (undocumented) export interface LegacyServiceSetupDeps { - // Warning: (ae-incompatible-release-tags) The symbol "core" is marked as @public, but its signature references "InternalCoreSetup" which is marked as @internal + // Warning: (ae-forgotten-export) The symbol "InternalCoreSetup" needs to be exported by the entry point index.d.ts // // (undocumented) core: InternalCoreSetup & { @@ -851,7 +821,7 @@ export interface LegacyServiceSetupDeps { // @public @deprecated (undocumented) export interface LegacyServiceStartDeps { - // Warning: (ae-incompatible-release-tags) The symbol "core" is marked as @public, but its signature references "InternalCoreStart" which is marked as @internal + // Warning: (ae-forgotten-export) The symbol "InternalCoreStart" needs to be exported by the entry point index.d.ts // // (undocumented) core: InternalCoreStart & { diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 46974e204c7a42..6c38de03f0f2d3 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -39,7 +39,8 @@ import { config as uiSettingsConfig } from './ui_settings'; import { mapToObject } from '../utils/'; import { ContextService } from './context'; import { SavedObjectsServiceSetup } from './saved_objects/saved_objects_service'; -import { RequestHandlerContext, InternalCoreSetup } from '.'; +import { RequestHandlerContext } from '.'; +import { InternalCoreSetup } from './internal_types'; const coreId = Symbol('core'); diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index 556bce9d37bb54..fe8cc43d7f55dc 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -7,13 +7,10 @@ import { i18n } from '@kbn/i18n'; import { Server } from 'hapi'; import { resolve } from 'path'; -import { - InternalCoreSetup, - PluginInitializerContext -} from '../../../../src/core/server'; +import { PluginInitializerContext } from '../../../../src/core/server'; import { LegacyPluginInitializer } from '../../../../src/legacy/types'; import mappings from './mappings.json'; -import { plugin } from './server/new-platform/index'; +import { plugin } from './server/new-platform'; export const apm: LegacyPluginInitializer = kibana => { return new kibana.Plugin({ @@ -111,12 +108,13 @@ export const apm: LegacyPluginInitializer = kibana => { }); const initializerContext = {} as PluginInitializerContext; - const core = { - http: { - server - } - } as InternalCoreSetup; - plugin(initializerContext).setup(core); + const legacySetup = { + server + }; + plugin(initializerContext).setup( + server.newPlatform.setup.core, + legacySetup + ); } }); }; diff --git a/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/make_apm_usage_collector.ts b/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/make_apm_usage_collector.ts index 8a91bd8781fe77..886c3890f1a9a7 100644 --- a/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/make_apm_usage_collector.ts +++ b/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/make_apm_usage_collector.ts @@ -4,26 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InternalCoreSetup } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; import { getSavedObjectsClient } from '../helpers/saved_objects_client'; import { APM_TELEMETRY_DOC_ID, createApmTelementry } from './apm_telemetry'; +import { LegacySetup } from '../../new-platform/plugin'; -export interface CoreSetupWithUsageCollector extends InternalCoreSetup { - http: InternalCoreSetup['http'] & { - server: { - usage: { - collectorSet: { - makeUsageCollector: (options: unknown) => unknown; - register: (options: unknown) => unknown; - }; +export interface LegacySetupWithUsageCollector extends LegacySetup { + server: LegacySetup['server'] & { + usage: { + collectorSet: { + makeUsageCollector: (options: unknown) => unknown; + register: (options: unknown) => unknown; }; }; }; } -export function makeApmUsageCollector(core: CoreSetupWithUsageCollector) { - const { server } = core.http; - +export function makeApmUsageCollector( + core: CoreSetup, + { server }: LegacySetupWithUsageCollector +) { const apmUsageCollector = server.usage.collectorSet.makeUsageCollector({ type: 'apm', fetch: async () => { diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts index 861732ee039232..18f6aea610a68d 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts @@ -4,15 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InternalCoreSetup } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; import { CallCluster } from '../../../../../../../../src/legacy/core_plugins/elasticsearch'; import { getApmIndices } from '../apm_indices/get_apm_indices'; +import { LegacySetup } from '../../../new-platform/plugin'; export async function createApmAgentConfigurationIndex( - core: InternalCoreSetup + core: CoreSetup, + { server }: LegacySetup ) { try { - const { server } = core.http; const indices = await getApmIndices(server); const index = indices['apm_oss.apmAgentConfigurationIndex']; const { callWithInternalUser } = server.plugins.elasticsearch.getCluster( diff --git a/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts b/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts index 0458c8e4fedf04..351afe618901e8 100644 --- a/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts +++ b/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts @@ -4,16 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InternalCoreSetup } from 'src/core/server'; +import { Server } from 'hapi'; +import { CoreSetup } from 'src/core/server'; import { makeApmUsageCollector } from '../lib/apm_telemetry'; -import { CoreSetupWithUsageCollector } from '../lib/apm_telemetry/make_apm_usage_collector'; +import { LegacySetupWithUsageCollector } from '../lib/apm_telemetry/make_apm_usage_collector'; import { createApmAgentConfigurationIndex } from '../lib/settings/agent_configuration/create_agent_config_index'; import { createApmApi } from '../routes/create_apm_api'; +export interface LegacySetup { + server: Server; +} + export class Plugin { - public setup(core: InternalCoreSetup) { - createApmApi().init(core); - createApmAgentConfigurationIndex(core); - makeApmUsageCollector(core as CoreSetupWithUsageCollector); + public setup(core: CoreSetup, __LEGACY: LegacySetup) { + createApmApi().init(core, __LEGACY); + createApmAgentConfigurationIndex(core, __LEGACY); + makeApmUsageCollector(core, __LEGACY as LegacySetupWithUsageCollector); } } diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts index b0461f5cb3b68d..98eae3196eaacb 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts @@ -5,23 +5,25 @@ */ import * as t from 'io-ts'; import { createApi } from './index'; -import { InternalCoreSetup } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; import { Params } from '../typings'; +import { LegacySetup } from '../../new-platform/plugin'; -const getCoreMock = () => +const getCoreMock = () => (({} as unknown) as CoreSetup); + +const getLegacyMock = () => (({ - http: { - server: { - route: jest.fn() - } + server: { + route: jest.fn() } - } as unknown) as InternalCoreSetup & { - http: { server: { route: ReturnType } }; + } as unknown) as LegacySetup & { + server: { route: ReturnType }; }); describe('createApi', () => { it('registers a route with the server', () => { const coreMock = getCoreMock(); + const legacySetupMock = getLegacyMock(); createApi() .add(() => ({ @@ -36,11 +38,11 @@ describe('createApi', () => { }, handler: async () => null })) - .init(coreMock); + .init(coreMock, legacySetupMock); - expect(coreMock.http.server.route).toHaveBeenCalledTimes(2); + expect(legacySetupMock.server.route).toHaveBeenCalledTimes(2); - const firstRoute = coreMock.http.server.route.mock.calls[0][0]; + const firstRoute = legacySetupMock.server.route.mock.calls[0][0]; expect(firstRoute).toEqual({ method: 'GET', @@ -51,7 +53,7 @@ describe('createApi', () => { handler: expect.any(Function) }); - const secondRoute = coreMock.http.server.route.mock.calls[1][0]; + const secondRoute = legacySetupMock.server.route.mock.calls[1][0]; expect(secondRoute).toEqual({ method: 'POST', @@ -66,6 +68,7 @@ describe('createApi', () => { describe('when validating', () => { const initApi = (params: Params) => { const core = getCoreMock(); + const legacySetupMock = getLegacyMock(); const handler = jest.fn(); createApi() .add(() => ({ @@ -73,9 +76,9 @@ describe('createApi', () => { params, handler })) - .init(core); + .init(core, legacySetupMock); - const route = core.http.server.route.mock.calls[0][0]; + const route = legacySetupMock.server.route.mock.calls[0][0]; const routeHandler = route.handler; diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts index f969e4d6024ca5..eae4fd4988debd 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts @@ -5,7 +5,7 @@ */ import { merge, pick, omit, difference } from 'lodash'; import Boom from 'boom'; -import { InternalCoreSetup } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; import { Request, ResponseToolkit } from 'hapi'; import * as t from 'io-ts'; import { PathReporter } from 'io-ts/lib/PathReporter'; @@ -18,6 +18,7 @@ import { Params } from '../typings'; import { jsonRt } from '../../../common/runtime_types/json_rt'; +import { LegacySetup } from '../../new-platform/plugin'; const debugRt = t.partial({ _debug: jsonRt.pipe(t.boolean) }); @@ -29,10 +30,10 @@ export function createApi() { factoryFns.push(fn); return this as any; }, - init(core: InternalCoreSetup) { - const { server } = core.http; + init(core: CoreSetup, __LEGACY: LegacySetup) { + const { server } = __LEGACY; factoryFns.forEach(fn => { - const { params = {}, ...route } = fn(core) as Route< + const { params = {}, ...route } = fn(core, __LEGACY) as Route< string, HttpMethod, Params, diff --git a/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts b/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts index 100df4dc238fe9..92e1284f3ed74e 100644 --- a/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts +++ b/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts @@ -9,15 +9,14 @@ import { createRoute } from './create_route'; import { getKueryBarIndexPattern } from '../lib/index_pattern/getKueryBarIndexPattern'; import { setupRequest } from '../lib/helpers/setup_request'; -export const indexPatternRoute = createRoute(core => ({ +export const indexPatternRoute = createRoute((core, { server }) => ({ path: '/api/apm/index_pattern', handler: async () => { - const { server } = core.http; return await getAPMIndexPattern(server); } })); -export const kueryBarIndexPatternRoute = createRoute(core => ({ +export const kueryBarIndexPatternRoute = createRoute(() => ({ path: '/api/apm/kuery_bar_index_pattern', params: { query: t.partial({ @@ -30,9 +29,7 @@ export const kueryBarIndexPatternRoute = createRoute(core => ({ }, handler: async (request, { query }) => { const { processorEvent } = query; - const setup = await setupRequest(request); - return getKueryBarIndexPattern({ request, processorEvent, setup }); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/services.ts b/x-pack/legacy/plugins/apm/server/routes/services.ts index 85d53925db86e4..26fdf2ab65d1a3 100644 --- a/x-pack/legacy/plugins/apm/server/routes/services.ts +++ b/x-pack/legacy/plugins/apm/server/routes/services.ts @@ -16,7 +16,7 @@ import { createRoute } from './create_route'; import { uiFiltersRt, rangeRt } from './default_api_types'; import { getServiceMap } from '../lib/services/map'; -export const servicesRoute = createRoute(core => ({ +export const servicesRoute = createRoute((core, { server }) => ({ path: '/api/apm/services', params: { query: t.intersection([uiFiltersRt, rangeRt]) @@ -24,7 +24,6 @@ export const servicesRoute = createRoute(core => ({ handler: async req => { const setup = await setupRequest(req); const services = await getServices(setup); - const { server } = core.http; // Store telemetry data derived from services const agentNames = services.items.map( diff --git a/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts b/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts index 3c82a35ec79033..40c29f30504558 100644 --- a/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts +++ b/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts @@ -14,28 +14,26 @@ import { import { saveApmIndices } from '../../lib/settings/apm_indices/save_apm_indices'; // get list of apm indices and values -export const apmIndexSettingsRoute = createRoute(core => ({ +export const apmIndexSettingsRoute = createRoute((core, { server }) => ({ method: 'GET', path: '/api/apm/settings/apm-index-settings', handler: async req => { - const { server } = core.http; const setup = await setupRequest(req); return await getApmIndexSettings({ setup, server }); } })); // get apm indices configuration object -export const apmIndicesRoute = createRoute(core => ({ +export const apmIndicesRoute = createRoute((core, { server }) => ({ method: 'GET', path: '/api/apm/settings/apm-indices', handler: async req => { - const { server } = core.http; return await getApmIndices(server); } })); // save ui indices -export const saveApmIndicesRoute = createRoute(core => ({ +export const saveApmIndicesRoute = createRoute((core, { server }) => ({ method: 'POST', path: '/api/apm/settings/apm-indices/save', params: { @@ -50,7 +48,6 @@ export const saveApmIndicesRoute = createRoute(core => ({ }) }, handler: async (req, { body }) => { - const { server } = core.http; return await saveApmIndices(server, body); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/typings.ts b/x-pack/legacy/plugins/apm/server/routes/typings.ts index a0ddffe044c151..8ba8c067fb961a 100644 --- a/x-pack/legacy/plugins/apm/server/routes/typings.ts +++ b/x-pack/legacy/plugins/apm/server/routes/typings.ts @@ -6,9 +6,10 @@ import t from 'io-ts'; import { Request, ResponseToolkit } from 'hapi'; -import { InternalCoreSetup } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; import { PickByValue, Optional } from 'utility-types'; import { FetchOptions } from '../../public/services/rest/callApi'; +import { LegacySetup } from '../new-platform/plugin'; export interface Params { query?: t.HasProps; @@ -45,7 +46,10 @@ export type RouteFactoryFn< TMethod extends HttpMethod | undefined, TParams extends Params, TReturn -> = (core: InternalCoreSetup) => Route; +> = ( + core: CoreSetup, + __LEGACY: LegacySetup +) => Route; export interface RouteState { [key: string]: { @@ -76,7 +80,7 @@ export interface ServerAPI { }; } >; - init: (core: InternalCoreSetup) => void; + init: (core: CoreSetup, __LEGACY: LegacySetup) => void; } // without this, TS does not recognize possible existence of `params` in `options` below From 167dd7f5a001a9d1ecc48f0125d5b81999f620a6 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 13 Nov 2019 11:05:49 +0000 Subject: [PATCH 04/59] [ML] Server info service refactor (#50302) * [ML] Server info service refactor * removing new job defaults * changes based on review * renaming all ml server info getter functions * missed a file --- .../file_datavisualizer_directive.js | 4 +- .../components/edit_job_flyout/edit_utils.js | 4 +- .../edit_job_flyout/tabs/datafeed.js | 4 +- .../node_available_warning.tsx | 96 +++++++++---------- .../jobs/jobs_list/components/validate_job.js | 4 +- .../ml/public/jobs/jobs_list/directive.js | 4 +- .../common/job_validator/job_validator.ts | 4 +- .../new_job_new/common/job_validator/util.ts | 4 +- .../model_memory_limit_input.tsx | 4 +- .../scroll_size/scroll_size_input.tsx | 4 +- .../datafeed_details/datafeed_details.tsx | 4 +- .../components/job_details/job_details.tsx | 4 +- .../jobs/new_job_new/pages/new_job/route.ts | 4 +- .../services/__mocks__/ml_info_response.json | 21 ++++ .../ml/public/services/cloud_service.js | 30 ------ .../public/services/ml_api_service/index.d.ts | 2 +- .../ml/public/services/ml_server_info.test.ts | 62 ++++++++++++ .../ml_server_info.ts} | 12 +-- 18 files changed, 162 insertions(+), 109 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/public/services/__mocks__/ml_info_response.json delete mode 100644 x-pack/legacy/plugins/ml/public/services/cloud_service.js create mode 100644 x-pack/legacy/plugins/ml/public/services/ml_server_info.test.ts rename x-pack/legacy/plugins/ml/public/{jobs/new_job_new/utils/new_job_defaults.ts => services/ml_server_info.ts} (84%) diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js index fa4e0c2654e976..8b76e57029bd14 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js @@ -16,7 +16,7 @@ import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs'; import { checkBasicLicense } from '../../license/check_license'; import { checkFindFileStructurePrivilege } from '../../privilege/check_privilege'; import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes'; -import { loadNewJobDefaults } from '../../jobs/new_job_new/utils/new_job_defaults'; +import { loadMlServerInfo } from '../../services/ml_server_info'; import { loadIndexPatterns } from '../../util/index_utils'; import { FileDataVisualizerPage } from './file_datavisualizer'; @@ -36,7 +36,7 @@ uiRoutes privileges: checkFindFileStructurePrivilege, indexPatterns: loadIndexPatterns, mlNodeCount: getMlNodeCount, - loadNewJobDefaults, + loadMlServerInfo, } }); diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_utils.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_utils.js index 8bd3d9228b8579..2b01a848945648 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_utils.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_utils.js @@ -7,7 +7,7 @@ import { difference } from 'lodash'; import chrome from 'ui/chrome'; -import { newJobLimits } from 'plugins/ml/jobs/new_job_new/utils/new_job_defaults'; +import { getNewJobLimits } from '../../../../services/ml_server_info'; import { mlJobService } from 'plugins/ml/services/job_service'; import { processCreatedBy } from '../../../../../common/util/job_utils'; @@ -157,7 +157,7 @@ function extractGroups(job, newJobData) { } function extractMML(job, newJobData) { - const jobLimits = newJobLimits(); + const jobLimits = getNewJobLimits(); const mmlData = {}; // if the job's model_memory_limit has changed, add it to the jobData json if (job.analysis_limits.model_memory_limit !== undefined) { diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/datafeed.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/datafeed.js index e7e99830372d83..b09162b0e84cff 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/datafeed.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/datafeed.js @@ -19,7 +19,7 @@ import { } from '@elastic/eui'; import { calculateDatafeedFrequencyDefaultSeconds } from 'plugins/ml/../common/util/job_utils'; -import { newJobDefaults } from 'plugins/ml/jobs/new_job_new/utils/new_job_defaults'; +import { getNewJobDefaults } from '../../../../../services/ml_server_info'; import { parseInterval } from 'plugins/ml/../common/util/parse_interval'; import { MLJobEditor } from '../../ml_job_editor'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -47,7 +47,7 @@ export class Datafeed extends Component { frequency: '', scrollSize: 0, }, - jobDefaults: newJobDefaults() + jobDefaults: getNewJobDefaults() }; this.setDatafeed = props.setDatafeed; diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx index 17562aba8e45a0..c4684f356fdafc 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx @@ -9,58 +9,58 @@ import React, { Fragment, FC } from 'react'; import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { mlNodesAvailable, permissionToViewMlNodeCount } from '../../../../ml_nodes_check'; -import { cloudDeploymentId, isCloud } from '../../../../jobs/new_job_new/utils/new_job_defaults'; +import { getCloudDeploymentId, isCloud } from '../../../../services/ml_server_info'; export const NodeAvailableWarning: FC = () => { if (mlNodesAvailable() === true || permissionToViewMlNodeCount() === false) { return null; - } else { - const id = cloudDeploymentId(); - return ( - - - } - color="warning" - iconType="alert" - > -

- -
+ } + + const id = getCloudDeploymentId(); + return ( + + + } + color="warning" + iconType="alert" + > +

+ +
+
+ +
+ {isCloud && id !== null && ( +
+ + + ), + }} /> - {isCloud && id !== null && ( - -
- - - - ), - }} - /> -
- )} -

- - - - ); - } +
+ )} + + + + ); }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js index 05f9ec9d943f98..71e16188db9482 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js @@ -5,7 +5,7 @@ */ -import { newJobLimits } from '../../new_job_new/utils/new_job_defaults'; +import { getNewJobLimits } from '../../../services/ml_server_info'; import { populateValidationMessages } from '../../new_job_new/common/job_validator/util'; import { @@ -16,7 +16,7 @@ import { import { isValidLabel, isValidTimeRange } from '../../../util/custom_url_utils'; export function validateModelMemoryLimit(mml) { - const limits = newJobLimits(); + const limits = getNewJobLimits(); const tempJob = { analysis_limits: { model_memory_limit: mml diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/directive.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/directive.js index 3267c78deecc16..4b6f3f485d49de 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/directive.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/directive.js @@ -16,7 +16,7 @@ import { checkFullLicense } from 'plugins/ml/license/check_license'; import { checkGetJobsPrivilege } from 'plugins/ml/privilege/check_privilege'; import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; import { getJobManagementBreadcrumbs } from 'plugins/ml/jobs/breadcrumbs'; -import { loadNewJobDefaults } from 'plugins/ml/jobs/new_job_new/utils/new_job_defaults'; +import { loadMlServerInfo } from 'plugins/ml/services/ml_server_info'; import uiRoutes from 'ui/routes'; @@ -31,7 +31,7 @@ uiRoutes indexPatterns: loadIndexPatterns, privileges: checkGetJobsPrivilege, mlNodeCount: getMlNodeCount, - loadNewJobDefaults, + loadMlServerInfo, } }); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts index 358bbf67bee485..82b1684b7b72f3 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts @@ -6,7 +6,7 @@ import { ReactElement } from 'react'; import { basicJobValidation, basicDatafeedValidation } from '../../../../../common/util/job_utils'; -import { newJobLimits } from '../../../new_job_new/utils/new_job_defaults'; +import { getNewJobLimits } from '../../../../services/ml_server_info'; import { JobCreatorType } from '../job_creator'; import { populateValidationMessages, checkForExistingJobAndGroupIds } from './util'; import { ExistingJobsAndGroups } from '../../../../services/job_service'; @@ -111,7 +111,7 @@ export class JobValidator { const jobConfig = this._jobCreator.jobConfig; const datafeedConfig = this._jobCreator.datafeedConfig; - const limits = newJobLimits(); + const limits = getNewJobLimits(); // run standard basic validation const basicJobResults = basicJobValidation(jobConfig, undefined, limits); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts index 224d9ebf558239..b1bd352db387bf 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { BasicValidations } from './job_validator'; import { Job, Datafeed } from '../job_creator/configs'; import { ALLOWED_DATA_UNITS, JOB_ID_MAX_LENGTH } from '../../../../../common/constants/validation'; -import { newJobLimits } from '../../../new_job_new/utils/new_job_defaults'; +import { getNewJobLimits } from '../../../../services/ml_server_info'; import { ValidationResults, ValidationMessage } from '../../../../../common/util/job_utils'; import { ExistingJobsAndGroups } from '../../../../services/job_service'; @@ -18,7 +18,7 @@ export function populateValidationMessages( jobConfig: Job, datafeedConfig: Datafeed ) { - const limits = newJobLimits(); + const limits = getNewJobLimits(); if (validationResults.contains('job_id_empty')) { basicValidations.jobId.valid = false; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx index 3a3bd0c5a13a4c..54fb19d868cdce 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx @@ -6,7 +6,7 @@ import React, { FC, useState, useContext, useEffect } from 'react'; import { EuiFieldText } from '@elastic/eui'; -import { newJobDefaults } from '../../../../../new_job_new/utils/new_job_defaults'; +import { getNewJobDefaults } from '../../../../../../services/ml_server_info'; import { JobCreatorContext } from '../../job_creator_context'; import { Description } from './description'; @@ -23,7 +23,7 @@ export const ModelMemoryLimitInput: FC = () => { jobCreator.modelMemoryLimit === null ? '' : jobCreator.modelMemoryLimit ); - const { anomaly_detectors: anomalyDetectors } = newJobDefaults(); + const { anomaly_detectors: anomalyDetectors } = getNewJobDefaults(); const { model_memory_limit: modelMemoryLimitDefault } = anomalyDetectors; useEffect(() => { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx index da6a19434135c9..ea03d16fcccca7 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx @@ -6,7 +6,7 @@ import React, { FC, useState, useContext, useEffect } from 'react'; import { EuiFieldNumber } from '@elastic/eui'; -import { newJobDefaults } from '../../../../../utils/new_job_defaults'; +import { getNewJobDefaults } from '../../../../../../../services/ml_server_info'; import { JobCreatorContext } from '../../../job_creator_context'; import { Description } from './description'; @@ -19,7 +19,7 @@ export const ScrollSizeInput: FC = () => { jobCreator.scrollSize === null ? '' : `${jobCreator.scrollSize}` ); - const { datafeeds } = newJobDefaults(); + const { datafeeds } = getNewJobDefaults(); const scrollSizeDefault = datafeeds.scroll_size !== undefined ? `${datafeeds.scroll_size}` : ''; useEffect(() => { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx index 1927fc430abcbc..5e1bf9f1ec889b 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx @@ -11,14 +11,14 @@ import { JobCreatorContext } from '../../../job_creator_context'; import { MLJobEditor } from '../../../../../../jobs_list/components/ml_job_editor'; import { calculateDatafeedFrequencyDefaultSeconds } from '../../../../../../../../common/util/job_utils'; import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants'; -import { newJobDefaults } from '../../../../../utils/new_job_defaults'; +import { getNewJobDefaults } from '../../../../../../../services/ml_server_info'; import { ListItems, defaultLabel, Italic } from '../common'; const EDITOR_HEIGHT = '200px'; export const DatafeedDetails: FC = () => { const { jobCreator } = useContext(JobCreatorContext); - const { datafeeds } = newJobDefaults(); + const { datafeeds } = getNewJobDefaults(); const queryString = JSON.stringify(jobCreator.query, null, 2); const defaultFrequency = calculateDatafeedFrequencyDefaultSeconds(jobCreator.bucketSpanMs / 1000); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx index dc0311e552bdab..ebe113a1f8befe 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx @@ -15,7 +15,7 @@ import { isPopulationJobCreator, isAdvancedJobCreator, } from '../../../../../common/job_creator'; -import { newJobDefaults } from '../../../../../utils/new_job_defaults'; +import { getNewJobDefaults } from '../../../../../../../services/ml_server_info'; import { ListItems, falseLabel, trueLabel, defaultLabel, Italic } from '../common'; import { useKibanaContext } from '../../../../../../../contexts/kibana'; @@ -23,7 +23,7 @@ export const JobDetails: FC = () => { const { jobCreator } = useContext(JobCreatorContext); const kibanaContext = useKibanaContext(); const dateFormat: string = kibanaContext.kibanaConfig.get('dateFormat'); - const { anomaly_detectors: anomalyDetectors } = newJobDefaults(); + const { anomaly_detectors: anomalyDetectors } = getNewJobDefaults(); const isAdvanced = isAdvancedJobCreator(jobCreator); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts index 964dc1eee51402..09f14c971418d3 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts @@ -22,7 +22,7 @@ import { Route } from '../../../../../common/types/kibana'; import { loadNewJobCapabilities } from '../../../../services/new_job_capabilities_service'; -import { loadNewJobDefaults } from '../../utils/new_job_defaults'; +import { loadMlServerInfo } from '../../../../services/ml_server_info'; import { mlJobService } from '../../../../services/job_service'; import { JOB_TYPE } from '../../common/job_creator/util/constants'; @@ -58,7 +58,7 @@ routes.forEach((route: Route) => { indexPattern: loadCurrentIndexPattern, savedSearch: loadCurrentSavedSearch, loadNewJobCapabilities, - loadNewJobDefaults, + loadMlServerInfo, existingJobsAndGroups: mlJobService.getJobAndGroupIds, jobType: () => route.id, }, diff --git a/x-pack/legacy/plugins/ml/public/services/__mocks__/ml_info_response.json b/x-pack/legacy/plugins/ml/public/services/__mocks__/ml_info_response.json new file mode 100644 index 00000000000000..ab6dcf8a5b5f66 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/services/__mocks__/ml_info_response.json @@ -0,0 +1,21 @@ +{ + "defaults": { + "anomaly_detectors": { + "model_memory_limit": "128mb", + "categorization_examples_limit": 4, + "model_snapshot_retention_days": 1 + }, + "datafeeds": { + "scroll_size": 1000 + } + }, + "upgrade_mode": false, + "native_code": { + "version": "8.0.0-SNAPSHOT", + "build_hash": "4cde1d7c50fc28" + }, + "limits": { + "max_model_memory_limit": "128mb" + }, + "cloudId": "cloud_message_test:ZXUtd2VzdC0yLmF3cy5jbG91ZC5lcy5pbyQ4NWQ2NjZmMzM1MGM0NjllOGMzMjQyZDc2YTdmNDU5YyQxNmI1ZDM2ZGE1Mzk0YjlkYjIyZWJlNDk1OWY1OGQzMg==" +} diff --git a/x-pack/legacy/plugins/ml/public/services/cloud_service.js b/x-pack/legacy/plugins/ml/public/services/cloud_service.js deleted file mode 100644 index b9777e34737ae0..00000000000000 --- a/x-pack/legacy/plugins/ml/public/services/cloud_service.js +++ /dev/null @@ -1,30 +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; - * you may not use this file except in compliance with the Elastic License. - */ - - - -export function cloudServiceProvider(config) { - function isRunningOnCloud() { - try { - return config.get('cloud.enabled'); - } catch (error) { - return false; - } - } - - function getCloudId() { - try { - return config.get('cloud.id'); - } catch (error) { - return undefined; - } - } - - return { - isRunningOnCloud, - getCloudId - }; -} diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts index 4f042c638471d1..38a71d994c601e 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts @@ -9,7 +9,7 @@ import { AggFieldNamePair } from '../../../common/types/fields'; import { ExistingJobsAndGroups } from '../job_service'; import { PrivilegesResponse } from '../../../common/types/privileges'; import { MlSummaryJobs } from '../../../common/types/jobs'; -import { MlServerDefaults, MlServerLimits } from '../../jobs/new_job_new/utils/new_job_defaults'; +import { MlServerDefaults, MlServerLimits } from '../../services/ml_server_info'; import { ES_AGGREGATION } from '../../../common/constants/aggregation_types'; import { DataFrameAnalyticsStats } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/common'; diff --git a/x-pack/legacy/plugins/ml/public/services/ml_server_info.test.ts b/x-pack/legacy/plugins/ml/public/services/ml_server_info.test.ts new file mode 100644 index 00000000000000..2b6fb505380208 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/services/ml_server_info.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + loadMlServerInfo, + getCloudDeploymentId, + isCloud, + getNewJobDefaults, + getNewJobLimits, +} from './ml_server_info'; +import mockMlInfoResponse from './__mocks__/ml_info_response.json'; + +jest.mock('./ml_api_service', () => ({ + ml: { + mlInfo: jest.fn(() => Promise.resolve(mockMlInfoResponse)), + }, +})); + +describe('ml_server_info initial state', () => { + it('server info not loaded ', () => { + expect(isCloud()).toBe(false); + expect(getCloudDeploymentId()).toBe(null); + }); +}); + +describe('ml_server_info', () => { + beforeEach(async done => { + await loadMlServerInfo(); + done(); + }); + + describe('cloud information', () => { + it('can get could deployment id', () => { + expect(isCloud()).toBe(true); + expect(getCloudDeploymentId()).toBe('85d666f3350c469e8c3242d76a7f459c'); + }); + }); + + describe('defaults', () => { + it('can get defaults', async done => { + const defaults = getNewJobDefaults(); + + expect(defaults.anomaly_detectors.model_memory_limit).toBe('128mb'); + expect(defaults.anomaly_detectors.categorization_examples_limit).toBe(4); + expect(defaults.anomaly_detectors.model_snapshot_retention_days).toBe(1); + expect(defaults.datafeeds.scroll_size).toBe(1000); + done(); + }); + }); + + describe('limits', () => { + it('can get limits', async done => { + const limits = getNewJobLimits(); + + expect(limits.max_model_memory_limit).toBe('128mb'); + done(); + }); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts b/x-pack/legacy/plugins/ml/public/services/ml_server_info.ts similarity index 84% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts rename to x-pack/legacy/plugins/ml/public/services/ml_server_info.ts index e3c4bc8a4a28ce..95d670eda8a4f1 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts +++ b/x-pack/legacy/plugins/ml/public/services/ml_server_info.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ml } from '../../../services/ml_api_service'; +import { ml } from './ml_api_service'; export interface MlServerDefaults { anomaly_detectors: { @@ -35,7 +35,7 @@ const cloudInfo: CloudInfo = { isCloud: false, }; -export async function loadNewJobDefaults() { +export async function loadMlServerInfo() { try { const resp = await ml.mlInfo(); defaults = resp.defaults; @@ -48,15 +48,15 @@ export async function loadNewJobDefaults() { } } -export function newJobDefaults(): MlServerDefaults { +export function getNewJobDefaults(): MlServerDefaults { return defaults; } -export function newJobLimits(): MlServerLimits { +export function getNewJobLimits(): MlServerLimits { return limits; } -export function cloudId(): string | null { +export function getCloudId(): string | null { return cloudInfo.cloudId; } @@ -64,7 +64,7 @@ export function isCloud(): boolean { return cloudInfo.isCloud; } -export function cloudDeploymentId(): string | null { +export function getCloudDeploymentId(): string | null { if (cloudInfo.cloudId === null) { return null; } From 3a2e865b2ffb9d879cde93598c5658cc98e3d560 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Wed, 13 Nov 2019 17:26:30 +0400 Subject: [PATCH 05/59] Move mockFields and mockIndexPatterns to relevant directories (#50012) * Move mockFields and mockIndexPatterns to relevant directories * Restructure stubs store * Remove test code from production files * Restructure stubs store --- .../lib/filter_editor_utils.test.ts | 11 +-- src/legacy/core_plugins/data/public/index.ts | 2 - .../index_patterns/index_patterns_service.ts | 4 +- .../data/public/index_patterns/utils.ts | 69 +--------------- .../public/index_patterns/__mocks__/index.ts | 2 - src/legacy/ui/public/index_patterns/index.ts | 2 - src/plugins/data/common/types.ts | 6 ++ .../data/public/index_patterns/field.stub.ts | 79 +++++++++++++++++++ .../index_patterns/index_pattern.stub.ts | 28 +++++++ src/plugins/data/public/stubs.ts | 21 +++++ .../value_suggestions.test.ts | 32 ++++---- 11 files changed, 158 insertions(+), 98 deletions(-) create mode 100644 src/plugins/data/public/index_patterns/field.stub.ts create mode 100644 src/plugins/data/public/index_patterns/index_pattern.stub.ts create mode 100644 src/plugins/data/public/stubs.ts diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts index dbff5096f2287d..7ee3e375c0967e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts @@ -17,7 +17,8 @@ * under the License. */ -import { mockFields, mockIndexPattern } from '../../../../index_patterns'; +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import { stubIndexPattern, stubFields } from '../../../../../../../../plugins/data/public/stubs'; import { IndexPattern, Field } from '../../../../index'; import { buildFilter, @@ -45,8 +46,8 @@ import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); -const mockedFields = mockFields as Field[]; -const mockedIndexPattern = mockIndexPattern as IndexPattern; +const mockedFields = stubFields as Field[]; +const mockedIndexPattern = stubIndexPattern as IndexPattern; describe('Filter editor utils', () => { describe('getQueryDslFromFilter', () => { @@ -171,14 +172,14 @@ describe('Filter editor utils', () => { describe('getOperatorOptions', () => { it('returns range for number fields', () => { - const [field] = mockFields.filter(({ type }) => type === 'number'); + const [field] = stubFields.filter(({ type }) => type === 'number'); const operatorOptions = getOperatorOptions(field as Field); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).not.toBeUndefined(); }); it('does not return range for string fields', () => { - const [field] = mockFields.filter(({ type }) => type === 'string'); + const [field] = stubFields.filter(({ type }) => type === 'string'); const operatorOptions = getOperatorOptions(field as Field); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).toBeUndefined(); diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 60828b4a2a2025..c3892fa581fc42 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -58,6 +58,4 @@ export { IndexPatternMissingIndices, NoDefaultIndexPattern, NoDefinedIndexPatterns, - mockFields, - mockIndexPattern, } from './index_patterns'; diff --git a/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts b/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts index bdeeb787c983d6..9ce1b5f2e4a208 100644 --- a/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts +++ b/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts @@ -24,11 +24,11 @@ import { NotificationsStart, } from 'src/core/public'; import { Field, FieldList, FieldListInterface, FieldType } from './fields'; -import { createFlattenHitWrapper } from './index_patterns'; import { createIndexPatternSelect } from './components'; import { setNotifications } from './services'; import { + createFlattenHitWrapper, formatHitProvider, IndexPattern, IndexPatterns, @@ -92,8 +92,6 @@ export { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE, isFilterable, validateIndexPattern, - mockFields, - mockIndexPattern, } from './utils'; /** @public */ diff --git a/src/legacy/core_plugins/data/public/index_patterns/utils.ts b/src/legacy/core_plugins/data/public/index_patterns/utils.ts index 62f5ddbe9e2b05..1c877f4f142513 100644 --- a/src/legacy/core_plugins/data/public/index_patterns/utils.ts +++ b/src/legacy/core_plugins/data/public/index_patterns/utils.ts @@ -19,8 +19,7 @@ import { find, get } from 'lodash'; -import { Field, FieldType } from './fields'; -import { StaticIndexPattern } from './index_patterns'; +import { Field } from './fields'; import { getFilterableKbnTypeNames } from '../../../../../plugins/data/public'; import { SavedObjectsClientContract, SimpleSavedObject } from '../../../../../core/public'; @@ -139,69 +138,3 @@ export function getRoutes() { sourceFilters: '/management/kibana/index_patterns/{{id}}?_a=(tab:sourceFilters)', }; } - -export const mockFields: FieldType[] = [ - { - name: 'machine.os', - esTypes: ['text'], - type: 'string', - aggregatable: false, - searchable: false, - filterable: true, - }, - { - name: 'machine.os.raw', - type: 'string', - esTypes: ['keyword'], - aggregatable: true, - searchable: true, - filterable: true, - }, - { - name: 'not.filterable', - type: 'string', - esTypes: ['text'], - aggregatable: true, - searchable: false, - filterable: false, - }, - { - name: 'bytes', - type: 'number', - esTypes: ['long'], - aggregatable: true, - searchable: true, - filterable: true, - }, - { - name: '@timestamp', - type: 'date', - esTypes: ['date'], - aggregatable: true, - searchable: true, - filterable: true, - }, - { - name: 'clientip', - type: 'ip', - esTypes: ['ip'], - aggregatable: true, - searchable: true, - filterable: true, - }, - { - name: 'bool.field', - type: 'boolean', - esTypes: ['boolean'], - aggregatable: true, - searchable: true, - filterable: true, - }, -]; - -export const mockIndexPattern: StaticIndexPattern = { - id: 'logstash-*', - fields: mockFields, - title: 'logstash-*', - timeFieldName: '@timestamp', -}; diff --git a/src/legacy/ui/public/index_patterns/__mocks__/index.ts b/src/legacy/ui/public/index_patterns/__mocks__/index.ts index 85c07cb3b1df17..2dd3f370c6d6aa 100644 --- a/src/legacy/ui/public/index_patterns/__mocks__/index.ts +++ b/src/legacy/ui/public/index_patterns/__mocks__/index.ts @@ -45,6 +45,4 @@ export { IndexPatternMissingIndices, NoDefaultIndexPattern, NoDefinedIndexPatterns, - mockFields, - mockIndexPattern, } from '../../../../core_plugins/data/public'; diff --git a/src/legacy/ui/public/index_patterns/index.ts b/src/legacy/ui/public/index_patterns/index.ts index 67c370cad82a50..3b4952ac815192 100644 --- a/src/legacy/ui/public/index_patterns/index.ts +++ b/src/legacy/ui/public/index_patterns/index.ts @@ -47,8 +47,6 @@ export { IndexPatternMissingIndices, NoDefaultIndexPattern, NoDefinedIndexPatterns, - mockFields, - mockIndexPattern, } from '../../../core_plugins/data/public'; // types diff --git a/src/plugins/data/common/types.ts b/src/plugins/data/common/types.ts index 9eda75d8abd0b6..eae7c26e3ab3f9 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -21,3 +21,9 @@ export * from './field_formats/types'; export * from './timefilter/types'; export * from './query/types'; export * from './kbn_field_types/types'; + +// We can't import the real types from the data plugin, so need to either duplicate +// them here or figure out another solution, perhaps housing them in this package +// will be replaces after Fieds / IndexPattern will be moved into new platform +export type Field = any; +export type IndexPattern = any; diff --git a/src/plugins/data/public/index_patterns/field.stub.ts b/src/plugins/data/public/index_patterns/field.stub.ts new file mode 100644 index 00000000000000..315894cd212c40 --- /dev/null +++ b/src/plugins/data/public/index_patterns/field.stub.ts @@ -0,0 +1,79 @@ +/* + * 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 { Field } from '../../common'; + +export const stubFields: Field[] = [ + { + name: 'machine.os', + esTypes: ['text'], + type: 'string', + aggregatable: false, + searchable: false, + filterable: true, + }, + { + name: 'machine.os.raw', + type: 'string', + esTypes: ['keyword'], + aggregatable: true, + searchable: true, + filterable: true, + }, + { + name: 'not.filterable', + type: 'string', + esTypes: ['text'], + aggregatable: true, + searchable: false, + filterable: false, + }, + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + aggregatable: true, + searchable: true, + filterable: true, + }, + { + name: '@timestamp', + type: 'date', + esTypes: ['date'], + aggregatable: true, + searchable: true, + filterable: true, + }, + { + name: 'clientip', + type: 'ip', + esTypes: ['ip'], + aggregatable: true, + searchable: true, + filterable: true, + }, + { + name: 'bool.field', + type: 'boolean', + esTypes: ['boolean'], + aggregatable: true, + searchable: true, + filterable: true, + }, +]; diff --git a/src/plugins/data/public/index_patterns/index_pattern.stub.ts b/src/plugins/data/public/index_patterns/index_pattern.stub.ts new file mode 100644 index 00000000000000..444e65cd0cd4b9 --- /dev/null +++ b/src/plugins/data/public/index_patterns/index_pattern.stub.ts @@ -0,0 +1,28 @@ +/* + * 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 { IndexPattern } from '../../common'; +import { stubFields } from './field.stub'; + +export const stubIndexPattern: IndexPattern = { + id: 'logstash-*', + fields: stubFields, + title: 'logstash-*', + timeFieldName: '@timestamp', +}; diff --git a/src/plugins/data/public/stubs.ts b/src/plugins/data/public/stubs.ts new file mode 100644 index 00000000000000..40a5e7d18f8d9f --- /dev/null +++ b/src/plugins/data/public/stubs.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { stubIndexPattern } from './index_patterns/index_pattern.stub'; +export { stubFields } from './index_patterns/field.stub'; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index 13ccbbd9f3ddea..de2147cd752671 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -21,7 +21,7 @@ jest.mock('ui/new_platform'); jest.mock('ui/index_patterns'); -import { mockFields, mockIndexPattern } from 'ui/index_patterns'; +import { stubIndexPattern, stubFields } from '../stubs'; import { getSuggestionsProvider } from './value_suggestions'; import { UiSettingsClientContract } from 'kibana/public'; @@ -37,8 +37,8 @@ describe('getSuggestions', () => { }); it('should return an empty array', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields; + const index = stubIndexPattern.id; + const [field] = stubFields; const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); @@ -54,8 +54,8 @@ describe('getSuggestions', () => { }); it('should return true/false for boolean fields', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter(({ type }) => type === 'boolean'); + const index = stubIndexPattern.id; + const [field] = stubFields.filter(({ type }) => type === 'boolean'); const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([true, false]); @@ -63,8 +63,8 @@ describe('getSuggestions', () => { }); it('should return an empty array if the field type is not a string or boolean', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter(({ type }) => type !== 'string' && type !== 'boolean'); + const index = stubIndexPattern.id; + const [field] = stubFields.filter(({ type }) => type !== 'string' && type !== 'boolean'); const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); @@ -72,8 +72,8 @@ describe('getSuggestions', () => { }); it('should return an empty array if the field is not aggregatable', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter(({ aggregatable }) => !aggregatable); + const index = stubIndexPattern.id; + const [field] = stubFields.filter(({ aggregatable }) => !aggregatable); const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); @@ -81,8 +81,8 @@ describe('getSuggestions', () => { }); it('should otherwise request suggestions', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter( + const index = stubIndexPattern.id; + const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); const query = ''; @@ -91,8 +91,8 @@ describe('getSuggestions', () => { }); it('should cache results if using the same index/field/query/filter', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter( + const index = stubIndexPattern.id; + const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); const query = ''; @@ -102,8 +102,8 @@ describe('getSuggestions', () => { }); it('should cache results for only one minute', async () => { - const index = mockIndexPattern.id; - const [field] = mockFields.filter( + const index = stubIndexPattern.id; + const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); const query = ''; @@ -119,7 +119,7 @@ describe('getSuggestions', () => { }); it('should not cache results if using a different index/field/query', async () => { - const fields = mockFields.filter( + const fields = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); await getSuggestions('index', fields[0], ''); From 7bb968c5541095cd7b0883813e7cabf99302b21c Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Wed, 13 Nov 2019 08:59:50 -0500 Subject: [PATCH 06/59] [Canvas] Fix incompatible ie11 method (#50007) * Fix incompatible ie11 method * Comment about origin of polyfill --- .../workpad_interactive_page/index.js | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js index 56ea35a6887ec6..454fa6f917aec9 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js @@ -58,6 +58,21 @@ const configuration = { tooltipZ: 1100, }; +// Polyfill for browsers (IE11) that don't have element.closest +// From: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest +function closest(s) { + let el = this; + const matchFn = el.matches ? 'matches' : 'msMatchesSelector'; + + do { + if (el[matchFn](s)) { + return el; + } + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1); + return null; +} + const componentLayoutState = ({ aeroStore, setAeroStore, @@ -197,8 +212,15 @@ export const InteractivePage = compose( })), withProps((...props) => ({ ...props, - canDragElement: element => - !element.closest('.embeddable') || element.closest('.embPanel__header'), + canDragElement: element => { + const hasClosest = typeof element.closest === 'function'; + + if (hasClosest) { + return !element.closest('.embeddable') || element.closest('.embPanel__header'); + } else { + return !closest.call(element, '.embeddable') || closest.call(element, '.embPanel__header'); + } + }, })), withHandlers(eventHandlers), // Captures user intent, needs to have reconciled state () => InteractiveComponent From f317c2585252a177eae85c1aa71957ef4da6af02 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 13 Nov 2019 15:42:46 +0100 Subject: [PATCH 07/59] =?UTF-8?q?[APM]=20Use=20callWithInternalUser=20for?= =?UTF-8?q?=20agent=20configuration=20endpoin=E2=80=A6=20(#50211)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [APM] Use callWithInternalUser for agent configuration endpoints Closes #50050. * Review feedback * Use internalClient for agent conf queries only --- x-pack/legacy/plugins/apm/index.ts | 2 +- .../plugins/apm/public/utils/testHelpers.tsx | 19 +++++++++++- .../__tests__/get_buckets.test.ts | 3 ++ .../apm/server/lib/helpers/es_client.ts | 29 +++++++++++++------ .../server/lib/helpers/setup_request.test.ts | 29 +++++++++++++++++-- .../apm/server/lib/helpers/setup_request.ts | 3 +- .../create_or_update_configuration.ts | 4 +-- .../delete_configuration.ts | 4 +-- .../get_existing_environments_for_service.ts | 4 +-- .../list_configurations.ts | 4 +-- .../mark_applied_by_agent.ts | 4 +-- .../agent_configuration/search.test.ts | 2 ++ .../settings/agent_configuration/search.ts | 6 ++-- .../lib/transaction_groups/fetcher.test.ts | 3 ++ .../lib/transactions/breakdown/index.test.ts | 5 ++++ .../charts/get_anomaly_data/index.test.ts | 1 + .../get_timeseries_data/fetcher.test.ts | 1 + .../server/routes/create_api/index.test.ts | 21 +++++++++++++- .../apm/server/routes/create_api/index.ts | 15 ++++------ .../routes/settings/agent_configuration.ts | 9 ++++++ .../plugins/apm/server/routes/typings.ts | 3 ++ 21 files changed, 135 insertions(+), 36 deletions(-) diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index fe8cc43d7f55dc..4655e5e6f92ea8 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -87,7 +87,7 @@ export const apm: LegacyPluginInitializer = kibana => { catalogue: ['apm'], privileges: { all: { - api: ['apm'], + api: ['apm', 'apm_write'], catalogue: ['apm'], savedObject: { all: [], diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx index a18882120fe757..a224df9e59e58f 100644 --- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx @@ -97,6 +97,7 @@ interface MockSetup { start: number; end: number; client: any; + internalClient: any; config: { get: any; has: any; @@ -122,12 +123,21 @@ export async function inspectSearchParams( } }); + const internalClientSpy = jest.fn().mockReturnValueOnce({ + hits: { + total: 0 + } + }); + const mockSetup = { start: 1528113600000, end: 1528977600000, client: { search: clientSpy } as any, + internalClient: { + search: internalClientSpy + } as any, config: { get: () => 'myIndex' as any, has: () => true @@ -153,8 +163,15 @@ export async function inspectSearchParams( // we're only extracting the search params } + let params; + if (clientSpy.mock.calls.length) { + params = clientSpy.mock.calls[0][0]; + } else { + params = internalClientSpy.mock.calls[0][0]; + } + return { - params: clientSpy.mock.calls[0][0], + params, teardown: () => clientSpy.mockClear() }; } diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts index b7081c43465bf8..5bbd6be14a7082 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts @@ -31,6 +31,9 @@ describe('timeseriesFetcher', () => { client: { search: clientSpy } as any, + internalClient: { + search: clientSpy + } as any, config: { get: () => 'myIndex' as any, has: () => true diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts index ee41599454dd69..f38184fe460b1f 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts @@ -92,10 +92,23 @@ interface APMOptions { includeLegacyData: boolean; } -export function getESClient(req: Legacy.Request) { +interface ClientCreateOptions { + clientAsInternalUser?: boolean; +} + +export type ESClient = ReturnType; + +export function getESClient( + req: Legacy.Request, + { clientAsInternalUser = false }: ClientCreateOptions = {} +) { const cluster = req.server.plugins.elasticsearch.getCluster('data'); const query = req.query as Record; + const callMethod = clientAsInternalUser + ? cluster.callWithInternalUser.bind(cluster) + : cluster.callWithRequest.bind(cluster, req); + return { search: async < TDocument = unknown, @@ -121,20 +134,18 @@ export function getESClient(req: Legacy.Request) { console.log(JSON.stringify(nextParams.body, null, 4)); } - return (cluster.callWithRequest( - req, - 'search', - nextParams - ) as unknown) as Promise>; + return (callMethod('search', nextParams) as unknown) as Promise< + ESSearchResponse + >; }, index: (params: APMIndexDocumentParams) => { - return cluster.callWithRequest(req, 'index', params); + return callMethod('index', params); }, delete: (params: IndicesDeleteParams) => { - return cluster.callWithRequest(req, 'delete', params); + return callMethod('delete', params); }, indicesCreate: (params: IndicesCreateParams) => { - return cluster.callWithRequest(req, 'indices.create', params); + return callMethod('indices.create', params); } }; } diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts index 57de438be7f2ad..6ebf7a896591ff 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts @@ -21,6 +21,7 @@ jest.mock('../settings/apm_indices/get_apm_indices', () => ({ function getMockRequest() { const callWithRequestSpy = jest.fn(); + const callWithInternalUserSpy = jest.fn(); const mockRequest = ({ params: {}, query: {}, @@ -28,14 +29,17 @@ function getMockRequest() { config: () => ({ get: () => 'apm-*' }), plugins: { elasticsearch: { - getCluster: () => ({ callWithRequest: callWithRequestSpy }) + getCluster: () => ({ + callWithRequest: callWithRequestSpy, + callWithInternalUser: callWithInternalUserSpy + }) } } }, getUiSettingsService: () => ({ get: async () => false }) } as any) as Legacy.Request; - return { callWithRequestSpy, mockRequest }; + return { callWithRequestSpy, callWithInternalUserSpy, mockRequest }; } describe('setupRequest', () => { @@ -57,6 +61,27 @@ describe('setupRequest', () => { }); }); + it('should call callWithInternalUser with default args', async () => { + const { mockRequest, callWithInternalUserSpy } = getMockRequest(); + const { internalClient } = await setupRequest(mockRequest); + await internalClient.search({ + index: 'apm-*', + body: { foo: 'bar' } + } as any); + expect(callWithInternalUserSpy).toHaveBeenCalledWith('search', { + index: 'apm-*', + body: { + foo: 'bar', + query: { + bool: { + filter: [{ range: { 'observer.version_major': { gte: 7 } } }] + } + } + }, + ignore_throttled: true + }); + }); + describe('observer.version_major filter', () => { describe('if index is apm-*', () => { it('should merge `observer.version_major` filter with existing boolean filters', async () => { diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts index 3ec519d5e71b57..850de4939d5997 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts @@ -41,7 +41,8 @@ export async function setupRequest(req: Legacy.Request) { start: moment.utc(query.start).valueOf(), end: moment.utc(query.end).valueOf(), uiFiltersES, - client: getESClient(req), + client: getESClient(req, { clientAsInternalUser: false }), + internalClient: getESClient(req, { clientAsInternalUser: true }), config, indices }; diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts index 25a4f5141498f4..23faa4b74cf8fb 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts @@ -21,7 +21,7 @@ export async function createOrUpdateConfiguration({ >; setup: Setup; }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; const params: APMIndexDocumentParams = { refresh: true, @@ -44,5 +44,5 @@ export async function createOrUpdateConfiguration({ params.id = configurationId; } - return client.index(params); + return internalClient.index(params); } diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts index 896363c054ba78..ed20a58b271e10 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts @@ -13,7 +13,7 @@ export async function deleteConfiguration({ configurationId: string; setup: Setup; }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; const params = { refresh: 'wait_for', @@ -21,5 +21,5 @@ export async function deleteConfiguration({ id: configurationId }; - return client.delete(params); + return internalClient.delete(params); } diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts index d5aa389cea3357..52efc2b50305b9 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts @@ -19,7 +19,7 @@ export async function getExistingEnvironmentsForService({ serviceName: string | undefined; setup: Setup; }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; const bool = serviceName ? { filter: [{ term: { [SERVICE_NAME]: serviceName } }] } @@ -42,7 +42,7 @@ export async function getExistingEnvironmentsForService({ } }; - const resp = await client.search(params); + const resp = await internalClient.search(params); const buckets = idx(resp.aggregations, _ => _.environments.buckets) || []; return buckets.map(bucket => bucket.key as string); } diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts index 283f30b51441d3..dd4d019ef7263b 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts @@ -12,13 +12,13 @@ export type AgentConfigurationListAPIResponse = PromiseReturnType< typeof listConfigurations >; export async function listConfigurations({ setup }: { setup: Setup }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; const params = { index: indices['apm_oss.apmAgentConfigurationIndex'] }; - const resp = await client.search(params); + const resp = await internalClient.search(params); return resp.hits.hits.map(item => ({ id: item._id, ...item._source diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts index e5349edb67f308..b7b9c21172140a 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts @@ -16,7 +16,7 @@ export async function markAppliedByAgent({ body: AgentConfiguration; setup: Setup; }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; const params = { index: indices['apm_oss.apmAgentConfigurationIndex'], @@ -27,5 +27,5 @@ export async function markAppliedByAgent({ } }; - return client.index(params); + return internalClient.index(params); } diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.test.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.test.ts index 400bd0207771af..dcf7329b229d85 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.test.ts @@ -16,6 +16,7 @@ describe('search configurations', () => { setup: ({ config: { get: () => '' }, client: { search: async () => searchMocks }, + internalClient: { search: async () => searchMocks }, indices: { apm_oss: { sourcemapIndices: 'myIndex', @@ -41,6 +42,7 @@ describe('search configurations', () => { setup: ({ config: { get: () => '' }, client: { search: async () => searchMocks }, + internalClient: { search: async () => searchMocks }, indices: { apm_oss: { sourcemapIndices: 'myIndex', diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts index 35d76d745cf4f1..969bbc542f8a6e 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts @@ -20,7 +20,7 @@ export async function searchConfigurations({ environment?: string; setup: Setup; }) { - const { client, indices } = setup; + const { internalClient, indices } = setup; // sorting order // 1. exact match: service.name AND service.environment (eg. opbeans-node / production) @@ -49,7 +49,9 @@ export async function searchConfigurations({ } }; - const resp = await client.search(params); + const resp = await internalClient.search( + params + ); const { hits } = resp.hits; const exactMatch = hits.find( diff --git a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts index 99553690359cf5..ca10183bb259e4 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts @@ -13,6 +13,9 @@ function getSetup() { client: { search: jest.fn() } as any, + internalClient: { + search: jest.fn() + } as any, config: { get: jest.fn((key: string) => { switch (key) { diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts index 67816d67a29a2a..2648851789c662 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts @@ -30,6 +30,7 @@ describe('getTransactionBreakdown', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true @@ -54,6 +55,7 @@ describe('getTransactionBreakdown', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true @@ -95,6 +97,7 @@ describe('getTransactionBreakdown', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true @@ -135,6 +138,7 @@ describe('getTransactionBreakdown', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true @@ -159,6 +163,7 @@ describe('getTransactionBreakdown', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts index cddc66e52cf701..3b9e80c901fe92 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts @@ -26,6 +26,7 @@ describe('getAnomalySeries', () => { start: 0, end: 500000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts index 5056a100de3ce6..0345b0815679f6 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts @@ -21,6 +21,7 @@ describe('timeseriesFetcher', () => { start: 1528113600000, end: 1528977600000, client: { search: clientSpy } as any, + internalClient: { search: clientSpy } as any, config: { get: () => 'myIndex' as any, has: () => true diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts index 98eae3196eaacb..18fe547a34cf01 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts @@ -38,9 +38,17 @@ describe('createApi', () => { }, handler: async () => null })) + .add(() => ({ + path: '/baz', + method: 'PUT', + options: { + tags: ['access:apm', 'access:apm_write'] + }, + handler: async () => null + })) .init(coreMock, legacySetupMock); - expect(legacySetupMock.server.route).toHaveBeenCalledTimes(2); + expect(legacySetupMock.server.route).toHaveBeenCalledTimes(3); const firstRoute = legacySetupMock.server.route.mock.calls[0][0]; @@ -63,6 +71,17 @@ describe('createApi', () => { path: '/bar', handler: expect.any(Function) }); + + const thirdRoute = legacySetupMock.server.route.mock.calls[2][0]; + + expect(thirdRoute).toEqual({ + method: 'PUT', + options: { + tags: ['access:apm', 'access:apm_write'] + }, + path: '/baz', + handler: expect.any(Function) + }); }); describe('when validating', () => { diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts index eae4fd4988debd..2ce27fbc5e5e49 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts @@ -33,12 +33,11 @@ export function createApi() { init(core: CoreSetup, __LEGACY: LegacySetup) { const { server } = __LEGACY; factoryFns.forEach(fn => { - const { params = {}, ...route } = fn(core, __LEGACY) as Route< - string, - HttpMethod, - Params, - any - >; + const { + params = {}, + options = { tags: ['access:apm'] }, + ...route + } = fn(core, __LEGACY) as Route; const bodyRt = params.body; const fallbackBodyRt = bodyRt || t.null; @@ -55,9 +54,7 @@ export function createApi() { server.route( merge( { - options: { - tags: ['access:apm'] - }, + options, method: 'GET' }, route, diff --git a/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts index d25ad949d6ddef..2867cef28d952b 100644 --- a/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts @@ -31,6 +31,9 @@ export const agentConfigurationRoute = createRoute(core => ({ export const deleteAgentConfigurationRoute = createRoute(() => ({ method: 'DELETE', path: '/api/apm/settings/agent-configuration/{configurationId}', + options: { + tags: ['access:apm', 'access:apm_write'] + }, params: { path: t.type({ configurationId: t.string @@ -108,6 +111,9 @@ export const createAgentConfigurationRoute = createRoute(() => ({ params: { body: agentPayloadRt }, + options: { + tags: ['access:apm', 'access:apm_write'] + }, handler: async (req, { body }) => { const setup = await setupRequest(req); return await createOrUpdateConfiguration({ configuration: body, setup }); @@ -117,6 +123,9 @@ export const createAgentConfigurationRoute = createRoute(() => ({ export const updateAgentConfigurationRoute = createRoute(() => ({ method: 'PUT', path: '/api/apm/settings/agent-configuration/{configurationId}', + options: { + tags: ['access:apm', 'access:apm_write'] + }, params: { path: t.type({ configurationId: t.string diff --git a/x-pack/legacy/plugins/apm/server/routes/typings.ts b/x-pack/legacy/plugins/apm/server/routes/typings.ts index 8ba8c067fb961a..cf1a6cf7694523 100644 --- a/x-pack/legacy/plugins/apm/server/routes/typings.ts +++ b/x-pack/legacy/plugins/apm/server/routes/typings.ts @@ -34,6 +34,9 @@ export interface Route< path: TPath; method?: TMethod; params?: TParams; + options?: { + tags: Array<'access:apm' | 'access:apm_write'>; + }; handler: ( req: Request, params: DecodeParams, From 4c8afa76d337af91ae2cbfc6456fc44bb8341777 Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Wed, 13 Nov 2019 17:28:21 +0200 Subject: [PATCH 08/59] Move temporary types in data plugin to common/types. (#50280) * Move temporary ui imported types in data plugin to common/types. Remove unnecessary mocks. * Updated dashboard, discover and visualize mappings - type removal * Revert "Updated dashboard, discover and visualize mappings - type removal" This reverts commit 5e931ce62a070eb9d4ea254808e75cc3fd47833d. --- src/plugins/data/common/es_query/filters/exists_filter.ts | 2 +- .../data/common/es_query/filters/phrase_filter.test.ts | 2 +- src/plugins/data/common/es_query/filters/phrase_filter.ts | 2 +- src/plugins/data/common/es_query/filters/phrases_filter.ts | 2 +- .../common/es_query/filters/query_string_filter.test.ts | 2 +- .../data/common/es_query/filters/query_string_filter.ts | 2 +- .../data/common/es_query/filters/range_filter.test.ts | 2 +- src/plugins/data/common/es_query/filters/range_filter.ts | 2 +- src/plugins/data/common/es_query/filters/types.ts | 6 ------ src/plugins/data/common/types.ts | 1 + src/plugins/data/public/autocomplete_provider/types.ts | 2 +- .../data/public/query/persisted_log/persisted_log.test.ts | 6 ------ src/plugins/data/public/suggestions_provider/types.ts | 4 +--- .../public/suggestions_provider/value_suggestions.test.ts | 1 - .../data/public/suggestions_provider/value_suggestions.ts | 3 ++- 15 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/plugins/data/common/es_query/filters/exists_filter.ts b/src/plugins/data/common/es_query/filters/exists_filter.ts index 9125048e5f6cd0..1a404ca4151172 100644 --- a/src/plugins/data/common/es_query/filters/exists_filter.ts +++ b/src/plugins/data/common/es_query/filters/exists_filter.ts @@ -18,7 +18,7 @@ */ import { Filter, FilterMeta } from './meta_filter'; -import { IndexPattern, Field } from './types'; +import { IndexPattern, Field } from '../../types'; export type ExistsFilterMeta = FilterMeta; diff --git a/src/plugins/data/common/es_query/filters/phrase_filter.test.ts b/src/plugins/data/common/es_query/filters/phrase_filter.test.ts index ec13e28c583d18..250ec792fbb573 100644 --- a/src/plugins/data/common/es_query/filters/phrase_filter.test.ts +++ b/src/plugins/data/common/es_query/filters/phrase_filter.test.ts @@ -18,7 +18,7 @@ */ import { buildInlineScriptForPhraseFilter, buildPhraseFilter } from './phrase_filter'; -import { IndexPattern } from './types'; +import { IndexPattern } from '../../types'; import { getField } from '../__tests__/fields_mock'; describe('Phrase filter builder', () => { diff --git a/src/plugins/data/common/es_query/filters/phrase_filter.ts b/src/plugins/data/common/es_query/filters/phrase_filter.ts index 15c5c9d4ad2e6d..35110c924fe611 100644 --- a/src/plugins/data/common/es_query/filters/phrase_filter.ts +++ b/src/plugins/data/common/es_query/filters/phrase_filter.ts @@ -19,7 +19,7 @@ import { get, isPlainObject } from 'lodash'; import { Filter, FilterMeta } from './meta_filter'; -import { IndexPattern, Field } from './types'; +import { IndexPattern, Field } from '../../types'; export type PhraseFilterMeta = FilterMeta & { params?: { diff --git a/src/plugins/data/common/es_query/filters/phrases_filter.ts b/src/plugins/data/common/es_query/filters/phrases_filter.ts index e4606695c0f6a5..e207a3ff5961be 100644 --- a/src/plugins/data/common/es_query/filters/phrases_filter.ts +++ b/src/plugins/data/common/es_query/filters/phrases_filter.ts @@ -18,7 +18,7 @@ */ import { Filter, FilterMeta } from './meta_filter'; -import { Field, IndexPattern } from './types'; +import { Field, IndexPattern } from '../../types'; import { getPhraseScript } from './phrase_filter'; export type PhrasesFilterMeta = FilterMeta & { diff --git a/src/plugins/data/common/es_query/filters/query_string_filter.test.ts b/src/plugins/data/common/es_query/filters/query_string_filter.test.ts index 839e4f6359257e..5a580db0c57b82 100644 --- a/src/plugins/data/common/es_query/filters/query_string_filter.test.ts +++ b/src/plugins/data/common/es_query/filters/query_string_filter.test.ts @@ -18,7 +18,7 @@ */ import { buildQueryFilter } from './query_string_filter'; -import { IndexPattern } from './types'; +import { IndexPattern } from '../../types'; describe('Phrase filter builder', () => { let indexPattern: IndexPattern; diff --git a/src/plugins/data/common/es_query/filters/query_string_filter.ts b/src/plugins/data/common/es_query/filters/query_string_filter.ts index 901dc724aa4e49..d2374162b195f4 100644 --- a/src/plugins/data/common/es_query/filters/query_string_filter.ts +++ b/src/plugins/data/common/es_query/filters/query_string_filter.ts @@ -18,7 +18,7 @@ */ import { Filter, FilterMeta } from './meta_filter'; -import { IndexPattern } from './types'; +import { IndexPattern } from '../../types'; export type QueryStringFilterMeta = FilterMeta; diff --git a/src/plugins/data/common/es_query/filters/range_filter.test.ts b/src/plugins/data/common/es_query/filters/range_filter.test.ts index 9008dc2a672944..017bb8e9cb7c5b 100644 --- a/src/plugins/data/common/es_query/filters/range_filter.test.ts +++ b/src/plugins/data/common/es_query/filters/range_filter.test.ts @@ -19,7 +19,7 @@ import { each } from 'lodash'; import { buildRangeFilter, RangeFilter } from './range_filter'; -import { IndexPattern, Field } from './types'; +import { IndexPattern, Field } from '../../types'; import { getField } from '../__tests__/fields_mock'; describe('Range filter builder', () => { diff --git a/src/plugins/data/common/es_query/filters/range_filter.ts b/src/plugins/data/common/es_query/filters/range_filter.ts index d7931f191e52b1..c2513a9dc0c5e1 100644 --- a/src/plugins/data/common/es_query/filters/range_filter.ts +++ b/src/plugins/data/common/es_query/filters/range_filter.ts @@ -18,7 +18,7 @@ */ import { map, reduce, mapValues, get, keys, pick } from 'lodash'; import { Filter, FilterMeta } from './meta_filter'; -import { Field, IndexPattern } from './types'; +import { Field, IndexPattern } from '../../types'; const OPERANDS_IN_RANGE = 2; diff --git a/src/plugins/data/common/es_query/filters/types.ts b/src/plugins/data/common/es_query/filters/types.ts index 28147350619995..a242df4811c059 100644 --- a/src/plugins/data/common/es_query/filters/types.ts +++ b/src/plugins/data/common/es_query/filters/types.ts @@ -49,9 +49,3 @@ export enum FILTERS { GEO_BOUNDING_BOX = 'geo_bounding_box', GEO_POLYGON = 'geo_polygon', } - -// We can't import the real types from the data plugin, so need to either duplicate -// them here or figure out another solution, perhaps housing them in this package -// will be replaces after Fieds / IndexPattern will be moved into new platform -export type Field = any; -export type IndexPattern = any; diff --git a/src/plugins/data/common/types.ts b/src/plugins/data/common/types.ts index eae7c26e3ab3f9..ec8d8b006317fd 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -27,3 +27,4 @@ export * from './kbn_field_types/types'; // will be replaces after Fieds / IndexPattern will be moved into new platform export type Field = any; export type IndexPattern = any; +export type StaticIndexPattern = any; diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete_provider/types.ts index 1f2d8f914dde3e..d838e54e9ead49 100644 --- a/src/plugins/data/public/autocomplete_provider/types.ts +++ b/src/plugins/data/public/autocomplete_provider/types.ts @@ -17,8 +17,8 @@ * under the License. */ -import { StaticIndexPattern, Field } from 'ui/index_patterns'; import { AutocompleteProviderRegister } from '.'; +import { Field, StaticIndexPattern } from '..'; export type AutocompletePublicPluginSetup = Pick< AutocompleteProviderRegister, diff --git a/src/plugins/data/public/query/persisted_log/persisted_log.test.ts b/src/plugins/data/public/query/persisted_log/persisted_log.test.ts index e0bc8f2c3525f5..87c1ec29c1aee1 100644 --- a/src/plugins/data/public/query/persisted_log/persisted_log.test.ts +++ b/src/plugins/data/public/query/persisted_log/persisted_log.test.ts @@ -36,12 +36,6 @@ const createMockStorage = () => ({ clear: jest.fn(), }); -jest.mock('ui/chrome', () => { - return { - getBasePath: () => `/some/base/path`, - }; -}); - const historyName = 'testHistory'; const historyLimit = 10; const payload = [ diff --git a/src/plugins/data/public/suggestions_provider/types.ts b/src/plugins/data/public/suggestions_provider/types.ts index eac380dde6a62f..988b5fcd43fa89 100644 --- a/src/plugins/data/public/suggestions_provider/types.ts +++ b/src/plugins/data/public/suggestions_provider/types.ts @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - -// Should be import { Field } from './index_patterns'; -export type Field = any; +import { Field } from '..'; export type IGetSuggestions = (index: string, field: Field, query: string, boolFilter?: any) => any; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index de2147cd752671..7dc8ff0fe133d1 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -19,7 +19,6 @@ // TODO: remove when index patterns are moved here. jest.mock('ui/new_platform'); -jest.mock('ui/index_patterns'); import { stubIndexPattern, stubFields } from '../stubs'; import { getSuggestionsProvider } from './value_suggestions'; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts index 03eaa5d9594d27..c769f64025b0ed 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts @@ -20,7 +20,8 @@ import { memoize } from 'lodash'; import { UiSettingsClientContract, HttpServiceBase } from 'src/core/public'; -import { IGetSuggestions, Field } from './types'; +import { IGetSuggestions } from './types'; +import { Field } from '..'; export function getSuggestionsProvider( uiSettings: UiSettingsClientContract, From a50dbefb62edf0be6b98110023afc32b04c06a7f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 13 Nov 2019 07:48:34 -0800 Subject: [PATCH 09/59] [Newsfeed] UI plugin for Kibana (#49579) * Added base folder structure for Newsfeed plugin * Added base folders for lib and component * Added newsfeed button to navigation controls on the right side * add getApi() to return api data observable (#49581) * Added flyout base body and provided EuiHeaderAlert component inside the newsfeed plugin * Moved newsfeed plugin to OSS and added for the styles purpose new folder for legacy plugin 'newsfeed' with the same id to support this * Added subscribe on fetch newsfeed change * Add NewsfeedApiDriver class (#49710) * add NewsfeedApiDriver class * fix xpack prefix * add corner case handling * Added data binding to the ui * added EuiHeaderAlert style overrides (#49739) * Fixed due to comments on PR * add missing fields to NewsfeedItem and FetchResult * fix templating of service url * gracefully handle temporary request failure * Mapped missing fields for data and badge * Fixed typos issues * integrate i18n.getLocale() * allow service url root to be changed in dev mode * replace a lot of consts with config * fix flyout height (#49809) * Add "error" field to FetchResult: Error | null * simplify fetch error handling * Do not store hash for items that are filtered out * add expireOn in case it is useful to UI * always use staging url for dev config * unit test for newsfeed api driver * simplify modelItems * Fixed eslint errors * Fixed label translations * Add unit test for concatenating the stored hashes with the new * add newsfeed to i18n.json * Fixed expression error * --wip-- [skip ci] * fix parse error * fix test * test(newsfeed): Added testing endpoint which simulates the Elastic Newsfeed for consumption in functional tests * add tests for getApi() * add tests for getApi * Added no news page * fix fetch not happening after page refresh with sessionStorage primed * test(newsfeed): Added testing endpoint which simulates the Elastic Newsfeed for consumption in functional tests * Added loading screen * Small fixes due to comments * Fixed issue with stop fetching news on error catch * test(newsfeed): Configure FTS to point newsfeed to the simulated newsfeed endpoit * Fixed browser error message: Invariant Violation: [React Intl] Could not find required `intl` object. needs to exist in the component ancestry. * Fixed typo issue in label name * polish the code changes * Add simple jest/enzyme tests for the components * honor utc format * Filter pre-published items * Fall back to en * retry tests * comment clarfication * Setup newsfeed service fixture from test/common/config * Added base functional tests for newsfeed functionality * valid urlroot is for prod * add documentation for the supported enabled setting * more urlRoot * --wip-- [skip ci] * add the before for fn * add ui_capabilties test * update jest snapshot * Fixed failing test * finish newsfeed error functional test * include ui_capability config * error case testing in ci group 6 * refactor(newsfeed): moved newsfeed api call so that it is done before its use * code polish * enabled newsfeed_err test in CI --- .i18nrc.json | 1 + docs/setup/settings.asciidoc | 4 + scripts/functional_tests.js | 1 + src/legacy/core_plugins/newsfeed/constants.ts | 23 + src/legacy/core_plugins/newsfeed/index.ts | 71 ++ src/legacy/core_plugins/newsfeed/package.json | 4 + .../core_plugins/newsfeed/public/index.scss | 3 + .../components/header_alert/_index.scss | 27 + .../components/header_alert/header_alert.tsx | 76 ++ src/plugins/newsfeed/constants.ts | 22 + src/plugins/newsfeed/kibana.json | 6 + .../__snapshots__/empty_news.test.tsx.snap | 27 + .../__snapshots__/loading_news.test.tsx.snap | 20 + .../public/components/empty_news.test.tsx | 32 + .../newsfeed/public/components/empty_news.tsx | 44 ++ .../public/components/flyout_list.tsx | 110 +++ .../public/components/loading_news.test.tsx | 32 + .../public/components/loading_news.tsx | 39 + .../components/newsfeed_header_nav_button.tsx | 82 ++ src/plugins/newsfeed/public/index.ts | 25 + src/plugins/newsfeed/public/lib/api.test.ts | 701 ++++++++++++++++++ src/plugins/newsfeed/public/lib/api.ts | 194 +++++ src/plugins/newsfeed/public/plugin.tsx | 76 ++ src/plugins/newsfeed/types.ts | 63 ++ tasks/function_test_groups.js | 1 + test/common/config.js | 5 + .../common/fixtures/plugins/newsfeed/index.ts | 33 + .../plugins/newsfeed/newsfeed_simulation.ts | 114 +++ .../fixtures/plugins/newsfeed/package.json | 7 + test/functional/apps/home/_newsfeed.ts | 62 ++ test/functional/apps/home/index.js | 1 + test/functional/page_objects/index.ts | 2 + test/functional/page_objects/newsfeed_page.ts | 73 ++ test/functional/services/global_nav.ts | 4 + test/ui_capabilities/newsfeed_err/config.ts | 45 ++ test/ui_capabilities/newsfeed_err/test.ts | 60 ++ 36 files changed, 2090 insertions(+) create mode 100644 src/legacy/core_plugins/newsfeed/constants.ts create mode 100644 src/legacy/core_plugins/newsfeed/index.ts create mode 100644 src/legacy/core_plugins/newsfeed/package.json create mode 100644 src/legacy/core_plugins/newsfeed/public/index.scss create mode 100644 src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/_index.scss create mode 100644 src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert.tsx create mode 100644 src/plugins/newsfeed/constants.ts create mode 100644 src/plugins/newsfeed/kibana.json create mode 100644 src/plugins/newsfeed/public/components/__snapshots__/empty_news.test.tsx.snap create mode 100644 src/plugins/newsfeed/public/components/__snapshots__/loading_news.test.tsx.snap create mode 100644 src/plugins/newsfeed/public/components/empty_news.test.tsx create mode 100644 src/plugins/newsfeed/public/components/empty_news.tsx create mode 100644 src/plugins/newsfeed/public/components/flyout_list.tsx create mode 100644 src/plugins/newsfeed/public/components/loading_news.test.tsx create mode 100644 src/plugins/newsfeed/public/components/loading_news.tsx create mode 100644 src/plugins/newsfeed/public/components/newsfeed_header_nav_button.tsx create mode 100644 src/plugins/newsfeed/public/index.ts create mode 100644 src/plugins/newsfeed/public/lib/api.test.ts create mode 100644 src/plugins/newsfeed/public/lib/api.ts create mode 100644 src/plugins/newsfeed/public/plugin.tsx create mode 100644 src/plugins/newsfeed/types.ts create mode 100644 test/common/fixtures/plugins/newsfeed/index.ts create mode 100644 test/common/fixtures/plugins/newsfeed/newsfeed_simulation.ts create mode 100644 test/common/fixtures/plugins/newsfeed/package.json create mode 100644 test/functional/apps/home/_newsfeed.ts create mode 100644 test/functional/page_objects/newsfeed_page.ts create mode 100644 test/ui_capabilities/newsfeed_err/config.ts create mode 100644 test/ui_capabilities/newsfeed_err/test.ts diff --git a/.i18nrc.json b/.i18nrc.json index 01065201b9d641..51727ce014f58f 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -20,6 +20,7 @@ "kibana_react": "src/legacy/core_plugins/kibana_react", "kibana-react": "src/plugins/kibana_react", "navigation": "src/legacy/core_plugins/navigation", + "newsfeed": "src/plugins/newsfeed", "regionMap": "src/legacy/core_plugins/region_map", "server": "src/legacy/server", "statusPage": "src/legacy/core_plugins/status_page", diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 6e7f939a1d2abd..0f17ffcf26930e 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -240,6 +240,10 @@ Kibana reads this url from an external metadata service, but users can still override this parameter to use their own Tile Map Service. For example: `"https://tiles.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana"` +`newsfeed.enabled:` :: *Default: `true`* Controls whether to enable the newsfeed +system for the Kibana UI notification center. Set to `false` to disable the +newsfeed system. + `path.data:`:: *Default: `data`* The path where Kibana stores persistent data not saved in Elasticsearch. diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js index 472545b203a9b0..9f4e678c6adf5a 100644 --- a/scripts/functional_tests.js +++ b/scripts/functional_tests.js @@ -23,4 +23,5 @@ require('@kbn/test').runTestsCli([ require.resolve('../test/api_integration/config.js'), require.resolve('../test/plugin_functional/config.js'), require.resolve('../test/interpreter_functional/config.js'), + require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'), ]); diff --git a/src/legacy/core_plugins/newsfeed/constants.ts b/src/legacy/core_plugins/newsfeed/constants.ts new file mode 100644 index 00000000000000..55a0c51c2ac653 --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/constants.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const PLUGIN_ID = 'newsfeed'; +export const DEFAULT_SERVICE_URLROOT = 'https://feeds.elastic.co'; +export const DEV_SERVICE_URLROOT = 'https://feeds-staging.elastic.co'; +export const DEFAULT_SERVICE_PATH = '/kibana/v{VERSION}.json'; diff --git a/src/legacy/core_plugins/newsfeed/index.ts b/src/legacy/core_plugins/newsfeed/index.ts new file mode 100644 index 00000000000000..cf8852be09a1ef --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/index.ts @@ -0,0 +1,71 @@ +/* + * 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 { resolve } from 'path'; +import { LegacyPluginApi, LegacyPluginSpec, ArrayOrItem } from 'src/legacy/plugin_discovery/types'; +import { Legacy } from 'kibana'; +import { NewsfeedPluginInjectedConfig } from '../../../plugins/newsfeed/types'; +import { + PLUGIN_ID, + DEFAULT_SERVICE_URLROOT, + DEV_SERVICE_URLROOT, + DEFAULT_SERVICE_PATH, +} from './constants'; + +// eslint-disable-next-line import/no-default-export +export default function(kibana: LegacyPluginApi): ArrayOrItem { + const pluginSpec: Legacy.PluginSpecOptions = { + id: PLUGIN_ID, + config(Joi: any) { + // NewsfeedPluginInjectedConfig in Joi form + return Joi.object({ + enabled: Joi.boolean().default(true), + service: Joi.object({ + pathTemplate: Joi.string().default(DEFAULT_SERVICE_PATH), + urlRoot: Joi.when('$prod', { + is: true, + then: Joi.string().default(DEFAULT_SERVICE_URLROOT), + otherwise: Joi.string().default(DEV_SERVICE_URLROOT), + }), + }).default(), + defaultLanguage: Joi.string().default('en'), + mainInterval: Joi.number().default(120 * 1000), // (2min) How often to retry failed fetches, and/or check if newsfeed items need to be refreshed from remote + fetchInterval: Joi.number().default(86400 * 1000), // (1day) How often to fetch remote and reset the last fetched time + }).default(); + }, + uiExports: { + styleSheetPaths: resolve(__dirname, 'public/index.scss'), + injectDefaultVars(server): NewsfeedPluginInjectedConfig { + const config = server.config(); + return { + newsfeed: { + service: { + pathTemplate: config.get('newsfeed.service.pathTemplate') as string, + urlRoot: config.get('newsfeed.service.urlRoot') as string, + }, + defaultLanguage: config.get('newsfeed.defaultLanguage') as string, + mainInterval: config.get('newsfeed.mainInterval') as number, + fetchInterval: config.get('newsfeed.fetchInterval') as number, + }, + }; + }, + }, + }; + return new kibana.Plugin(pluginSpec); +} diff --git a/src/legacy/core_plugins/newsfeed/package.json b/src/legacy/core_plugins/newsfeed/package.json new file mode 100644 index 00000000000000..d4d753f32b0f96 --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/package.json @@ -0,0 +1,4 @@ +{ + "name": "newsfeed", + "version": "kibana" +} diff --git a/src/legacy/core_plugins/newsfeed/public/index.scss b/src/legacy/core_plugins/newsfeed/public/index.scss new file mode 100644 index 00000000000000..a77132379041cb --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/public/index.scss @@ -0,0 +1,3 @@ +@import 'src/legacy/ui/public/styles/styling_constants'; + +@import './np_ready/components/header_alert/_index'; diff --git a/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/_index.scss b/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/_index.scss new file mode 100644 index 00000000000000..e25dbd25daaf5b --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/_index.scss @@ -0,0 +1,27 @@ +@import '@elastic/eui/src/components/header/variables'; + +.kbnNews__flyout { + top: $euiHeaderChildSize + 1px; + height: calc(100% - #{$euiHeaderChildSize}); +} + +.kbnNewsFeed__headerAlert.euiHeaderAlert { + margin-bottom: $euiSizeL; + padding: 0 $euiSizeS $euiSizeL; + border-bottom: $euiBorderThin; + border-top: none; + + .euiHeaderAlert__title { + @include euiTitle('xs'); + margin-bottom: $euiSizeS; + } + + .euiHeaderAlert__text { + @include euiFontSizeS; + margin-bottom: $euiSize; + } + + .euiHeaderAlert__action { + @include euiFontSizeS; + } +} diff --git a/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert.tsx b/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert.tsx new file mode 100644 index 00000000000000..c3c3e4144fca8a --- /dev/null +++ b/src/legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert.tsx @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import { EuiFlexGroup, EuiFlexItem, EuiI18n } from '@elastic/eui'; + +interface IEuiHeaderAlertProps { + action: JSX.Element; + className?: string; + date: string; + text: string; + title: string; + badge?: JSX.Element; + rest?: string[]; +} + +export const EuiHeaderAlert = ({ + action, + className, + date, + text, + title, + badge, + ...rest +}: IEuiHeaderAlertProps) => { + const classes = classNames('euiHeaderAlert', 'kbnNewsFeed__headerAlert', className); + + const badgeContent = badge || null; + + return ( + + {(dismiss: any) => ( +
+ + +
{date}
+
+ {badgeContent} +
+ +
{title}
+
{text}
+
{action}
+
+ )} +
+ ); +}; + +EuiHeaderAlert.propTypes = { + action: PropTypes.node, + className: PropTypes.string, + date: PropTypes.node.isRequired, + text: PropTypes.node, + title: PropTypes.node.isRequired, + badge: PropTypes.node, +}; diff --git a/src/plugins/newsfeed/constants.ts b/src/plugins/newsfeed/constants.ts new file mode 100644 index 00000000000000..ddcbbb6cb1dbe6 --- /dev/null +++ b/src/plugins/newsfeed/constants.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const NEWSFEED_FALLBACK_LANGUAGE = 'en'; +export const NEWSFEED_LAST_FETCH_STORAGE_KEY = 'newsfeed.lastfetchtime'; +export const NEWSFEED_HASH_SET_STORAGE_KEY = 'newsfeed.hashes'; diff --git a/src/plugins/newsfeed/kibana.json b/src/plugins/newsfeed/kibana.json new file mode 100644 index 00000000000000..9d49b42424a06c --- /dev/null +++ b/src/plugins/newsfeed/kibana.json @@ -0,0 +1,6 @@ +{ + "id": "newsfeed", + "version": "kibana", + "server": false, + "ui": true +} diff --git a/src/plugins/newsfeed/public/components/__snapshots__/empty_news.test.tsx.snap b/src/plugins/newsfeed/public/components/__snapshots__/empty_news.test.tsx.snap new file mode 100644 index 00000000000000..8764b7664d4496 --- /dev/null +++ b/src/plugins/newsfeed/public/components/__snapshots__/empty_news.test.tsx.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`empty_news rendering renders the default Empty News 1`] = ` + + +

+ } + data-test-subj="emptyNewsfeed" + iconType="documents" + title={ +

+ +

+ } + titleSize="s" +/> +`; diff --git a/src/plugins/newsfeed/public/components/__snapshots__/loading_news.test.tsx.snap b/src/plugins/newsfeed/public/components/__snapshots__/loading_news.test.tsx.snap new file mode 100644 index 00000000000000..2e88b0053535e6 --- /dev/null +++ b/src/plugins/newsfeed/public/components/__snapshots__/loading_news.test.tsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`news_loading rendering renders the default News Loading 1`] = ` + + +

+ } + title={ + + } +/> +`; diff --git a/src/plugins/newsfeed/public/components/empty_news.test.tsx b/src/plugins/newsfeed/public/components/empty_news.test.tsx new file mode 100644 index 00000000000000..33702df00a583a --- /dev/null +++ b/src/plugins/newsfeed/public/components/empty_news.test.tsx @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as React from 'react'; +import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; +import { NewsEmptyPrompt } from './empty_news'; + +describe('empty_news', () => { + describe('rendering', () => { + it('renders the default Empty News', () => { + const wrapper = shallow(); + expect(toJson(wrapper)).toMatchSnapshot(); + }); + }); +}); diff --git a/src/plugins/newsfeed/public/components/empty_news.tsx b/src/plugins/newsfeed/public/components/empty_news.tsx new file mode 100644 index 00000000000000..cec18e0bdec433 --- /dev/null +++ b/src/plugins/newsfeed/public/components/empty_news.tsx @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied.  See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +export const NewsEmptyPrompt = () => { + return ( + + + + } + body={ +

+ +

+ } + /> + ); +}; diff --git a/src/plugins/newsfeed/public/components/flyout_list.tsx b/src/plugins/newsfeed/public/components/flyout_list.tsx new file mode 100644 index 00000000000000..8a99abe18a75f3 --- /dev/null +++ b/src/plugins/newsfeed/public/components/flyout_list.tsx @@ -0,0 +1,110 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied.  See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback, useContext } from 'react'; +import { + EuiIcon, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiLink, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiText, + EuiBadge, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiHeaderAlert } from '../../../../legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert'; +import { NewsfeedContext } from './newsfeed_header_nav_button'; +import { NewsfeedItem } from '../../types'; +import { NewsEmptyPrompt } from './empty_news'; +import { NewsLoadingPrompt } from './loading_news'; + +export const NewsfeedFlyout = () => { + const { newsFetchResult, setFlyoutVisible } = useContext(NewsfeedContext); + const closeFlyout = useCallback(() => setFlyoutVisible(false), [setFlyoutVisible]); + + return ( + + + +

+ +

+
+
+ + {!newsFetchResult ? ( + + ) : newsFetchResult.feedItems.length > 0 ? ( + newsFetchResult.feedItems.map((item: NewsfeedItem) => { + return ( + + {item.linkText} + + + } + date={item.publishOn.format('DD MMMM YYYY')} + badge={{item.badge}} + /> + ); + }) + ) : ( + + )} + + + + + + + + + + {newsFetchResult ? ( + +

+ +

+
+ ) : null} +
+
+
+
+ ); +}; diff --git a/src/plugins/newsfeed/public/components/loading_news.test.tsx b/src/plugins/newsfeed/public/components/loading_news.test.tsx new file mode 100644 index 00000000000000..ca449b8ee879e2 --- /dev/null +++ b/src/plugins/newsfeed/public/components/loading_news.test.tsx @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as React from 'react'; +import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; +import { NewsLoadingPrompt } from './loading_news'; + +describe('news_loading', () => { + describe('rendering', () => { + it('renders the default News Loading', () => { + const wrapper = shallow(); + expect(toJson(wrapper)).toMatchSnapshot(); + }); + }); +}); diff --git a/src/plugins/newsfeed/public/components/loading_news.tsx b/src/plugins/newsfeed/public/components/loading_news.tsx new file mode 100644 index 00000000000000..fcbc7970377d4e --- /dev/null +++ b/src/plugins/newsfeed/public/components/loading_news.tsx @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied.  See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiEmptyPrompt } from '@elastic/eui'; +import { EuiLoadingKibana } from '@elastic/eui'; + +export const NewsLoadingPrompt = () => { + return ( + } + body={ +

+ +

+ } + /> + ); +}; diff --git a/src/plugins/newsfeed/public/components/newsfeed_header_nav_button.tsx b/src/plugins/newsfeed/public/components/newsfeed_header_nav_button.tsx new file mode 100644 index 00000000000000..da042f0fce7b6e --- /dev/null +++ b/src/plugins/newsfeed/public/components/newsfeed_header_nav_button.tsx @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied.  See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, Fragment, useEffect } from 'react'; +import * as Rx from 'rxjs'; +import { EuiHeaderSectionItemButton, EuiIcon, EuiNotificationBadge } from '@elastic/eui'; +import { NewsfeedFlyout } from './flyout_list'; +import { FetchResult } from '../../types'; + +export interface INewsfeedContext { + setFlyoutVisible: React.Dispatch>; + newsFetchResult: FetchResult | void | null; +} +export const NewsfeedContext = React.createContext({} as INewsfeedContext); + +export type NewsfeedApiFetchResult = Rx.Observable; + +export interface Props { + apiFetchResult: NewsfeedApiFetchResult; +} + +export const NewsfeedNavButton = ({ apiFetchResult }: Props) => { + const [showBadge, setShowBadge] = useState(false); + const [flyoutVisible, setFlyoutVisible] = useState(false); + const [newsFetchResult, setNewsFetchResult] = useState(null); + + useEffect(() => { + function handleStatusChange(fetchResult: FetchResult | void | null) { + if (fetchResult) { + setShowBadge(fetchResult.hasNew); + } + setNewsFetchResult(fetchResult); + } + + const subscription = apiFetchResult.subscribe(res => handleStatusChange(res)); + return () => subscription.unsubscribe(); + }, [apiFetchResult]); + + function showFlyout() { + setShowBadge(false); + setFlyoutVisible(!flyoutVisible); + } + + return ( + + + + + {showBadge ? ( + + ▪ + + ) : null} + + {flyoutVisible ? : null} + + + ); +}; diff --git a/src/plugins/newsfeed/public/index.ts b/src/plugins/newsfeed/public/index.ts new file mode 100644 index 00000000000000..1217de60d9638c --- /dev/null +++ b/src/plugins/newsfeed/public/index.ts @@ -0,0 +1,25 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginInitializerContext } from 'src/core/public'; +import { NewsfeedPublicPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new NewsfeedPublicPlugin(initializerContext); +} diff --git a/src/plugins/newsfeed/public/lib/api.test.ts b/src/plugins/newsfeed/public/lib/api.test.ts new file mode 100644 index 00000000000000..b9707ff91b9365 --- /dev/null +++ b/src/plugins/newsfeed/public/lib/api.test.ts @@ -0,0 +1,701 @@ +/* + * 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 { take, tap, toArray } from 'rxjs/operators'; +import { interval, race } from 'rxjs'; +import sinon, { stub } from 'sinon'; +import moment from 'moment'; +import { HttpServiceBase } from 'src/core/public'; +import { NEWSFEED_HASH_SET_STORAGE_KEY, NEWSFEED_LAST_FETCH_STORAGE_KEY } from '../../constants'; +import { ApiItem, NewsfeedItem, NewsfeedPluginInjectedConfig } from '../../types'; +import { NewsfeedApiDriver, getApi } from './api'; + +const localStorageGet = sinon.stub(); +const sessionStoragetGet = sinon.stub(); + +Object.defineProperty(window, 'localStorage', { + value: { + getItem: localStorageGet, + setItem: stub(), + }, + writable: true, +}); +Object.defineProperty(window, 'sessionStorage', { + value: { + getItem: sessionStoragetGet, + setItem: stub(), + }, + writable: true, +}); + +describe('NewsfeedApiDriver', () => { + const kibanaVersion = 'test_version'; + const userLanguage = 'en'; + const fetchInterval = 2000; + const getDriver = () => new NewsfeedApiDriver(kibanaVersion, userLanguage, fetchInterval); + + afterEach(() => { + sinon.reset(); + }); + + describe('shouldFetch', () => { + it('defaults to true', () => { + const driver = getDriver(); + expect(driver.shouldFetch()).toBe(true); + }); + + it('returns true if last fetch time precedes page load time', () => { + sessionStoragetGet.throws('Wrong key passed!'); + sessionStoragetGet.withArgs(NEWSFEED_LAST_FETCH_STORAGE_KEY).returns(322642800000); // 1980-03-23 + const driver = getDriver(); + expect(driver.shouldFetch()).toBe(true); + }); + + it('returns false if last fetch time is recent enough', () => { + sessionStoragetGet.throws('Wrong key passed!'); + sessionStoragetGet.withArgs(NEWSFEED_LAST_FETCH_STORAGE_KEY).returns(3005017200000); // 2065-03-23 + const driver = getDriver(); + expect(driver.shouldFetch()).toBe(false); + }); + }); + + describe('updateHashes', () => { + it('returns previous and current storage', () => { + const driver = getDriver(); + const items: NewsfeedItem[] = [ + { + title: 'Good news, everyone!', + description: 'good item description', + linkText: 'click here', + linkUrl: 'about:blank', + badge: 'test', + publishOn: moment(1572489035150), + expireOn: moment(1572489047858), + hash: 'hash1oneoneoneone', + }, + ]; + expect(driver.updateHashes(items)).toMatchInlineSnapshot(` + Object { + "current": Array [ + "hash1oneoneoneone", + ], + "previous": Array [], + } + `); + }); + + it('concatenates the previous hashes with the current', () => { + localStorageGet.throws('Wrong key passed!'); + localStorageGet.withArgs(NEWSFEED_HASH_SET_STORAGE_KEY).returns('happyness'); + const driver = getDriver(); + const items: NewsfeedItem[] = [ + { + title: 'Better news, everyone!', + description: 'better item description', + linkText: 'click there', + linkUrl: 'about:blank', + badge: 'concatentated', + publishOn: moment(1572489035150), + expireOn: moment(1572489047858), + hash: 'three33hash', + }, + ]; + expect(driver.updateHashes(items)).toMatchInlineSnapshot(` + Object { + "current": Array [ + "happyness", + "three33hash", + ], + "previous": Array [ + "happyness", + ], + } + `); + }); + }); + + it('Validates items for required fields', () => { + const driver = getDriver(); + expect(driver.validateItem({})).toBe(false); + expect( + driver.validateItem({ + title: 'Gadzooks!', + description: 'gadzooks item description', + linkText: 'click here', + linkUrl: 'about:blank', + badge: 'test', + publishOn: moment(1572489035150), + expireOn: moment(1572489047858), + hash: 'hash2twotwotwotwotwo', + }) + ).toBe(true); + expect( + driver.validateItem({ + title: 'Gadzooks!', + description: 'gadzooks item description', + linkText: 'click here', + linkUrl: 'about:blank', + publishOn: moment(1572489035150), + hash: 'hash2twotwotwotwotwo', + }) + ).toBe(true); + expect( + driver.validateItem({ + title: 'Gadzooks!', + description: 'gadzooks item description', + linkText: 'click here', + linkUrl: 'about:blank', + publishOn: moment(1572489035150), + // hash: 'hash2twotwotwotwotwo', // should fail because this is missing + }) + ).toBe(false); + }); + + describe('modelItems', () => { + it('Models empty set with defaults', () => { + const driver = getDriver(); + const apiItems: ApiItem[] = []; + expect(driver.modelItems(apiItems)).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "test_version", + } + `); + }); + + it('Selects default language', () => { + const driver = getDriver(); + const apiItems: ApiItem[] = [ + { + title: { + en: 'speaking English', + es: 'habla Espanol', + }, + description: { + en: 'language test', + es: 'idiomas', + }, + languages: ['en', 'es'], + link_text: { + en: 'click here', + es: 'aqui', + }, + link_url: { + en: 'xyzxyzxyz', + es: 'abcabc', + }, + badge: { + en: 'firefighter', + es: 'bombero', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'abcabc1231123123hash', + }, + ]; + expect(driver.modelItems(apiItems)).toMatchObject({ + error: null, + feedItems: [ + { + badge: 'firefighter', + description: 'language test', + hash: 'abcabc1231', + linkText: 'click here', + linkUrl: 'xyzxyzxyz', + title: 'speaking English', + }, + ], + hasNew: true, + kibanaVersion: 'test_version', + }); + }); + + it("Falls back to English when user language isn't present", () => { + // Set Language to French + const driver = new NewsfeedApiDriver(kibanaVersion, 'fr', fetchInterval); + const apiItems: ApiItem[] = [ + { + title: { + en: 'speaking English', + fr: 'Le Title', + }, + description: { + en: 'not French', + fr: 'Le Description', + }, + languages: ['en', 'fr'], + link_text: { + en: 'click here', + fr: 'Le Link Text', + }, + link_url: { + en: 'xyzxyzxyz', + fr: 'le_url', + }, + badge: { + en: 'firefighter', + fr: 'le_badge', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'frfrfrfr1231123123hash', + }, // fallback: no + { + title: { + en: 'speaking English', + es: 'habla Espanol', + }, + description: { + en: 'not French', + es: 'no Espanol', + }, + languages: ['en', 'es'], + link_text: { + en: 'click here', + es: 'aqui', + }, + link_url: { + en: 'xyzxyzxyz', + es: 'abcabc', + }, + badge: { + en: 'firefighter', + es: 'bombero', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'enenenen1231123123hash', + }, // fallback: yes + ]; + expect(driver.modelItems(apiItems)).toMatchObject({ + error: null, + feedItems: [ + { + badge: 'le_badge', + description: 'Le Description', + hash: 'frfrfrfr12', + linkText: 'Le Link Text', + linkUrl: 'le_url', + title: 'Le Title', + }, + { + badge: 'firefighter', + description: 'not French', + hash: 'enenenen12', + linkText: 'click here', + linkUrl: 'xyzxyzxyz', + title: 'speaking English', + }, + ], + hasNew: true, + kibanaVersion: 'test_version', + }); + }); + + it('Models multiple items into an API FetchResult', () => { + const driver = getDriver(); + const apiItems: ApiItem[] = [ + { + title: { + en: 'guess what', + }, + description: { + en: 'this tests the modelItems function', + }, + link_text: { + en: 'click here', + }, + link_url: { + en: 'about:blank', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'abcabc1231123123hash', + }, + { + title: { + en: 'guess when', + }, + description: { + en: 'this also tests the modelItems function', + }, + link_text: { + en: 'click here', + }, + link_url: { + en: 'about:blank', + }, + badge: { + en: 'hero', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'defdefdef456456456', + }, + ]; + expect(driver.modelItems(apiItems)).toMatchObject({ + error: null, + feedItems: [ + { + badge: null, + description: 'this tests the modelItems function', + hash: 'abcabc1231', + linkText: 'click here', + linkUrl: 'about:blank', + title: 'guess what', + }, + { + badge: 'hero', + description: 'this also tests the modelItems function', + hash: 'defdefdef4', + linkText: 'click here', + linkUrl: 'about:blank', + title: 'guess when', + }, + ], + hasNew: true, + kibanaVersion: 'test_version', + }); + }); + + it('Filters expired', () => { + const driver = getDriver(); + const apiItems: ApiItem[] = [ + { + title: { + en: 'guess what', + }, + description: { + en: 'this tests the modelItems function', + }, + link_text: { + en: 'click here', + }, + link_url: { + en: 'about:blank', + }, + publish_on: new Date('2013-10-31T04:23:47Z'), + expire_on: new Date('2014-10-31T04:23:47Z'), // too old + hash: 'abcabc1231123123hash', + }, + ]; + expect(driver.modelItems(apiItems)).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "test_version", + } + `); + }); + + it('Filters pre-published', () => { + const driver = getDriver(); + const apiItems: ApiItem[] = [ + { + title: { + en: 'guess what', + }, + description: { + en: 'this tests the modelItems function', + }, + link_text: { + en: 'click here', + }, + link_url: { + en: 'about:blank', + }, + publish_on: new Date('2055-10-31T04:23:47Z'), // too new + expire_on: new Date('2056-10-31T04:23:47Z'), + hash: 'abcabc1231123123hash', + }, + ]; + expect(driver.modelItems(apiItems)).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "test_version", + } + `); + }); + }); +}); + +describe('getApi', () => { + const mockHttpGet = jest.fn(); + let httpMock = ({ + fetch: mockHttpGet, + } as unknown) as HttpServiceBase; + const getHttpMockWithItems = (mockApiItems: ApiItem[]) => ( + arg1: string, + arg2: { method: string } + ) => { + if ( + arg1 === 'http://fakenews.co/kibana-test/v6.8.2.json' && + arg2.method && + arg2.method === 'GET' + ) { + return Promise.resolve({ items: mockApiItems }); + } + return Promise.reject('wrong args!'); + }; + let configMock: NewsfeedPluginInjectedConfig; + + afterEach(() => { + jest.resetAllMocks(); + }); + + beforeEach(() => { + configMock = { + newsfeed: { + service: { + urlRoot: 'http://fakenews.co', + pathTemplate: '/kibana-test/v{VERSION}.json', + }, + defaultLanguage: 'en', + mainInterval: 86400000, + fetchInterval: 86400000, + }, + }; + httpMock = ({ + fetch: mockHttpGet, + } as unknown) as HttpServiceBase; + }); + + it('creates a result', done => { + mockHttpGet.mockImplementationOnce(() => Promise.resolve({ items: [] })); + getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => { + expect(result).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "6.8.2", + } + `); + done(); + }); + }); + + it('hasNew is true when the service returns hashes not in the cache', done => { + const mockApiItems: ApiItem[] = [ + { + title: { + en: 'speaking English', + es: 'habla Espanol', + }, + description: { + en: 'language test', + es: 'idiomas', + }, + languages: ['en', 'es'], + link_text: { + en: 'click here', + es: 'aqui', + }, + link_url: { + en: 'xyzxyzxyz', + es: 'abcabc', + }, + badge: { + en: 'firefighter', + es: 'bombero', + }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'abcabc1231123123hash', + }, + ]; + + mockHttpGet.mockImplementationOnce(getHttpMockWithItems(mockApiItems)); + + getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => { + expect(result).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [ + Object { + "badge": "firefighter", + "description": "language test", + "expireOn": "2049-10-31T04:23:47.000Z", + "hash": "abcabc1231", + "linkText": "click here", + "linkUrl": "xyzxyzxyz", + "publishOn": "2014-10-31T04:23:47.000Z", + "title": "speaking English", + }, + ], + "hasNew": true, + "kibanaVersion": "6.8.2", + } + `); + done(); + }); + }); + + it('hasNew is false when service returns hashes that are all stored', done => { + localStorageGet.throws('Wrong key passed!'); + localStorageGet.withArgs(NEWSFEED_HASH_SET_STORAGE_KEY).returns('happyness'); + const mockApiItems: ApiItem[] = [ + { + title: { en: 'hasNew test' }, + description: { en: 'test' }, + link_text: { en: 'click here' }, + link_url: { en: 'xyzxyzxyz' }, + badge: { en: 'firefighter' }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'happyness', + }, + ]; + mockHttpGet.mockImplementationOnce(getHttpMockWithItems(mockApiItems)); + getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => { + expect(result).toMatchInlineSnapshot(` + Object { + "error": null, + "feedItems": Array [ + Object { + "badge": "firefighter", + "description": "test", + "expireOn": "2049-10-31T04:23:47.000Z", + "hash": "happyness", + "linkText": "click here", + "linkUrl": "xyzxyzxyz", + "publishOn": "2014-10-31T04:23:47.000Z", + "title": "hasNew test", + }, + ], + "hasNew": false, + "kibanaVersion": "6.8.2", + } + `); + done(); + }); + }); + + it('forwards an error', done => { + mockHttpGet.mockImplementationOnce((arg1, arg2) => Promise.reject('sorry, try again later!')); + + getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => { + expect(result).toMatchInlineSnapshot(` + Object { + "error": "sorry, try again later!", + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "6.8.2", + } + `); + done(); + }); + }); + + describe('Retry fetching', () => { + const successItems: ApiItem[] = [ + { + title: { en: 'hasNew test' }, + description: { en: 'test' }, + link_text: { en: 'click here' }, + link_url: { en: 'xyzxyzxyz' }, + badge: { en: 'firefighter' }, + publish_on: new Date('2014-10-31T04:23:47Z'), + expire_on: new Date('2049-10-31T04:23:47Z'), + hash: 'happyness', + }, + ]; + + it("retries until fetch doesn't error", done => { + configMock.newsfeed.mainInterval = 10; // fast retry for testing + mockHttpGet + .mockImplementationOnce(() => Promise.reject('Sorry, try again later!')) + .mockImplementationOnce(() => Promise.reject('Sorry, internal server error!')) + .mockImplementationOnce(() => Promise.reject("Sorry, it's too cold to go outside!")) + .mockImplementationOnce(getHttpMockWithItems(successItems)); + + getApi(httpMock, configMock.newsfeed, '6.8.2') + .pipe( + take(4), + toArray() + ) + .subscribe(result => { + expect(result).toMatchInlineSnapshot(` + Array [ + Object { + "error": "Sorry, try again later!", + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "6.8.2", + }, + Object { + "error": "Sorry, internal server error!", + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "6.8.2", + }, + Object { + "error": "Sorry, it's too cold to go outside!", + "feedItems": Array [], + "hasNew": false, + "kibanaVersion": "6.8.2", + }, + Object { + "error": null, + "feedItems": Array [ + Object { + "badge": "firefighter", + "description": "test", + "expireOn": "2049-10-31T04:23:47.000Z", + "hash": "happyness", + "linkText": "click here", + "linkUrl": "xyzxyzxyz", + "publishOn": "2014-10-31T04:23:47.000Z", + "title": "hasNew test", + }, + ], + "hasNew": false, + "kibanaVersion": "6.8.2", + }, + ] + `); + done(); + }); + }); + + it("doesn't retry if fetch succeeds", done => { + configMock.newsfeed.mainInterval = 10; // fast retry for testing + mockHttpGet.mockImplementation(getHttpMockWithItems(successItems)); + + const timeout$ = interval(1000); // lets us capture some results after a short time + let timesFetched = 0; + + const get$ = getApi(httpMock, configMock.newsfeed, '6.8.2').pipe( + tap(() => { + timesFetched++; + }) + ); + + race(get$, timeout$).subscribe(() => { + expect(timesFetched).toBe(1); // first fetch was successful, so there was no retry + done(); + }); + }); + }); +}); diff --git a/src/plugins/newsfeed/public/lib/api.ts b/src/plugins/newsfeed/public/lib/api.ts new file mode 100644 index 00000000000000..6920dd9b2bccc2 --- /dev/null +++ b/src/plugins/newsfeed/public/lib/api.ts @@ -0,0 +1,194 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; +import moment from 'moment'; +import { i18n } from '@kbn/i18n'; +import { catchError, filter, mergeMap, tap } from 'rxjs/operators'; +import { HttpServiceBase } from 'src/core/public'; +import { + NEWSFEED_FALLBACK_LANGUAGE, + NEWSFEED_LAST_FETCH_STORAGE_KEY, + NEWSFEED_HASH_SET_STORAGE_KEY, +} from '../../constants'; +import { NewsfeedPluginInjectedConfig, ApiItem, NewsfeedItem, FetchResult } from '../../types'; + +type ApiConfig = NewsfeedPluginInjectedConfig['newsfeed']['service']; + +export class NewsfeedApiDriver { + private readonly loadedTime = moment().utc(); // the date is compared to time in UTC format coming from the service + + constructor( + private readonly kibanaVersion: string, + private readonly userLanguage: string, + private readonly fetchInterval: number + ) {} + + shouldFetch(): boolean { + const lastFetchUtc: string | null = sessionStorage.getItem(NEWSFEED_LAST_FETCH_STORAGE_KEY); + if (lastFetchUtc == null) { + return true; + } + const last = moment(lastFetchUtc, 'x'); // parse as unix ms timestamp (already is UTC) + + // does the last fetch time precede the time that the page was loaded? + if (this.loadedTime.diff(last) > 0) { + return true; + } + + const now = moment.utc(); // always use UTC to compare timestamps that came from the service + const duration = moment.duration(now.diff(last)); + + return duration.asMilliseconds() > this.fetchInterval; + } + + updateLastFetch() { + sessionStorage.setItem(NEWSFEED_LAST_FETCH_STORAGE_KEY, Date.now().toString()); + } + + updateHashes(items: NewsfeedItem[]): { previous: string[]; current: string[] } { + // replace localStorage hashes with new hashes + const stored: string | null = localStorage.getItem(NEWSFEED_HASH_SET_STORAGE_KEY); + let old: string[] = []; + if (stored != null) { + old = stored.split(','); + } + + const newHashes = items.map(i => i.hash); + const updatedHashes = [...new Set(old.concat(newHashes))]; + localStorage.setItem(NEWSFEED_HASH_SET_STORAGE_KEY, updatedHashes.join(',')); + + return { previous: old, current: updatedHashes }; + } + + fetchNewsfeedItems(http: HttpServiceBase, config: ApiConfig): Rx.Observable { + const urlPath = config.pathTemplate.replace('{VERSION}', this.kibanaVersion); + const fullUrl = config.urlRoot + urlPath; + + return Rx.from( + http + .fetch(fullUrl, { + method: 'GET', + }) + .then(({ items }) => this.modelItems(items)) + ); + } + + validateItem(item: Partial) { + const hasMissing = [ + item.title, + item.description, + item.linkText, + item.linkUrl, + item.publishOn, + item.hash, + ].includes(undefined); + + return !hasMissing; + } + + modelItems(items: ApiItem[]): FetchResult { + const feedItems: NewsfeedItem[] = items.reduce((accum: NewsfeedItem[], it: ApiItem) => { + let chosenLanguage = this.userLanguage; + const { + expire_on: expireOnUtc, + publish_on: publishOnUtc, + languages, + title, + description, + link_text: linkText, + link_url: linkUrl, + badge, + hash, + } = it; + + if (moment(expireOnUtc).isBefore(Date.now())) { + return accum; // ignore item if expired + } + + if (moment(publishOnUtc).isAfter(Date.now())) { + return accum; // ignore item if publish date hasn't occurred yet (pre-published) + } + + if (languages && !languages.includes(chosenLanguage)) { + chosenLanguage = NEWSFEED_FALLBACK_LANGUAGE; // don't remove the item: fallback on a language + } + + const tempItem: NewsfeedItem = { + title: title[chosenLanguage], + description: description[chosenLanguage], + linkText: linkText[chosenLanguage], + linkUrl: linkUrl[chosenLanguage], + badge: badge != null ? badge![chosenLanguage] : null, + publishOn: moment(publishOnUtc), + expireOn: moment(expireOnUtc), + hash: hash.slice(0, 10), // optimize for storage and faster parsing + }; + + if (!this.validateItem(tempItem)) { + return accum; // ignore if title, description, etc is missing + } + + return [...accum, tempItem]; + }, []); + + // calculate hasNew + const { previous, current } = this.updateHashes(feedItems); + const hasNew = current.length > previous.length; + + return { + error: null, + kibanaVersion: this.kibanaVersion, + hasNew, + feedItems, + }; + } +} + +/* + * Creates an Observable to newsfeed items, powered by the main interval + * Computes hasNew value from new item hashes saved in localStorage + */ +export function getApi( + http: HttpServiceBase, + config: NewsfeedPluginInjectedConfig['newsfeed'], + kibanaVersion: string +): Rx.Observable { + const userLanguage = i18n.getLocale() || config.defaultLanguage; + const fetchInterval = config.fetchInterval; + const driver = new NewsfeedApiDriver(kibanaVersion, userLanguage, fetchInterval); + + return Rx.timer(0, config.mainInterval).pipe( + filter(() => driver.shouldFetch()), + mergeMap(() => + driver.fetchNewsfeedItems(http, config.service).pipe( + catchError(err => { + window.console.error(err); + return Rx.of({ + error: err, + kibanaVersion, + hasNew: false, + feedItems: [], + }); + }) + ) + ), + tap(() => driver.updateLastFetch()) + ); +} diff --git a/src/plugins/newsfeed/public/plugin.tsx b/src/plugins/newsfeed/public/plugin.tsx new file mode 100644 index 00000000000000..5ea5e5b324717d --- /dev/null +++ b/src/plugins/newsfeed/public/plugin.tsx @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; +import { catchError, takeUntil } from 'rxjs/operators'; +import ReactDOM from 'react-dom'; +import React from 'react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { NewsfeedPluginInjectedConfig } from '../types'; +import { NewsfeedNavButton, NewsfeedApiFetchResult } from './components/newsfeed_header_nav_button'; +import { getApi } from './lib/api'; + +export type Setup = void; +export type Start = void; + +export class NewsfeedPublicPlugin implements Plugin { + private readonly kibanaVersion: string; + private readonly stop$ = new Rx.ReplaySubject(1); + + constructor(initializerContext: PluginInitializerContext) { + this.kibanaVersion = initializerContext.env.packageInfo.version; + } + + public setup(core: CoreSetup): Setup {} + + public start(core: CoreStart): Start { + const api$ = this.fetchNewsfeed(core); + core.chrome.navControls.registerRight({ + order: 1000, + mount: target => this.mount(api$, target), + }); + } + + public stop() { + this.stop$.next(); + } + + private fetchNewsfeed(core: CoreStart) { + const { http, injectedMetadata } = core; + const config = injectedMetadata.getInjectedVar( + 'newsfeed' + ) as NewsfeedPluginInjectedConfig['newsfeed']; + + return getApi(http, config, this.kibanaVersion).pipe( + takeUntil(this.stop$), // stop the interval when stop method is called + catchError(() => Rx.of(null)) // do not throw error + ); + } + + private mount(api$: NewsfeedApiFetchResult, targetDomElement: HTMLElement) { + ReactDOM.render( + + + , + targetDomElement + ); + return () => ReactDOM.unmountComponentAtNode(targetDomElement); + } +} diff --git a/src/plugins/newsfeed/types.ts b/src/plugins/newsfeed/types.ts new file mode 100644 index 00000000000000..78485c6ee4f590 --- /dev/null +++ b/src/plugins/newsfeed/types.ts @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Moment } from 'moment'; + +export interface NewsfeedPluginInjectedConfig { + newsfeed: { + service: { + urlRoot: string; + pathTemplate: string; + }; + defaultLanguage: string; + mainInterval: number; // how often to check last updated time + fetchInterval: number; // how often to fetch remote service and set last updated + }; +} + +export interface ApiItem { + hash: string; + expire_on: Date; + publish_on: Date; + title: { [lang: string]: string }; + description: { [lang: string]: string }; + link_text: { [lang: string]: string }; + link_url: { [lang: string]: string }; + badge?: { [lang: string]: string } | null; + languages?: string[] | null; + image_url?: null; // not used phase 1 +} + +export interface NewsfeedItem { + title: string; + description: string; + linkText: string; + linkUrl: string; + badge: string | null; + publishOn: Moment; + expireOn: Moment; + hash: string; +} + +export interface FetchResult { + kibanaVersion: string; + hasNew: boolean; + feedItems: NewsfeedItem[]; + error: Error | null; +} diff --git a/tasks/function_test_groups.js b/tasks/function_test_groups.js index 31656df2cb6447..f5a1e63617dfa0 100644 --- a/tasks/function_test_groups.js +++ b/tasks/function_test_groups.js @@ -41,6 +41,7 @@ export function getFunctionalTestGroupRunConfigs({ kibanaInstallDir } = {}) { 'scripts/functional_tests', '--include-tag', tag, '--config', 'test/functional/config.js', + '--config', 'test/ui_capabilities/newsfeed_err/config.ts', // '--config', 'test/functional/config.firefox.js', '--bail', '--debug', diff --git a/test/common/config.js b/test/common/config.js index cd29b593cdadbd..58161e545bd06a 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -17,6 +17,7 @@ * under the License. */ +import path from 'path'; import { format as formatUrl } from 'url'; import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig } from '@kbn/test'; import { services } from './services'; @@ -57,6 +58,10 @@ export default function () { `--kibana.disableWelcomeScreen=true`, '--telemetry.banner=false', `--server.maxPayloadBytes=1679958`, + // newsfeed mock service + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'newsfeed')}`, + `--newsfeed.service.urlRoot=${servers.kibana.protocol}://${servers.kibana.hostname}:${servers.kibana.port}`, + `--newsfeed.service.pathTemplate=/api/_newsfeed-FTS-external-service-simulators/kibana/v{VERSION}.json`, ], }, services diff --git a/test/common/fixtures/plugins/newsfeed/index.ts b/test/common/fixtures/plugins/newsfeed/index.ts new file mode 100644 index 00000000000000..beee9bb5c6069d --- /dev/null +++ b/test/common/fixtures/plugins/newsfeed/index.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Hapi from 'hapi'; +import { initPlugin as initNewsfeed } from './newsfeed_simulation'; + +const NAME = 'newsfeed-FTS-external-service-simulators'; + +// eslint-disable-next-line import/no-default-export +export default function(kibana: any) { + return new kibana.Plugin({ + name: NAME, + init: (server: Hapi.Server) => { + initNewsfeed(server, `/api/_${NAME}`); + }, + }); +} diff --git a/test/common/fixtures/plugins/newsfeed/newsfeed_simulation.ts b/test/common/fixtures/plugins/newsfeed/newsfeed_simulation.ts new file mode 100644 index 00000000000000..2a7ea3793324da --- /dev/null +++ b/test/common/fixtures/plugins/newsfeed/newsfeed_simulation.ts @@ -0,0 +1,114 @@ +/* + * 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 Hapi from 'hapi'; + +interface WebhookRequest extends Hapi.Request { + payload: string; +} + +export async function initPlugin(server: Hapi.Server, path: string) { + server.route({ + method: ['GET'], + path: `${path}/kibana/v{version}.json`, + options: { + cors: { + origin: ['*'], + additionalHeaders: [ + 'Sec-Fetch-Mode', + 'Access-Control-Request-Method', + 'Access-Control-Request-Headers', + 'cache-control', + 'x-requested-with', + 'Origin', + 'User-Agent', + 'DNT', + 'content-type', + 'kbn-version', + ], + }, + }, + handler: newsfeedHandler, + }); + + server.route({ + method: ['GET'], + path: `${path}/kibana/crash.json`, + options: { + cors: { + origin: ['*'], + additionalHeaders: [ + 'Sec-Fetch-Mode', + 'Access-Control-Request-Method', + 'Access-Control-Request-Headers', + 'cache-control', + 'x-requested-with', + 'Origin', + 'User-Agent', + 'DNT', + 'content-type', + 'kbn-version', + ], + }, + }, + handler() { + throw new Error('Internal server error'); + }, + }); +} + +function newsfeedHandler(request: WebhookRequest, h: any) { + return htmlResponse(h, 200, JSON.stringify(mockNewsfeed(request.params.version))); +} + +const mockNewsfeed = (version: string) => ({ + items: [ + { + title: { en: `You are functionally testing the newsfeed widget with fixtures!` }, + description: { en: 'See test/common/fixtures/plugins/newsfeed/newsfeed_simulation' }, + link_text: { en: 'Generic feed-viewer could go here' }, + link_url: { en: 'https://feeds.elastic.co' }, + languages: null, + badge: null, + image_url: null, + publish_on: '2019-06-21T00:00:00', + expire_on: '2019-12-31T00:00:00', + hash: '39ca7d409c7eb25f4c69a5a6a11309b2f5ced7ca3f9b3a0109517126e0fd91ca', + }, + { + title: { en: 'Staging too!' }, + description: { en: 'Hello world' }, + link_text: { en: 'Generic feed-viewer could go here' }, + link_url: { en: 'https://feeds-staging.elastic.co' }, + languages: null, + badge: null, + image_url: null, + publish_on: '2019-06-21T00:00:00', + expire_on: '2019-12-31T00:00:00', + hash: 'db445c9443eb50ea2eb15f20edf89cf0f7dac2b058b11cafc2c8c288b6e4ce2a', + }, + ], +}); + +function htmlResponse(h: any, code: number, text: string) { + return h + .response(text) + .type('application/json') + .code(code); +} diff --git a/test/common/fixtures/plugins/newsfeed/package.json b/test/common/fixtures/plugins/newsfeed/package.json new file mode 100644 index 00000000000000..5291b1031b0a94 --- /dev/null +++ b/test/common/fixtures/plugins/newsfeed/package.json @@ -0,0 +1,7 @@ +{ + "name": "newsfeed-fixtures", + "version": "0.0.0", + "kibana": { + "version": "kibana" + } +} diff --git a/test/functional/apps/home/_newsfeed.ts b/test/functional/apps/home/_newsfeed.ts new file mode 100644 index 00000000000000..35d7ac8adefa53 --- /dev/null +++ b/test/functional/apps/home/_newsfeed.ts @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function({ getService, getPageObjects }: FtrProviderContext) { + const globalNav = getService('globalNav'); + const PageObjects = getPageObjects(['common', 'newsfeed']); + + describe('Newsfeed', () => { + before(async () => { + await PageObjects.newsfeed.resetPage(); + }); + + it('has red icon which is a sign of not checked news', async () => { + const hasCheckedNews = await PageObjects.newsfeed.getRedButtonSign(); + expect(hasCheckedNews).to.be(true); + }); + + it('clicking on newsfeed icon should open you newsfeed', async () => { + await globalNav.clickNewsfeed(); + const isOpen = await PageObjects.newsfeed.openNewsfeedPanel(); + expect(isOpen).to.be(true); + }); + + it('no red icon, because all news is checked', async () => { + const hasCheckedNews = await PageObjects.newsfeed.getRedButtonSign(); + expect(hasCheckedNews).to.be(false); + }); + + it('shows all news from newsfeed', async () => { + const objects = await PageObjects.newsfeed.getNewsfeedList(); + expect(objects).to.eql([ + '21 June 2019\nYou are functionally testing the newsfeed widget with fixtures!\nSee test/common/fixtures/plugins/newsfeed/newsfeed_simulation\nGeneric feed-viewer could go here', + '21 June 2019\nStaging too!\nHello world\nGeneric feed-viewer could go here', + ]); + }); + + it('clicking on newsfeed icon should close opened newsfeed', async () => { + await globalNav.clickNewsfeed(); + const isOpen = await PageObjects.newsfeed.openNewsfeedPanel(); + expect(isOpen).to.be(false); + }); + }); +} diff --git a/test/functional/apps/home/index.js b/test/functional/apps/home/index.js index 17c93680088cbc..f3f564fbd29193 100644 --- a/test/functional/apps/home/index.js +++ b/test/functional/apps/home/index.js @@ -29,6 +29,7 @@ export default function ({ getService, loadTestFile }) { loadTestFile(require.resolve('./_navigation')); loadTestFile(require.resolve('./_home')); + loadTestFile(require.resolve('./_newsfeed')); loadTestFile(require.resolve('./_add_data')); loadTestFile(require.resolve('./_sample_data')); }); diff --git a/test/functional/page_objects/index.ts b/test/functional/page_objects/index.ts index 1e8c454f42cfe3..84562990191d1b 100644 --- a/test/functional/page_objects/index.ts +++ b/test/functional/page_objects/index.ts @@ -35,6 +35,7 @@ import { HeaderPageProvider } from './header_page'; import { HomePageProvider } from './home_page'; // @ts-ignore not TS yet import { MonitoringPageProvider } from './monitoring_page'; +import { NewsfeedPageProvider } from './newsfeed_page'; // @ts-ignore not TS yet import { PointSeriesPageProvider } from './point_series_page'; // @ts-ignore not TS yet @@ -61,6 +62,7 @@ export const pageObjects = { header: HeaderPageProvider, home: HomePageProvider, monitoring: MonitoringPageProvider, + newsfeed: NewsfeedPageProvider, pointSeries: PointSeriesPageProvider, settings: SettingsPageProvider, share: SharePageProvider, diff --git a/test/functional/page_objects/newsfeed_page.ts b/test/functional/page_objects/newsfeed_page.ts new file mode 100644 index 00000000000000..24ff21f0b47de8 --- /dev/null +++ b/test/functional/page_objects/newsfeed_page.ts @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export function NewsfeedPageProvider({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const retry = getService('retry'); + const flyout = getService('flyout'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common']); + + class NewsfeedPage { + async resetPage() { + await PageObjects.common.navigateToUrl('home'); + } + + async closeNewsfeedPanel() { + await flyout.ensureClosed('NewsfeedFlyout'); + log.debug('clickNewsfeed icon'); + await retry.waitFor('newsfeed flyout', async () => { + if (await testSubjects.exists('NewsfeedFlyout')) { + await testSubjects.click('NewsfeedFlyout > euiFlyoutCloseButton'); + return false; + } + return true; + }); + } + + async openNewsfeedPanel() { + log.debug('clickNewsfeed icon'); + return await testSubjects.exists('NewsfeedFlyout'); + } + + async getRedButtonSign() { + return await testSubjects.exists('showBadgeNews'); + } + + async getNewsfeedList() { + const list = await testSubjects.find('NewsfeedFlyout'); + const cells = await list.findAllByCssSelector('[data-test-subj="newsHeadAlert"]'); + + const objects = []; + for (const cell of cells) { + objects.push(await cell.getVisibleText()); + } + + return objects; + } + + async openNewsfeedEmptyPanel() { + return await testSubjects.exists('emptyNewsfeed'); + } + } + + return new NewsfeedPage(); +} diff --git a/test/functional/services/global_nav.ts b/test/functional/services/global_nav.ts index 164ea999fa2793..df3aac67f22a1b 100644 --- a/test/functional/services/global_nav.ts +++ b/test/functional/services/global_nav.ts @@ -32,6 +32,10 @@ export function GlobalNavProvider({ getService }: FtrProviderContext) { return await testSubjects.click('headerGlobalNav > logo'); } + public async clickNewsfeed(): Promise { + return await testSubjects.click('headerGlobalNav > newsfeed'); + } + public async exists(): Promise { return await testSubjects.exists('headerGlobalNav'); } diff --git a/test/ui_capabilities/newsfeed_err/config.ts b/test/ui_capabilities/newsfeed_err/config.ts new file mode 100644 index 00000000000000..1f5f770e8447ce --- /dev/null +++ b/test/ui_capabilities/newsfeed_err/config.ts @@ -0,0 +1,45 @@ +/* + * 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 { FtrConfigProviderContext } from '@kbn/test/types/ftr'; +// @ts-ignore untyped module +import getFunctionalConfig from '../../functional/config'; + +// eslint-disable-next-line import/no-default-export +export default async ({ readConfigFile }: FtrConfigProviderContext) => { + const functionalConfig = await getFunctionalConfig({ readConfigFile }); + + return { + ...functionalConfig, + + testFiles: [require.resolve('./test')], + + kbnTestServer: { + ...functionalConfig.kbnTestServer, + serverArgs: [ + ...functionalConfig.kbnTestServer.serverArgs, + `--newsfeed.service.pathTemplate=/api/_newsfeed-FTS-external-service-simulators/kibana/crash.json`, + ], + }, + + junit: { + reportName: 'Newsfeed Error Handling', + }, + }; +}; diff --git a/test/ui_capabilities/newsfeed_err/test.ts b/test/ui_capabilities/newsfeed_err/test.ts new file mode 100644 index 00000000000000..2aa81f34028a02 --- /dev/null +++ b/test/ui_capabilities/newsfeed_err/test.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function uiCapabilitiesTests({ getService, getPageObjects }: FtrProviderContext) { + const globalNav = getService('globalNav'); + const PageObjects = getPageObjects(['common', 'newsfeed']); + + describe('Newsfeed icon button handle errors', function() { + this.tags('ciGroup6'); + + before(async () => { + await PageObjects.newsfeed.resetPage(); + }); + + it('clicking on newsfeed icon should open you empty newsfeed', async () => { + await globalNav.clickNewsfeed(); + const isOpen = await PageObjects.newsfeed.openNewsfeedPanel(); + expect(isOpen).to.be(true); + + const hasNewsfeedEmptyPanel = await PageObjects.newsfeed.openNewsfeedEmptyPanel(); + expect(hasNewsfeedEmptyPanel).to.be(true); + }); + + it('no red icon', async () => { + const hasCheckedNews = await PageObjects.newsfeed.getRedButtonSign(); + expect(hasCheckedNews).to.be(false); + }); + + it('shows empty panel due to error response', async () => { + const objects = await PageObjects.newsfeed.getNewsfeedList(); + expect(objects).to.eql([]); + }); + + it('clicking on newsfeed icon should close opened newsfeed', async () => { + await globalNav.clickNewsfeed(); + const isOpen = await PageObjects.newsfeed.openNewsfeedPanel(); + expect(isOpen).to.be(false); + }); + }); +} From fce52133d8818925aec9d5807ebbbd06693fcf38 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Wed, 13 Nov 2019 17:00:02 +0100 Subject: [PATCH 10/59] Upgrade Prettier 1.19 (#50487) * Upgrade Prettier to 1.19 * Fix new prettier style --- package.json | 2 +- .../src/proc_runner/observe_readable.ts | 5 +- .../src/tooling_log/tooling_log.test.ts | 5 +- packages/kbn-pm/package.json | 2 +- .../kbn-pm/src/commands/bootstrap.test.ts | 17 ++- packages/kbn-spec-to-console/package.json | 2 +- .../chrome/nav_links/nav_links_service.ts | 10 +- .../recently_accessed_service.test.ts | 5 +- src/core/public/core_system.test.ts | 5 +- .../injected_metadata_service.test.ts | 15 ++- .../overlays/banners/priority_map.test.ts | 5 +- .../public/plugins/plugins_service.test.ts | 22 ++-- .../ui_settings/ui_settings_api.test.ts | 15 +-- .../ui_settings/ui_settings_client.test.ts | 15 +-- .../public/utils/share_weak_replay.test.ts | 10 +- src/core/server/config/ensure_deep_object.ts | 23 ++-- src/core/server/plugins/plugins_system.ts | 42 +++---- .../lib/get_root_properties_objects.ts | 23 ++-- .../saved_objects/service/lib/repository.ts | 20 ++-- src/core/server/server.test.ts | 5 +- .../server/ui_settings/ui_settings_client.ts | 13 +- src/core/utils/context.ts | 27 ++--- src/core/utils/map_utils.test.ts | 13 +- src/core/utils/merge.ts | 27 ++--- src/core/utils/pick.ts | 15 +-- src/dev/license_checker/valid.ts | 17 ++- .../index_patterns/index_patterns.ts | 12 +- .../components/options/metrics_axes/index.tsx | 8 +- .../__jest__/extract_export_details.test.ts | 10 +- .../public/components/region_map_options.tsx | 5 +- .../collectors/usage/ensure_deep_object.ts | 21 ++-- src/legacy/ui/public/agg_types/agg_configs.ts | 22 ++-- .../public/agg_types/buckets/geo_hash.test.ts | 51 ++++---- .../ui/public/agg_types/buckets/range.test.ts | 5 +- .../ui/public/agg_types/buckets/range.ts | 5 +- .../ui/public/agg_types/filter/prop_filter.ts | 29 ++--- .../agg_types/metrics/metric_agg_type.ts | 5 +- .../metrics/percentile_ranks.test.ts | 5 +- .../agg_types/metrics/percentiles.test.ts | 5 +- .../agg_types/metrics/std_deviation.test.ts | 10 +- .../editors/default/components/agg.test.tsx | 7 +- .../default/components/agg_group_state.tsx | 11 +- .../components/agg_params_helper.test.ts | 5 +- .../components/number_list/utils.test.ts | 5 +- .../ui/public/vis/editors/default/utils.tsx | 29 ++--- .../pipeline_helpers/build_pipeline.test.ts | 20 +++- .../public/plugin.tsx | 7 +- .../lib/mappers/map_geo_polygon.test.ts | 5 +- .../create_app_mount_context_search.test.ts | 8 +- .../static/forms/helpers/serializers.ts | 29 ++--- .../forms/hook_form_lib/hooks/use_form.ts | 15 +-- .../static/forms/hook_form_lib/lib/utils.ts | 11 +- .../public/interpreter_provider.ts | 4 +- .../kibana_react/public/context/context.tsx | 11 +- .../page_objects/visual_builder_page.ts | 6 +- .../services/remote/poll_for_log_entry.ts | 5 +- .../public/demo_search_strategy.ts | 4 +- .../server/demo_search_strategy.ts | 4 +- x-pack/legacy/common/eui_draggable/index.d.ts | 2 +- .../server/lib/task_runner_factory.test.ts | 8 +- .../util/merge_projection/index.ts | 16 +-- .../components/app/ServiceMetrics/index.tsx | 4 +- .../app/ServiceNodeOverview/index.tsx | 4 +- .../components/app/ServiceOverview/index.tsx | 4 +- .../TransactionDetails/Distribution/index.tsx | 7 +- .../app/TransactionOverview/index.tsx | 4 +- .../components/shared/KueryBar/index.tsx | 14 ++- .../__test__/MetadataTable.test.tsx | 5 +- .../components/shared/Stacktrace/index.tsx | 43 ++++--- .../shared/charts/CustomPlot/VoronoiPlot.js | 5 +- .../Histogram/__test__/Histogram.test.js | 7 +- .../shared/charts/Histogram/index.js | 5 +- .../__tests__/chartSelectors.test.ts | 58 +++++++-- .../lib/transactions/breakdown/index.ts | 93 +++++++-------- .../lib/ui_filters/local_ui_filters/config.ts | 23 ++-- .../apm/server/routes/create_api/index.ts | 55 ++++----- .../plugins/apm/server/routes/typings.ts | 4 +- .../plugins/apm/server/routes/ui_filters.ts | 8 +- .../apm/typings/elasticsearch/aggregations.ts | 21 ++-- .../apm/typings/elasticsearch/index.ts | 5 +- .../common/config_block_validation.ts | 23 ++-- .../beats_management/common/domain_types.ts | 6 +- .../components/autocomplete_field/index.tsx | 12 +- .../navigation/breadcrumb/provider.tsx | 17 ++- .../components/table/table_type_configs.tsx | 5 +- .../lib/adapters/beats/rest_beats_adapter.ts | 22 ++-- .../lib/adapters/tags/rest_tags_adapter.ts | 20 ++-- .../adapters/tokens/rest_tokens_adapter.ts | 9 +- .../public/lib/compose/scripts.ts | 6 +- .../beats_management/server/lib/tags.ts | 15 +-- .../__tests__/beats_assignments.test.ts | 10 +- .../functions/browser/location.ts | 5 +- .../functions/common/csv.test.js | 5 +- .../common/get_flot_axis_config.test.js | 10 +- .../functions/common/get_tick_hash.test.js | 7 +- .../functions/common/math.ts | 5 +- .../functions/server/pointseries/index.ts | 5 +- .../renderers/pie/plugins/pie.js | 9 +- .../canvas/canvas_plugin_src/uis/views/pie.js | 5 +- .../canvas/public/apps/export/export/index.js | 5 +- .../canvas/public/apps/home/home_app/index.js | 5 +- .../public/apps/workpad/workpad_app/index.js | 5 +- .../canvas/public/components/app/index.js | 6 +- .../public/components/asset_manager/index.js | 6 +- .../public/components/datasource/index.js | 6 +- .../element_content/element_content.js | 9 +- .../components/element_types/element_types.js | 5 +- .../public/components/element_types/index.js | 6 +- .../components/embeddable_flyout/index.tsx | 6 +- .../public/components/expression/index.js | 6 +- .../public/components/function_form/index.js | 6 +- .../public/components/page_config/index.js | 6 +- .../public/components/page_manager/index.js | 5 +- .../canvas/public/components/router/index.js | 5 +- .../components/sidebar/sidebar_content.js | 6 +- .../public/components/sidebar_header/index.js | 5 +- .../canvas/public/components/workpad/index.js | 6 +- .../components/workpad_color_picker/index.ts | 5 +- .../public/components/workpad_config/index.js | 5 +- .../workpad_header/control_settings/index.ts | 5 +- .../fullscreen_control/index.js | 6 +- .../components/workpad_header/index.tsx | 6 +- .../workpad_header/refresh_control/index.ts | 5 +- .../workpad_header/workpad_zoom/index.tsx | 5 +- .../workpad_page/integration_utils.js | 7 +- .../workpad_interactive_page/index.js | 6 +- .../public/expression_types/arg_types/font.js | 6 +- .../lib/aeroelastic/layout_functions.js | 76 +++++++++--- .../canvas/public/state/actions/elements.js | 9 +- .../graph/public/services/fetch_top_nodes.ts | 8 +- .../graph/public/state_management/fields.ts | 15 +-- .../plugins/infra/common/utility_types.ts | 4 +- .../autocomplete_field/autocomplete_field.tsx | 12 +- .../components/loading_overlay_wrapper.tsx | 10 +- .../log_text_stream/log_entry_icon_column.tsx | 8 +- .../log_text_stream/vertical_scroll_panel.tsx | 21 ++-- .../metrics/sections/helpers/index.ts | 16 +-- .../helpers/calculate_domain.ts | 27 ++--- .../log_columns_configuration_panel.tsx | 28 +++-- .../log_analysis_results_url_state.tsx | 10 +- .../log_analysis_status_state.tsx | 7 +- .../containers/logs/with_log_position.tsx | 2 +- .../containers/metadata/use_metadata.ts | 5 +- .../containers/metrics/with_metrics.tsx | 9 +- ...ith_metrics_explorer_options_url_state.tsx | 25 ++-- .../public/containers/source_id/source_id.ts | 5 +- .../framework/kibana_framework_adapter.ts | 22 ++-- .../public/store/local/waffle_time/epic.ts | 5 +- .../store/local/waffle_time/selectors.ts | 13 +- .../store/remote/log_entries/selectors.ts | 30 ++--- .../infra/public/utils/is_displayable.ts | 9 +- .../remote_state/remote_graphql_state.ts | 55 +++------ .../infra/public/utils/use_kibana_space_id.ts | 5 +- .../fields/framework_fields_adapter.ts | 11 +- ...document_source_to_log_item_fields.test.ts | 5 +- .../lib/populate_series_with_tsvb_data.ts | 5 +- .../lens/public/app_plugin/app.test.tsx | 4 +- .../editor_frame/expression_helpers.ts | 10 +- .../embeddable/embeddable_factory.ts | 6 +- .../editor_frame_plugin/merge_tables.test.ts | 20 +++- .../dimension_panel/popover_editor.tsx | 3 +- .../lens/public/indexpattern_plugin/loader.ts | 17 ++- .../operations/definitions/index.ts | 4 +- .../rename_columns.test.ts | 36 +++++- .../indexpattern_plugin/to_expression.ts | 21 ++-- .../metric_expression.test.tsx | 6 +- .../xy_expression.test.tsx | 5 +- .../legacy/plugins/ml/common/util/es_utils.ts | 3 +- .../annotations/annotation_flyout/index.tsx | 7 +- .../analytics_list/analytics_list.tsx | 17 ++- .../datavisualizer/index_based/page.tsx | 6 +- .../models/job_service/new_job/line_chart.ts | 5 +- .../job_service/new_job/population_chart.ts | 5 +- .../export_types/csv/server/create_job.ts | 6 +- .../png/server/create_job/index.ts | 6 +- .../server/browsers/safe_child_process.ts | 5 +- .../components/profile_tree/init_data.ts | 8 +- .../privilege_space_table.test.tsx | 35 +++--- .../plugins/siem/common/utility_types.ts | 2 +- .../components/autocomplete_field/index.tsx | 13 +- .../charts/chart_place_holder.test.tsx | 20 +++- .../public/components/charts/common.test.tsx | 62 +++++++++- .../drag_and_drop/draggable_wrapper.tsx | 11 +- .../error_toast_dispatcher/index.tsx | 9 +- .../public/components/events_viewer/index.tsx | 19 ++- .../components/fields_browser/index.tsx | 11 +- .../public/components/flyout/header/index.tsx | 5 +- .../siem/public/components/flyout/index.tsx | 9 +- .../public/components/flyout/pane/index.tsx | 9 +- .../siem/public/components/inspect/index.tsx | 9 +- .../ml/conditional_links/replace_kql_parts.ts | 5 +- .../hooks/use_siem_jobs_helpers.tsx | 7 +- .../public/components/navigation/helpers.ts | 7 +- .../hosts/authentications_table/index.tsx | 16 +-- .../page/hosts/hosts_table/index.tsx | 13 +- .../hosts/uncommon_process_table/index.tsx | 16 +-- .../flow_target_select_connected/index.tsx | 9 +- .../page/network/network_dns_table/index.tsx | 9 +- .../page/network/network_http_table/index.tsx | 9 +- .../network_top_countries_table/index.tsx | 9 +- .../network_top_n_flow_table/index.tsx | 9 +- .../page/network/tls_table/index.tsx | 9 +- .../page/network/users_table/index.tsx | 9 +- .../public/components/search_bar/index.tsx | 5 +- .../public/components/search_bar/selectors.ts | 12 +- .../components/super_date_picker/selectors.ts | 57 ++------- .../timeline/auto_save_warning/index.tsx | 13 +- .../timeline/body/stateful_body.tsx | 25 ++-- .../timeline/fetch_kql_timeline.tsx | 9 +- .../siem/public/components/timeline/index.tsx | 35 +++--- .../components/timeline/refetch_timeline.tsx | 9 +- .../timeline/search_or_filter/index.tsx | 13 +- .../public/components/url_state/index.tsx | 5 +- .../components/url_state/test_dependencies.ts | 12 +- .../components/url_state/use_url_state.tsx | 7 +- .../public/containers/global_time/index.tsx | 13 +- .../plugins/siem/public/lib/keury/index.ts | 20 ++-- .../siem/public/pages/hosts/details/index.tsx | 11 +- .../plugins/siem/public/pages/hosts/hosts.tsx | 9 +- .../public/pages/network/ip_details/index.tsx | 11 +- .../siem/public/pages/network/network.tsx | 9 +- .../siem/public/store/app/selectors.ts | 13 +- .../siem/public/store/hosts/selectors.ts | 21 +--- .../siem/public/store/inputs/selectors.ts | 55 ++------- .../siem/public/store/network/selectors.ts | 38 ++---- .../siem/public/store/timeline/epic.ts | 15 +-- .../siem/public/store/timeline/model.ts | 112 +++++++++--------- .../siem/public/store/timeline/selectors.ts | 52 +++----- .../detection_engine/alerts/delete_signals.ts | 2 +- .../detection_engine/routes/schemas.test.ts | 4 +- .../lib/index_fields/elasticsearch_adapter.ts | 7 +- .../elasticsearch_adapter.test.ts | 5 +- .../siem/server/utils/build_query/fields.ts | 25 ++-- .../components/with_privileges.tsx | 27 ++--- .../policy_list/policy_table/policy_table.tsx | 5 +- .../task_manager/lib/fill_pool.test.ts | 25 +++- .../lib/sanitize_task_definitions.ts | 15 +-- .../transform/common/utils/es_utils.ts | 3 +- .../public/app/hooks/use_get_transforms.ts | 45 ++++--- .../components/with_privileges.tsx | 27 ++--- .../expanded_row.test.tsx | 17 ++- .../transform_list/transform_list.tsx | 17 ++- .../public/components/error_banner.tsx | 7 +- .../reindex/flyout/warnings_step.tsx | 11 +- .../components/tabs/checkup/filter_bar.tsx | 11 +- .../public/components/tabs/overview/steps.tsx | 16 +-- .../server/lib/es_migration_apis.ts | 27 ++--- .../server/lib/reindexing/reindex_service.ts | 8 +- .../higher_order/uptime_graphql_query.tsx | 18 +-- .../__tests__/series_has_down_values.test.ts | 5 +- .../plugins/uptime/server/kibana.index.ts | 5 +- .../pings/elasticsearch_pings_adapter.ts | 20 ++-- .../watch_create_threshold.test.tsx | 6 +- .../threshold_watch_edit.tsx | 5 +- .../watch_edit/components/watch_edit.tsx | 4 +- .../server/crypto/index.mock.ts | 2 +- ...ypted_saved_objects_client_wrapper.test.ts | 7 +- .../server/ui_capabilities_for_features.ts | 34 +++--- .../licensing/server/__fixtures__/setup.ts | 7 +- .../plugins/licensing/server/plugin.test.ts | 7 +- ...thorized_response_http_interceptor.test.ts | 5 +- .../server/authentication/api_keys.test.ts | 6 +- .../authentication/providers/kerberos.ts | 3 +- .../server/authentication/providers/oidc.ts | 4 +- .../server/authentication/providers/pki.ts | 8 +- .../server/authentication/providers/saml.ts | 4 +- .../security/server/authentication/tokens.ts | 18 +-- .../feature_privilege_builder/management.ts | 9 +- .../authorization/privileges_serializer.ts | 90 ++++++-------- .../roles/model/elasticsearch_role.ts | 46 ++++--- ...ecure_saved_objects_client_wrapper.test.ts | 15 ++- .../routes/api/external/copy_to_space.test.ts | 15 ++- .../tests/alerting/alerts.ts | 42 +++---- .../spaces_only/tests/alerting/alerts.ts | 28 ++--- .../infra_source_configuration_form.ts | 24 ++-- .../encrypted_saved_objects_api.ts | 5 +- .../common/suites/copy_to_space.ts | 23 ++-- x-pack/test_utils/testbed/mount_component.tsx | 7 +- yarn.lock | 8 +- 279 files changed, 1854 insertions(+), 1999 deletions(-) diff --git a/package.json b/package.json index cf9158c3a59b8d..757e868d4e02b5 100644 --- a/package.json +++ b/package.json @@ -433,7 +433,7 @@ "pngjs": "^3.4.0", "postcss": "^7.0.5", "postcss-url": "^8.0.0", - "prettier": "^1.18.2", + "prettier": "^1.19.1", "proxyquire": "1.8.0", "regenerate": "^1.4.0", "sass-lint": "^1.12.1", diff --git a/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts b/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts index 8feab74d363212..1a292aff303afd 100644 --- a/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts +++ b/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts @@ -29,10 +29,7 @@ import { first, ignoreElements, mergeMap } from 'rxjs/operators'; */ export function observeReadable(readable: Readable): Rx.Observable { return Rx.race( - Rx.fromEvent(readable, 'end').pipe( - first(), - ignoreElements() - ), + Rx.fromEvent(readable, 'end').pipe(first(), ignoreElements()), Rx.fromEvent(readable, 'error').pipe( first(), diff --git a/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts b/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts index 259bfd782d3fbe..21f02325cac662 100644 --- a/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts +++ b/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts @@ -112,10 +112,7 @@ describe('#getWritten$()', () => { const done$ = new Rx.Subject(); const promise = log .getWritten$() - .pipe( - takeUntil(done$), - toArray() - ) + .pipe(takeUntil(done$), toArray()) .toPromise(); log.debug('foo'); diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index 34a56615ed43a1..ac46dd02757cf9 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -50,7 +50,7 @@ "log-symbols": "^2.2.0", "ncp": "^2.0.0", "ora": "^1.4.0", - "prettier": "^1.18.2", + "prettier": "^1.19.1", "read-pkg": "^5.2.0", "rxjs": "^6.5.3", "spawn-sync": "^1.0.15", diff --git a/packages/kbn-pm/src/commands/bootstrap.test.ts b/packages/kbn-pm/src/commands/bootstrap.test.ts index b6d9a540ac940d..b36246d97c1add 100644 --- a/packages/kbn-pm/src/commands/bootstrap.test.ts +++ b/packages/kbn-pm/src/commands/bootstrap.test.ts @@ -101,7 +101,12 @@ test('handles dependencies of dependencies', async () => { 'packages/baz' ); - const projects = new Map([['kibana', kibana], ['foo', foo], ['bar', bar], ['baz', baz]]); + const projects = new Map([ + ['kibana', kibana], + ['foo', foo], + ['bar', bar], + ['baz', baz], + ]); const projectGraph = buildProjectGraph(projects); const logMock = jest.spyOn(console, 'log').mockImplementation(noop); @@ -133,7 +138,10 @@ test('does not run installer if no deps in package', async () => { 'packages/bar' ); - const projects = new Map([['kibana', kibana], ['bar', bar]]); + const projects = new Map([ + ['kibana', kibana], + ['bar', bar], + ]); const projectGraph = buildProjectGraph(projects); const logMock = jest.spyOn(console, 'log').mockImplementation(noop); @@ -193,7 +201,10 @@ test('calls "kbn:bootstrap" scripts and links executables after installing deps' 'packages/bar' ); - const projects = new Map([['kibana', kibana], ['bar', bar]]); + const projects = new Map([ + ['kibana', kibana], + ['bar', bar], + ]); const projectGraph = buildProjectGraph(projects); jest.spyOn(console, 'log').mockImplementation(noop); diff --git a/packages/kbn-spec-to-console/package.json b/packages/kbn-spec-to-console/package.json index 2e5f897894a900..a6b3e8f96f7dba 100644 --- a/packages/kbn-spec-to-console/package.json +++ b/packages/kbn-spec-to-console/package.json @@ -18,7 +18,7 @@ "homepage": "https://github.com/jbudz/spec-to-console#readme", "devDependencies": { "jest": "^24.9.0", - "prettier": "^1.18.2" + "prettier": "^1.19.1" }, "dependencies": { "commander": "^3.0.0", diff --git a/src/core/public/chrome/nav_links/nav_links_service.ts b/src/core/public/chrome/nav_links/nav_links_service.ts index affc639faf0b85..a636ff878dd410 100644 --- a/src/core/public/chrome/nav_links/nav_links_service.ts +++ b/src/core/public/chrome/nav_links/nav_links_service.ts @@ -130,10 +130,7 @@ export class NavLinksService { return { getNavLinks$: () => { - return navLinks$.pipe( - map(sortNavLinks), - takeUntil(this.stop$) - ); + return navLinks$.pipe(map(sortNavLinks), takeUntil(this.stop$)); }, get(id: string) { @@ -192,7 +189,10 @@ export class NavLinksService { } function sortNavLinks(navLinks: ReadonlyMap) { - return sortBy([...navLinks.values()].map(link => link.properties), 'order'); + return sortBy( + [...navLinks.values()].map(link => link.properties), + 'order' + ); } function relativeToAbsolute(url: string) { diff --git a/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts b/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts index cca16ddcd2a813..3c9713a93144a9 100644 --- a/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts +++ b/src/core/public/chrome/recently_accessed/recently_accessed_service.test.ts @@ -106,10 +106,7 @@ describe('RecentlyAccessed#start()', () => { const stop$ = new Subject(); const observedValues$ = recentlyAccessed .get$() - .pipe( - bufferCount(3), - takeUntil(stop$) - ) + .pipe(bufferCount(3), takeUntil(stop$)) .toPromise(); recentlyAccessed.add('/app/item1', 'Item 1', 'item1'); recentlyAccessed.add('/app/item2', 'Item 2', 'item2'); diff --git a/src/core/public/core_system.test.ts b/src/core/public/core_system.test.ts index d78504a899a345..1ee41fe64418ec 100644 --- a/src/core/public/core_system.test.ts +++ b/src/core/public/core_system.test.ts @@ -174,7 +174,10 @@ describe('#setup()', () => { it('injects legacy dependency to context#setup()', async () => { const pluginA = Symbol(); const pluginB = Symbol(); - const pluginDependencies = new Map([[pluginA, []], [pluginB, [pluginA]]]); + const pluginDependencies = new Map([ + [pluginA, []], + [pluginB, [pluginA]], + ]); MockPluginsService.getOpaqueIds.mockReturnValue(pluginDependencies); await setupCore(); diff --git a/src/core/public/injected_metadata/injected_metadata_service.test.ts b/src/core/public/injected_metadata/injected_metadata_service.test.ts index ef35fd2aa78ac3..1110097c1c92bd 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.test.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.test.ts @@ -68,18 +68,27 @@ describe('setup.getPlugins()', () => { it('returns injectedMetadata.uiPlugins', () => { const injectedMetadata = new InjectedMetadataService({ injectedMetadata: { - uiPlugins: [{ id: 'plugin-1', plugin: {} }, { id: 'plugin-2', plugin: {} }], + uiPlugins: [ + { id: 'plugin-1', plugin: {} }, + { id: 'plugin-2', plugin: {} }, + ], }, } as any); const plugins = injectedMetadata.setup().getPlugins(); - expect(plugins).toEqual([{ id: 'plugin-1', plugin: {} }, { id: 'plugin-2', plugin: {} }]); + expect(plugins).toEqual([ + { id: 'plugin-1', plugin: {} }, + { id: 'plugin-2', plugin: {} }, + ]); }); it('returns frozen version of uiPlugins', () => { const injectedMetadata = new InjectedMetadataService({ injectedMetadata: { - uiPlugins: [{ id: 'plugin-1', plugin: {} }, { id: 'plugin-2', plugin: {} }], + uiPlugins: [ + { id: 'plugin-1', plugin: {} }, + { id: 'plugin-2', plugin: {} }, + ], }, } as any); diff --git a/src/core/public/overlays/banners/priority_map.test.ts b/src/core/public/overlays/banners/priority_map.test.ts index 13d81989417f1a..2b16682c13aadd 100644 --- a/src/core/public/overlays/banners/priority_map.test.ts +++ b/src/core/public/overlays/banners/priority_map.test.ts @@ -42,7 +42,10 @@ describe('PriorityMap', () => { map = map.add('b', { priority: 3 }); map = map.add('c', { priority: 2 }); map = map.remove('c'); - expect([...map]).toEqual([['b', { priority: 3 }], ['a', { priority: 1 }]]); + expect([...map]).toEqual([ + ['b', { priority: 3 }], + ['a', { priority: 1 }], + ]); }); it('adds duplicate priorities to end', () => { diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index cfac4c36480534..0d8887774e900f 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -223,10 +223,13 @@ test('`PluginsService.setup` exposes dependent setup contracts to plugins', asyn test('`PluginsService.setup` does not set missing dependent setup contracts', async () => { plugins = [{ id: 'pluginD', plugin: createManifest('pluginD', { optional: ['missing'] }) }]; - mockPluginInitializers.set('pluginD', jest.fn(() => ({ - setup: jest.fn(), - start: jest.fn(), - })) as any); + mockPluginInitializers.set( + 'pluginD', + jest.fn(() => ({ + setup: jest.fn(), + start: jest.fn(), + })) as any + ); const pluginsService = new PluginsService(mockCoreContext, plugins); await pluginsService.setup(mockSetupDeps); @@ -268,10 +271,13 @@ test('`PluginsService.start` exposes dependent start contracts to plugins', asyn test('`PluginsService.start` does not set missing dependent start contracts', async () => { plugins = [{ id: 'pluginD', plugin: createManifest('pluginD', { optional: ['missing'] }) }]; - mockPluginInitializers.set('pluginD', jest.fn(() => ({ - setup: jest.fn(), - start: jest.fn(), - })) as any); + mockPluginInitializers.set( + 'pluginD', + jest.fn(() => ({ + setup: jest.fn(), + start: jest.fn(), + })) as any + ); const pluginsService = new PluginsService(mockCoreContext, plugins); await pluginsService.setup(mockSetupDeps); diff --git a/src/core/public/ui_settings/ui_settings_api.test.ts b/src/core/public/ui_settings/ui_settings_api.test.ts index 048ae2ccbae7f8..1170c42cea704c 100644 --- a/src/core/public/ui_settings/ui_settings_api.test.ts +++ b/src/core/public/ui_settings/ui_settings_api.test.ts @@ -183,10 +183,7 @@ describe('#getLoadingCount$()', () => { const done$ = new Rx.Subject(); const promise = uiSettingsApi .getLoadingCount$() - .pipe( - takeUntil(done$), - toArray() - ) + .pipe(takeUntil(done$), toArray()) .toPromise(); await uiSettingsApi.batchSet('foo', 'bar'); @@ -214,10 +211,7 @@ describe('#getLoadingCount$()', () => { const done$ = new Rx.Subject(); const promise = uiSettingsApi .getLoadingCount$() - .pipe( - takeUntil(done$), - toArray() - ) + .pipe(takeUntil(done$), toArray()) .toPromise(); await uiSettingsApi.batchSet('foo', 'bar'); @@ -250,7 +244,10 @@ describe('#stop', () => { uiSettingsApi.stop(); // both observables should emit the same values, and complete before the request is done loading - await expect(promise).resolves.toEqual([[0, 1], [0, 1]]); + await expect(promise).resolves.toEqual([ + [0, 1], + [0, 1], + ]); await batchSetPromise; }); }); diff --git a/src/core/public/ui_settings/ui_settings_client.test.ts b/src/core/public/ui_settings/ui_settings_client.test.ts index 8a481fe1704ddf..c58ba14d0da3e1 100644 --- a/src/core/public/ui_settings/ui_settings_client.test.ts +++ b/src/core/public/ui_settings/ui_settings_client.test.ts @@ -83,10 +83,7 @@ describe('#get$', () => { const { config } = setup(); const values = await config .get$('dateFormat') - .pipe( - take(1), - toArray() - ) + .pipe(take(1), toArray()) .toPromise(); expect(values).toEqual(['Browser']); @@ -122,10 +119,7 @@ You can use \`config.get("unknown key", defaultValue)\`, which will just return const values = await config .get$('dateFormat') - .pipe( - take(2), - toArray() - ) + .pipe(take(2), toArray()) .toPromise(); expect(values).toEqual(['Browser', 'new format']); @@ -144,10 +138,7 @@ You can use \`config.get("unknown key", defaultValue)\`, which will just return const values = await config .get$('dateFormat', 'my default') - .pipe( - take(3), - toArray() - ) + .pipe(take(3), toArray()) .toPromise(); expect(values).toEqual(['my default', 'new format', 'my default']); diff --git a/src/core/public/utils/share_weak_replay.test.ts b/src/core/public/utils/share_weak_replay.test.ts index dcf599f6d1e10f..6eaa140e5afad5 100644 --- a/src/core/public/utils/share_weak_replay.test.ts +++ b/src/core/public/utils/share_weak_replay.test.ts @@ -153,10 +153,7 @@ Array [ }); it('resubscribes if parent completes', async () => { - const shared = counter().pipe( - take(4), - shareWeakReplay(4) - ); + const shared = counter().pipe(take(4), shareWeakReplay(4)); await expect(Promise.all([record(shared.pipe(take(1))), record(shared)])).resolves .toMatchInlineSnapshot(` @@ -199,10 +196,7 @@ Array [ it('supports parents that complete synchronously', async () => { const next = jest.fn(); const complete = jest.fn(); - const shared = counter({ async: false }).pipe( - take(3), - shareWeakReplay(1) - ); + const shared = counter({ async: false }).pipe(take(3), shareWeakReplay(1)); shared.subscribe({ next, complete }); expect(next.mock.calls).toMatchInlineSnapshot(` diff --git a/src/core/server/config/ensure_deep_object.ts b/src/core/server/config/ensure_deep_object.ts index 0b24190741b10b..58865d13c1afa4 100644 --- a/src/core/server/config/ensure_deep_object.ts +++ b/src/core/server/config/ensure_deep_object.ts @@ -34,19 +34,16 @@ export function ensureDeepObject(obj: any): any { return obj.map(item => ensureDeepObject(item)); } - return Object.keys(obj).reduce( - (fullObject, propertyKey) => { - const propertyValue = obj[propertyKey]; - if (!propertyKey.includes(separator)) { - fullObject[propertyKey] = ensureDeepObject(propertyValue); - } else { - walk(fullObject, propertyKey.split(separator), propertyValue); - } - - return fullObject; - }, - {} as any - ); + return Object.keys(obj).reduce((fullObject, propertyKey) => { + const propertyValue = obj[propertyKey]; + if (!propertyKey.includes(separator)) { + fullObject[propertyKey] = ensureDeepObject(propertyValue); + } else { + walk(fullObject, propertyKey.split(separator), propertyValue); + } + + return fullObject; + }, {} as any); } function walk(obj: any, keys: string[], value: any) { diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index 9f7d8e4f351728..34acb66d4e9310 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -77,18 +77,15 @@ export class PluginsSystem { this.log.debug(`Setting up plugin "${pluginName}"...`); const pluginDeps = new Set([...plugin.requiredPlugins, ...plugin.optionalPlugins]); - const pluginDepContracts = Array.from(pluginDeps).reduce( - (depContracts, dependencyName) => { - // Only set if present. Could be absent if plugin does not have server-side code or is a - // missing optional dependency. - if (contracts.has(dependencyName)) { - depContracts[dependencyName] = contracts.get(dependencyName); - } - - return depContracts; - }, - {} as Record - ); + const pluginDepContracts = Array.from(pluginDeps).reduce((depContracts, dependencyName) => { + // Only set if present. Could be absent if plugin does not have server-side code or is a + // missing optional dependency. + if (contracts.has(dependencyName)) { + depContracts[dependencyName] = contracts.get(dependencyName); + } + + return depContracts; + }, {} as Record); contracts.set( pluginName, @@ -116,18 +113,15 @@ export class PluginsSystem { this.log.debug(`Starting plugin "${pluginName}"...`); const plugin = this.plugins.get(pluginName)!; const pluginDeps = new Set([...plugin.requiredPlugins, ...plugin.optionalPlugins]); - const pluginDepContracts = Array.from(pluginDeps).reduce( - (depContracts, dependencyName) => { - // Only set if present. Could be absent if plugin does not have server-side code or is a - // missing optional dependency. - if (contracts.has(dependencyName)) { - depContracts[dependencyName] = contracts.get(dependencyName); - } - - return depContracts; - }, - {} as Record - ); + const pluginDepContracts = Array.from(pluginDeps).reduce((depContracts, dependencyName) => { + // Only set if present. Could be absent if plugin does not have server-side code or is a + // missing optional dependency. + if (contracts.has(dependencyName)) { + depContracts[dependencyName] = contracts.get(dependencyName); + } + + return depContracts; + }, {} as Record); contracts.set( pluginName, diff --git a/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts b/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts index 3bac17bc46686f..61e4d752445c4f 100644 --- a/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts +++ b/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts @@ -39,17 +39,14 @@ const blacklist = ['migrationVersion', 'references']; export function getRootPropertiesObjects(mappings: IndexMapping) { const rootProperties = getRootProperties(mappings); - return Object.entries(rootProperties).reduce( - (acc, [key, value]) => { - // we consider the existence of the properties or type of object to designate that this is an object datatype - if ( - !blacklist.includes(key) && - ((value as ComplexFieldMapping).properties || value.type === 'object') - ) { - acc[key] = value; - } - return acc; - }, - {} as MappingProperties - ); + return Object.entries(rootProperties).reduce((acc, [key, value]) => { + // we consider the existence of the properties or type of object to designate that this is an object datatype + if ( + !blacklist.includes(key) && + ((value as ComplexFieldMapping).properties || value.type === 'object') + ) { + acc[key] = value; + } + return acc; + }, {} as MappingProperties); } diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 54b9938decb0a9..51d4a8ad50ad63 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -246,15 +246,17 @@ export class SavedObjectsRepository { const expectedResult = { esRequestIndex: requestIndexCounter++, requestedId: object.id, - rawMigratedDoc: this._serializer.savedObjectToRaw(this._migrator.migrateDocument({ - id: object.id, - type: object.type, - attributes: object.attributes, - migrationVersion: object.migrationVersion, - namespace, - updated_at: time, - references: object.references || [], - }) as SanitizedSavedObjectDoc), + rawMigratedDoc: this._serializer.savedObjectToRaw( + this._migrator.migrateDocument({ + id: object.id, + type: object.type, + attributes: object.attributes, + migrationVersion: object.migrationVersion, + namespace, + updated_at: time, + references: object.references || [], + }) as SanitizedSavedObjectDoc + ), }; bulkCreateParams.push( diff --git a/src/core/server/server.test.ts b/src/core/server/server.test.ts index aee6461580654e..f912a31901ad83 100644 --- a/src/core/server/server.test.ts +++ b/src/core/server/server.test.ts @@ -70,7 +70,10 @@ test('injects legacy dependency to context#setup()', async () => { const pluginA = Symbol(); const pluginB = Symbol(); - const pluginDependencies = new Map([[pluginA, []], [pluginB, [pluginA]]]); + const pluginDependencies = new Map([ + [pluginA, []], + [pluginB, [pluginA]], + ]); mockPluginsService.discover.mockResolvedValue(pluginDependencies); await server.setup(); diff --git a/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts index 423ff2a1dfd909..1a0f29f6ae6d93 100644 --- a/src/core/server/ui_settings/ui_settings_client.ts +++ b/src/core/server/ui_settings/ui_settings_client.ts @@ -83,14 +83,11 @@ export class UiSettingsClient implements IUiSettingsClient { async getAll() { const raw = await this.getRaw(); - return Object.keys(raw).reduce( - (all, key) => { - const item = raw[key]; - all[key] = ('userValue' in item ? item.userValue : item.value) as T; - return all; - }, - {} as Record - ); + return Object.keys(raw).reduce((all, key) => { + const item = raw[key]; + all[key] = ('userValue' in item ? item.userValue : item.value) as T; + return all; + }, {} as Record); } async getUserProvided(): Promise> { diff --git a/src/core/utils/context.ts b/src/core/utils/context.ts index 022c3e43300322..775c8906754100 100644 --- a/src/core/utils/context.ts +++ b/src/core/utils/context.ts @@ -254,23 +254,20 @@ export class ContextContainer> return [...this.contextProviders] .sort(sortByCoreFirst(this.coreId)) .filter(([contextName]) => contextsToBuild.has(contextName)) - .reduce( - async (contextPromise, [contextName, { provider, source: providerSource }]) => { - const resolvedContext = await contextPromise; + .reduce(async (contextPromise, [contextName, { provider, source: providerSource }]) => { + const resolvedContext = await contextPromise; - // For the next provider, only expose the context available based on the dependencies of the plugin that - // registered that provider. - const exposedContext = pick(resolvedContext, [ - ...this.getContextNamesForSource(providerSource), - ]) as Partial>; + // For the next provider, only expose the context available based on the dependencies of the plugin that + // registered that provider. + const exposedContext = pick(resolvedContext, [ + ...this.getContextNamesForSource(providerSource), + ]) as Partial>; - return { - ...resolvedContext, - [contextName]: await provider(exposedContext, ...contextArgs), - }; - }, - Promise.resolve({}) as Promise> - ); + return { + ...resolvedContext, + [contextName]: await provider(exposedContext, ...contextArgs), + }; + }, Promise.resolve({}) as Promise>); } private getContextNamesForSource( diff --git a/src/core/utils/map_utils.test.ts b/src/core/utils/map_utils.test.ts index 0d9b2a6129de0a..315ae3328c47f6 100644 --- a/src/core/utils/map_utils.test.ts +++ b/src/core/utils/map_utils.test.ts @@ -42,7 +42,11 @@ describe('groupIntoMap', () => { const groupBy = (item: { id: number }) => item.id; expect(groupIntoMap([{ id: 1 }, { id: 2 }, { id: 3 }], groupBy)).toEqual( - new Map([[1, [{ id: 1 }]], [2, [{ id: 2 }]], [3, [{ id: 3 }]]]) + new Map([ + [1, [{ id: 1 }]], + [2, [{ id: 2 }]], + [3, [{ id: 3 }]], + ]) ); }); @@ -93,7 +97,12 @@ describe('mapValuesOfMap', () => { map.set(even, 2); map.set(odd, 1); - expect(mapValuesOfMap(map, mapper)).toEqual(new Map([[even, 6], [odd, 3]])); + expect(mapValuesOfMap(map, mapper)).toEqual( + new Map([ + [even, 6], + [odd, 3], + ]) + ); expect(map.get(odd)).toEqual(1); expect(map.get(even)).toEqual(2); }); diff --git a/src/core/utils/merge.ts b/src/core/utils/merge.ts index aead3f35ba841b..8e5d9f4860d955 100644 --- a/src/core/utils/merge.ts +++ b/src/core/utils/merge.ts @@ -66,20 +66,17 @@ const mergeObjects = , U extends Record - [...new Set([...Object.keys(baseObj), ...Object.keys(overrideObj)])].reduce( - (merged, key) => { - const baseVal = baseObj[key]; - const overrideVal = overrideObj[key]; + [...new Set([...Object.keys(baseObj), ...Object.keys(overrideObj)])].reduce((merged, key) => { + const baseVal = baseObj[key]; + const overrideVal = overrideObj[key]; - if (isMergable(baseVal) && isMergable(overrideVal)) { - merged[key] = mergeObjects(baseVal, overrideVal); - } else if (overrideVal !== undefined) { - merged[key] = overrideVal; - } else if (baseVal !== undefined) { - merged[key] = baseVal; - } + if (isMergable(baseVal) && isMergable(overrideVal)) { + merged[key] = mergeObjects(baseVal, overrideVal); + } else if (overrideVal !== undefined) { + merged[key] = overrideVal; + } else if (baseVal !== undefined) { + merged[key] = baseVal; + } - return merged; - }, - {} as any - ); + return merged; + }, {} as any); diff --git a/src/core/utils/pick.ts b/src/core/utils/pick.ts index 77854f9af680b4..08288343d90778 100644 --- a/src/core/utils/pick.ts +++ b/src/core/utils/pick.ts @@ -18,14 +18,11 @@ */ export function pick(obj: T, keys: K[]): Pick { - return keys.reduce( - (acc, key) => { - if (obj.hasOwnProperty(key)) { - acc[key] = obj[key]; - } + return keys.reduce((acc, key) => { + if (obj.hasOwnProperty(key)) { + acc[key] = obj[key]; + } - return acc; - }, - {} as Pick - ); + return acc; + }, {} as Pick); } diff --git a/src/dev/license_checker/valid.ts b/src/dev/license_checker/valid.ts index 8fe09db0a58746..9142955185a1a0 100644 --- a/src/dev/license_checker/valid.ts +++ b/src/dev/license_checker/valid.ts @@ -36,24 +36,21 @@ interface Options { * violations or returns undefined. */ export function assertLicensesValid({ packages, validLicenses }: Options) { - const invalidMsgs = packages.reduce( - (acc, pkg) => { - const invalidLicenses = pkg.licenses.filter(license => !validLicenses.includes(license)); + const invalidMsgs = packages.reduce((acc, pkg) => { + const invalidLicenses = pkg.licenses.filter(license => !validLicenses.includes(license)); - if (pkg.licenses.length && !invalidLicenses.length) { - return acc; - } + if (pkg.licenses.length && !invalidLicenses.length) { + return acc; + } - return acc.concat(dedent` + return acc.concat(dedent` ${pkg.name} version: ${pkg.version} all licenses: ${pkg.licenses} invalid licenses: ${invalidLicenses.join(', ')} path: ${pkg.relative} `); - }, - [] as string[] - ); + }, [] as string[]); if (invalidMsgs.length) { throw createFailError( diff --git a/src/legacy/core_plugins/data/public/index_patterns/index_patterns/index_patterns.ts b/src/legacy/core_plugins/data/public/index_patterns/index_patterns/index_patterns.ts index 4767b6d3a3ca7a..2c58af9deaf49d 100644 --- a/src/legacy/core_plugins/data/public/index_patterns/index_patterns/index_patterns.ts +++ b/src/legacy/core_plugins/data/public/index_patterns/index_patterns/index_patterns.ts @@ -52,11 +52,13 @@ export class IndexPatterns { } private async refreshSavedObjectsCache() { - this.savedObjectsCache = (await this.savedObjectsClient.find({ - type: 'index-pattern', - fields: [], - perPage: 10000, - })).savedObjects; + this.savedObjectsCache = ( + await this.savedObjectsClient.find({ + type: 'index-pattern', + fields: [], + perPage: 10000, + }) + ).savedObjects; } getIds = async (refresh: boolean = false) => { diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx index c7ada18f9e1f25..2ca4ed1e2343d0 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx @@ -83,9 +83,11 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) // stores previous aggs' custom labels const [lastCustomLabels, setLastCustomLabels] = useState({} as { [key: string]: string }); // stores previous aggs' field and type - const [lastSeriesAgg, setLastSeriesAgg] = useState({} as { - [key: string]: { type: string; field: string }; - }); + const [lastSeriesAgg, setLastSeriesAgg] = useState( + {} as { + [key: string]: { type: string; field: string }; + } + ); const updateAxisTitle = () => { const axes = cloneDeep(stateParams.valueAxes); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/__jest__/extract_export_details.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/__jest__/extract_export_details.test.ts index a6ed2e36839f4b..4ecc3583e76cea 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/__jest__/extract_export_details.test.ts +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/__jest__/extract_export_details.test.ts @@ -62,7 +62,10 @@ describe('extractExportDetails', () => { [ [ objLine('1', 'index-pattern'), - detailsLine(1, [{ id: '2', type: 'index-pattern' }, { id: '3', type: 'index-pattern' }]), + detailsLine(1, [ + { id: '2', type: 'index-pattern' }, + { id: '3', type: 'index-pattern' }, + ]), ].join(''), ], { @@ -75,7 +78,10 @@ describe('extractExportDetails', () => { expect(result).toEqual({ exportedCount: 1, missingRefCount: 2, - missingReferences: [{ id: '2', type: 'index-pattern' }, { id: '3', type: 'index-pattern' }], + missingReferences: [ + { id: '2', type: 'index-pattern' }, + { id: '3', type: 'index-pattern' }, + ], }); }); diff --git a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx index 9749c7fa8e2f9a..8306b3274a9144 100644 --- a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx +++ b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx @@ -82,7 +82,10 @@ function RegionMapOptions(props: RegionMapOptionsProps) { const setField = useCallback( (paramName: 'selectedJoinField', value: FileLayerField['name']) => { if (stateParams.selectedLayer) { - setValue(paramName, stateParams.selectedLayer.fields.find(f => f.name === value)); + setValue( + paramName, + stateParams.selectedLayer.fields.find(f => f.name === value) + ); } }, [setValue, stateParams.selectedLayer] diff --git a/src/legacy/core_plugins/telemetry/server/collectors/usage/ensure_deep_object.ts b/src/legacy/core_plugins/telemetry/server/collectors/usage/ensure_deep_object.ts index 6594c7f8e7a6f0..3b7a9355da746f 100644 --- a/src/legacy/core_plugins/telemetry/server/collectors/usage/ensure_deep_object.ts +++ b/src/legacy/core_plugins/telemetry/server/collectors/usage/ensure_deep_object.ts @@ -42,19 +42,16 @@ export function ensureDeepObject(obj: any): any { return obj.map(item => ensureDeepObject(item)); } - return Object.keys(obj).reduce( - (fullObject, propertyKey) => { - const propertyValue = obj[propertyKey]; - if (!propertyKey.includes(separator)) { - fullObject[propertyKey] = ensureDeepObject(propertyValue); - } else { - walk(fullObject, propertyKey.split(separator), propertyValue); - } + return Object.keys(obj).reduce((fullObject, propertyKey) => { + const propertyValue = obj[propertyKey]; + if (!propertyKey.includes(separator)) { + fullObject[propertyKey] = ensureDeepObject(propertyValue); + } else { + walk(fullObject, propertyKey.split(separator), propertyValue); + } - return fullObject; - }, - {} as any - ); + return fullObject; + }, {} as any); } function walk(obj: any, keys: string[], value: any) { diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index 675d37d05c33c1..7c0245f30a1fda 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -253,13 +253,10 @@ export class AggConfigs { // collect all the aggregations const aggregations = this.aggs .filter(agg => agg.enabled && agg.type) - .reduce( - (requestValuesAggs, agg: AggConfig) => { - const aggs = agg.getRequestAggs(); - return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; - }, - [] as AggConfig[] - ); + .reduce((requestValuesAggs, agg: AggConfig) => { + const aggs = agg.getRequestAggs(); + return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; + }, [] as AggConfig[]); // move metrics to the end return _.sortBy(aggregations, (agg: AggConfig) => agg.type.type === AggGroupNames.Metrics ? 1 : 0 @@ -282,13 +279,10 @@ export class AggConfigs { * @return {array[AggConfig]} */ getResponseAggs(): AggConfig[] { - return this.getRequestAggs().reduce( - function(responseValuesAggs, agg: AggConfig) { - const aggs = agg.getResponseAggs(); - return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; - }, - [] as AggConfig[] - ); + return this.getRequestAggs().reduce(function(responseValuesAggs, agg: AggConfig) { + const aggs = agg.getResponseAggs(); + return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; + }, [] as AggConfig[]); } /** diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts index 5c599f16e09c2e..effa49f0ade6b2 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts @@ -156,8 +156,9 @@ describe('Geohash Agg', () => { describe('aggregation options', () => { it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => { const aggConfigs = getAggConfigs({ isFilteredByCollar: false }); - const requestAggs = geoHashBucketAgg.getRequestAggs(aggConfigs - .aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + const requestAggs = geoHashBucketAgg.getRequestAggs( + aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; expect(requestAggs.length).toEqual(2); expect(requestAggs[0].type.name).toEqual('geohash_grid'); @@ -166,8 +167,9 @@ describe('Geohash Agg', () => { it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => { const aggConfigs = getAggConfigs({ useGeocentroid: false }); - const requestAggs = geoHashBucketAgg.getRequestAggs(aggConfigs - .aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + const requestAggs = geoHashBucketAgg.getRequestAggs( + aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; expect(requestAggs.length).toEqual(2); expect(requestAggs[0].type.name).toEqual('filter'); @@ -179,36 +181,43 @@ describe('Geohash Agg', () => { let originalRequestAggs: IBucketGeoHashGridAggConfig[]; beforeEach(() => { - originalRequestAggs = geoHashBucketAgg.getRequestAggs(getAggConfigs() - .aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + originalRequestAggs = geoHashBucketAgg.getRequestAggs( + getAggConfigs().aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; }); it('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs(getAggConfigs({ - mapBounds: { - top_left: { lat: 10.0, lon: -10.0 }, - bottom_right: { lat: 9.0, lon: -9.0 }, - }, - }).aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapBounds: { + top_left: { lat: 10.0, lon: -10.0 }, + bottom_right: { lat: 9.0, lon: -9.0 }, + }, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; expect(originalRequestAggs[1].params).not.toEqual(geoBoxingBox.params); }); it('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs(getAggConfigs({ - mapBounds: { - top_left: { lat: 1, lon: -1 }, - bottom_right: { lat: -1, lon: 1 }, - }, - }).aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapBounds: { + top_left: { lat: 1, lon: -1 }, + bottom_right: { lat: -1, lon: 1 }, + }, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; expect(originalRequestAggs[1].params).toEqual(geoBoxingBox.params); }); it('should change geo_bounding_box filter aggregation and vis session state when map zoom level changes', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs(getAggConfigs({ - mapZoom: -1, - }).aggs[0] as IBucketGeoHashGridAggConfig) as IBucketGeoHashGridAggConfig[]; + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapZoom: -1, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; expect(originalRequestAggs[1].lastMapCollar).not.toEqual(geoBoxingBox.lastMapCollar); }); diff --git a/src/legacy/ui/public/agg_types/buckets/range.test.ts b/src/legacy/ui/public/agg_types/buckets/range.test.ts index f7cae60cce773b..1b423e64c48aef 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/range.test.ts @@ -72,7 +72,10 @@ describe('Range Agg', () => { schema: 'segment', params: { field: 'bytes', - ranges: [{ from: 0, to: 1000 }, { from: 1000, to: 2000 }], + ranges: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], }, }, ], diff --git a/src/legacy/ui/public/agg_types/buckets/range.ts b/src/legacy/ui/public/agg_types/buckets/range.ts index 348fccdab3fe37..230675ab487ade 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.ts +++ b/src/legacy/ui/public/agg_types/buckets/range.ts @@ -98,7 +98,10 @@ export const rangeBucketAgg = new BucketAggType({ }, { name: 'ranges', - default: [{ from: 0, to: 1000 }, { from: 1000, to: 2000 }], + default: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], editorComponent: RangesEditor, write(aggConfig: IBucketAggConfig, output: Record) { output.params.ranges = aggConfig.params.ranges; diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.ts b/src/legacy/ui/public/agg_types/filter/prop_filter.ts index 45f350ea6adc81..e6b5f3831e65d9 100644 --- a/src/legacy/ui/public/agg_types/filter/prop_filter.ts +++ b/src/legacy/ui/public/agg_types/filter/prop_filter.ts @@ -59,24 +59,21 @@ function propFilter

(prop: P) { return list; } - const options = filters.reduce( - (acc, filter) => { - let type = 'include'; - let value = filter; + const options = filters.reduce((acc, filter) => { + let type = 'include'; + let value = filter; - if (filter.charAt(0) === '!') { - type = 'exclude'; - value = filter.substr(1); - } + if (filter.charAt(0) === '!') { + type = 'exclude'; + value = filter.substr(1); + } - if (!acc[type]) { - acc[type] = []; - } - acc[type].push(value); - return acc; - }, - {} as { [type: string]: string[] } - ); + if (!acc[type]) { + acc[type] = []; + } + acc[type].push(value); + return acc; + }, {} as { [type: string]: string[] }); return list.filter(item => { const value = item[prop]; diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts index 66bc205cead132..c1f5528825bcc4 100644 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts @@ -58,8 +58,9 @@ export class MetricAggType< config.getValue || ((agg, bucket) => { // Metric types where an empty set equals `zero` - const isSettableToZero = [METRIC_TYPES.CARDINALITY, METRIC_TYPES.SUM].includes(agg.type - .name as METRIC_TYPES); + const isSettableToZero = [METRIC_TYPES.CARDINALITY, METRIC_TYPES.SUM].includes( + agg.type.name as METRIC_TYPES + ); // Return proper values when no buckets are present // `Count` handles empty sets properly diff --git a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts index f3882ca57161f1..7461b5cf07ee7c 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts @@ -63,8 +63,9 @@ describe('AggTypesMetricsPercentileRanksProvider class', function() { }); it('uses the custom label if it is set', function() { - const responseAggs: any = percentileRanksMetricAgg.getResponseAggs(aggConfigs - .aggs[0] as IPercentileRanksAggConfig); + const responseAggs: any = percentileRanksMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IPercentileRanksAggConfig + ); const percentileRankLabelFor5kBytes = responseAggs[0].makeLabel(); const percentileRankLabelFor10kBytes = responseAggs[1].makeLabel(); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts b/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts index 1503f43b22dc30..c9f4bcc3862a03 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts @@ -63,8 +63,9 @@ describe('AggTypesMetricsPercentilesProvider class', () => { }); it('uses the custom label if it is set', () => { - const responseAggs: any = percentilesMetricAgg.getResponseAggs(aggConfigs - .aggs[0] as IPercentileAggConfig); + const responseAggs: any = percentilesMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IPercentileAggConfig + ); const ninetyFifthPercentileLabel = responseAggs[0].makeLabel(); diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts b/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts index ae09b5cd789774..3125026a521854 100644 --- a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts @@ -58,8 +58,9 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { it('uses the custom label if it is set', () => { const aggConfigs = getAggConfigs('custom label'); - const responseAggs: any = stdDeviationMetricAgg.getResponseAggs(aggConfigs - .aggs[0] as IStdDevAggConfig); + const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IStdDevAggConfig + ); const lowerStdDevLabel = responseAggs[0].makeLabel(); const upperStdDevLabel = responseAggs[1].makeLabel(); @@ -71,8 +72,9 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { it('uses the default labels if custom label is not set', () => { const aggConfigs = getAggConfigs(); - const responseAggs: any = stdDeviationMetricAgg.getResponseAggs(aggConfigs - .aggs[0] as IStdDevAggConfig); + const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IStdDevAggConfig + ); const lowerStdDevLabel = responseAggs[0].makeLabel(); const upperStdDevLabel = responseAggs[1].makeLabel(); diff --git a/src/legacy/ui/public/vis/editors/default/components/agg.test.tsx b/src/legacy/ui/public/vis/editors/default/components/agg.test.tsx index 7806b1c0f78fbc..661ece5944fa34 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg.test.tsx +++ b/src/legacy/ui/public/vis/editors/default/components/agg.test.tsx @@ -248,10 +248,9 @@ describe('DefaultEditorAgg component', () => { expect(compHistogram.find(DefaultEditorAggParams).props()).toHaveProperty('disabledParams', [ 'min_doc_count', ]); - expect(compDateHistogram.find(DefaultEditorAggParams).props()).toHaveProperty( - 'disabledParams', - ['min_doc_count'] - ); + expect( + compDateHistogram.find(DefaultEditorAggParams).props() + ).toHaveProperty('disabledParams', ['min_doc_count']); }); it('should set error when agg is not histogram or date_histogram', () => { diff --git a/src/legacy/ui/public/vis/editors/default/components/agg_group_state.tsx b/src/legacy/ui/public/vis/editors/default/components/agg_group_state.tsx index 8e8926f027cad0..980889743c20d1 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg_group_state.tsx +++ b/src/legacy/ui/public/vis/editors/default/components/agg_group_state.tsx @@ -53,13 +53,10 @@ function aggGroupReducer(state: AggsState, action: AggsAction): AggsState { } function initAggsState(group: AggConfig[]): AggsState { - return group.reduce( - (state, agg) => { - state[agg.id] = { touched: false, valid: true }; - return state; - }, - {} as AggsState - ); + return group.reduce((state, agg) => { + state[agg.id] = { touched: false, valid: true }; + return state; + }, {} as AggsState); } export { aggGroupReducer, initAggsState }; diff --git a/src/legacy/ui/public/vis/editors/default/components/agg_params_helper.test.ts b/src/legacy/ui/public/vis/editors/default/components/agg_params_helper.test.ts index 5fb241714b2e8c..eb6bef48876420 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg_params_helper.test.ts +++ b/src/legacy/ui/public/vis/editors/default/components/agg_params_helper.test.ts @@ -121,7 +121,10 @@ describe('DefaultEditorAggParams helpers', () => { }, schema: {}, getIndexPattern: jest.fn(() => ({ - fields: [{ name: '@timestamp', type: 'date' }, { name: 'geo_desc', type: 'string' }], + fields: [ + { name: '@timestamp', type: 'date' }, + { name: 'geo_desc', type: 'string' }, + ], })), params: { orderBy: 'orderBy', diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts index 3928c0a62eeaa7..c6772cc1087627 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts +++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts @@ -35,7 +35,10 @@ describe('NumberList utils', () => { let range: Range; beforeEach(() => { - modelList = [{ value: 1, id: '1', isInvalid: false }, { value: 2, id: '2', isInvalid: false }]; + modelList = [ + { value: 1, id: '1', isInvalid: false }, + { value: 2, id: '2', isInvalid: false }, + ]; range = { min: 1, max: 10, diff --git a/src/legacy/ui/public/vis/editors/default/utils.tsx b/src/legacy/ui/public/vis/editors/default/utils.tsx index efc424488ec410..4f82298aaca41f 100644 --- a/src/legacy/ui/public/vis/editors/default/utils.tsx +++ b/src/legacy/ui/public/vis/editors/default/utils.tsx @@ -44,24 +44,21 @@ function groupAndSortBy< TGroupBy extends string = 'type', TLabelName extends string = 'title' >(objects: T[], groupBy: TGroupBy, labelName: TLabelName): ComboBoxGroupedOptions { - const groupedOptions = objects.reduce( - (array, obj) => { - const group = array.find(element => element.label === obj[groupBy]); - const option = { - label: obj[labelName], - target: obj, - }; + const groupedOptions = objects.reduce((array, obj) => { + const group = array.find(element => element.label === obj[groupBy]); + const option = { + label: obj[labelName], + target: obj, + }; - if (group && group.options) { - group.options.push(option); - } else { - array.push({ label: obj[groupBy], options: [option] }); - } + if (group && group.options) { + group.options.push(option); + } else { + array.push({ label: obj[groupBy], options: [option] }); + } - return array; - }, - [] as Array> - ); + return array; + }, [] as Array>); groupedOptions.sort(sortByLabel); diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/build_pipeline.test.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/build_pipeline.test.ts index 056f3e8cfc586a..70e0c1f1382fad 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/build_pipeline.test.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/build_pipeline.test.ts @@ -172,7 +172,10 @@ describe('visualize loader pipeline helpers: build pipeline', () => { const visState = { ...visStateDef, params: { foo: 'bar' } }; const schemas = { ...schemasDef, - metric: [{ ...schemaConfig, accessor: 0 }, { ...schemaConfig, accessor: 1 }], + metric: [ + { ...schemaConfig, accessor: 0 }, + { ...schemaConfig, accessor: 1 }, + ], }; const actual = buildPipelineVisFunction.table(visState, schemas, uiState); expect(actual).toMatchSnapshot(); @@ -192,7 +195,10 @@ describe('visualize loader pipeline helpers: build pipeline', () => { const visState = { ...visStateDef, params: { foo: 'bar' } }; const schemas = { ...schemasDef, - metric: [{ ...schemaConfig, accessor: 0 }, { ...schemaConfig, accessor: 1 }], + metric: [ + { ...schemaConfig, accessor: 0 }, + { ...schemaConfig, accessor: 1 }, + ], split_row: [2, 4], bucket: [3], }; @@ -250,7 +256,10 @@ describe('visualize loader pipeline helpers: build pipeline', () => { const visState = { ...visStateDef, params: { metric: {} } }; const schemas = { ...schemasDef, - metric: [{ ...schemaConfig, accessor: 0 }, { ...schemaConfig, accessor: 1 }], + metric: [ + { ...schemaConfig, accessor: 0 }, + { ...schemaConfig, accessor: 1 }, + ], }; const actual = buildPipelineVisFunction.metric(visState, schemas, uiState); expect(actual).toMatchSnapshot(); @@ -260,7 +269,10 @@ describe('visualize loader pipeline helpers: build pipeline', () => { const visState = { ...visStateDef, params: { metric: {} } }; const schemas = { ...schemasDef, - metric: [{ ...schemaConfig, accessor: 0 }, { ...schemaConfig, accessor: 1 }], + metric: [ + { ...schemaConfig, accessor: 0 }, + { ...schemaConfig, accessor: 1 }, + ], group: [{ accessor: 2 }], }; const actual = buildPipelineVisFunction.metric(visState, schemas, uiState); diff --git a/src/plugins/dashboard_embeddable_container/public/plugin.tsx b/src/plugins/dashboard_embeddable_container/public/plugin.tsx index eadf70a36416a6..dbb5a06da9cd94 100644 --- a/src/plugins/dashboard_embeddable_container/public/plugin.tsx +++ b/src/plugins/dashboard_embeddable_container/public/plugin.tsx @@ -61,9 +61,10 @@ export class DashboardEmbeddableContainerPublicPlugin const { application, notifications, overlays } = core; const { embeddable, inspector, uiActions } = plugins; - const SavedObjectFinder: React.FC< - Exclude - > = props => ( + const SavedObjectFinder: React.FC> = props => ( { }, geo_polygon: { point: { - points: [{ lat: 5, lon: 10 }, { lat: 15, lon: 20 }], + points: [ + { lat: 5, lon: 10 }, + { lat: 15, lon: 20 }, + ], }, }, } as esFilters.GeoPolygonFilter; diff --git a/src/plugins/data/public/search/create_app_mount_context_search.test.ts b/src/plugins/data/public/search/create_app_mount_context_search.test.ts index deab9af4e3a018..fa7cdbcda3082b 100644 --- a/src/plugins/data/public/search/create_app_mount_context_search.test.ts +++ b/src/plugins/data/public/search/create_app_mount_context_search.test.ts @@ -62,8 +62,10 @@ describe('Create app mount search context', () => { }); }, }); - context - .search({ greeting: 'hi' } as any, {}, 'mysearch') - .subscribe(response => {}, () => {}, done); + context.search({ greeting: 'hi' } as any, {}, 'mysearch').subscribe( + response => {}, + () => {}, + done + ); }); }); diff --git a/src/plugins/es_ui_shared/static/forms/helpers/serializers.ts b/src/plugins/es_ui_shared/static/forms/helpers/serializers.ts index e288f61de8681d..0bb89cc1af593b 100644 --- a/src/plugins/es_ui_shared/static/forms/helpers/serializers.ts +++ b/src/plugins/es_ui_shared/static/forms/helpers/serializers.ts @@ -69,24 +69,21 @@ export const stripEmptyFields = ( ): { [key: string]: any } => { const { types = ['string', 'object'], recursive = false } = options || {}; - return Object.entries(object).reduce( - (acc, [key, value]) => { - const type = typeof value; - const shouldStrip = types.includes(type as 'string'); + return Object.entries(object).reduce((acc, [key, value]) => { + const type = typeof value; + const shouldStrip = types.includes(type as 'string'); - if (shouldStrip && type === 'string' && value.trim() === '') { + if (shouldStrip && type === 'string' && value.trim() === '') { + return acc; + } else if (type === 'object' && !Array.isArray(value) && value !== null) { + if (Object.keys(value).length === 0 && shouldStrip) { return acc; - } else if (type === 'object' && !Array.isArray(value) && value !== null) { - if (Object.keys(value).length === 0 && shouldStrip) { - return acc; - } else if (recursive) { - value = stripEmptyFields({ ...value }, options); - } + } else if (recursive) { + value = stripEmptyFields({ ...value }, options); } + } - acc[key] = value; - return acc; - }, - {} as { [key: string]: any } - ); + acc[key] = value; + return acc; + }, {} as { [key: string]: any }); }; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts index 360182368ae638..3902b0615a33d8 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts @@ -65,15 +65,12 @@ export function useForm( const stripEmptyFields = (fields: FieldsMap): FieldsMap => { if (formOptions.stripEmptyFields) { - return Object.entries(fields).reduce( - (acc, [key, field]) => { - if (typeof field.value !== 'string' || field.value.trim() !== '') { - acc[key] = field; - } - return acc; - }, - {} as FieldsMap - ); + return Object.entries(fields).reduce((acc, [key, field]) => { + if (typeof field.value !== 'string' || field.value.trim() !== '') { + acc[key] = field; + } + return acc; + }, {} as FieldsMap); } return fields; }; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/lib/utils.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/lib/utils.ts index 66c3e8d983f983..62867a0c07a6b0 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/lib/utils.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/lib/utils.ts @@ -50,10 +50,7 @@ export const mapFormFields = ( formFields: Record, fn: (field: FieldHook) => any ) => - Object.entries(formFields).reduce( - (acc, [key, field]) => { - acc[key] = fn(field); - return acc; - }, - {} as Record - ); + Object.entries(formFields).reduce((acc, [key, field]) => { + acc[key] = fn(field); + return acc; + }, {} as Record); diff --git a/src/plugins/expressions/public/interpreter_provider.ts b/src/plugins/expressions/public/interpreter_provider.ts index cb84370ad69c52..15d6b1c025f549 100644 --- a/src/plugins/expressions/public/interpreter_provider.ts +++ b/src/plugins/expressions/public/interpreter_provider.ts @@ -163,9 +163,9 @@ export function interpreterProvider(config: InterpreterConfig): ExpressionInterp // Check for missing required arguments each(argDefs, argDef => { - const { aliases, default: argDefault, name: argName, required } = argDef as (ArgumentType< + const { aliases, default: argDefault, name: argName, required } = argDef as ArgumentType< any - > & { name: string }); + > & { name: string }; if ( typeof argDefault === 'undefined' && required && diff --git a/src/plugins/kibana_react/public/context/context.tsx b/src/plugins/kibana_react/public/context/context.tsx index cbae5c4638ca2d..cbf2ad07b463e7 100644 --- a/src/plugins/kibana_react/public/context/context.tsx +++ b/src/plugins/kibana_react/public/context/context.tsx @@ -32,12 +32,11 @@ const defaultContextValue = { export const context = createContext>(defaultContextValue); -export const useKibana = (): KibanaReactContextValue< - KibanaServices & Extra -> => - useContext((context as unknown) as React.Context< - KibanaReactContextValue - >); +export const useKibana = (): KibanaReactContextValue => + useContext( + (context as unknown) as React.Context> + ); export const withKibana = }>( type: React.ComponentType diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index 570511bee4bc5b..4b65de57f12d81 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -305,9 +305,9 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro public async getRhythmChartLegendValue(nth = 0) { await PageObjects.visualize.waitForVisualizationRenderingStabilized(); - const metricValue = (await find.allByCssSelector( - `.echLegendItem .echLegendItem__displayValue` - ))[nth]; + const metricValue = ( + await find.allByCssSelector(`.echLegendItem .echLegendItem__displayValue`) + )[nth]; await metricValue.moveMouseTo(); return await metricValue.getVisibleText(); } diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index b6b68cc0d3cf97..71e2711906fce7 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -95,10 +95,7 @@ export function pollForLogEntry$( [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], // pause 10 seconds then resubscribe - Rx.of(1).pipe( - delay(10 * 1000), - mergeMapTo(resubscribe) - ) + Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) ); }) ) diff --git a/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts b/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts index 377163251010c2..298eaaaf420e04 100644 --- a/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts +++ b/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts @@ -53,9 +53,7 @@ import { DEMO_SEARCH_STRATEGY, IDemoResponse } from '../common'; * @param context - context supplied by other plugins. * @param search - a search function to access other strategies that have already been registered. */ -export const demoClientSearchStrategyProvider: TSearchStrategyProvider< - typeof DEMO_SEARCH_STRATEGY -> = ( +export const demoClientSearchStrategyProvider: TSearchStrategyProvider = ( context: ISearchContext, search: ISearchGeneric ): ISearchStrategy => { diff --git a/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts b/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts index acb75b15196d69..d3f2360add6c03 100644 --- a/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts +++ b/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts @@ -20,9 +20,7 @@ import { TSearchStrategyProvider } from 'src/plugins/data/server'; import { DEMO_SEARCH_STRATEGY } from '../common'; -export const demoSearchStrategyProvider: TSearchStrategyProvider< - typeof DEMO_SEARCH_STRATEGY -> = () => { +export const demoSearchStrategyProvider: TSearchStrategyProvider = () => { return { search: request => { return Promise.resolve({ diff --git a/x-pack/legacy/common/eui_draggable/index.d.ts b/x-pack/legacy/common/eui_draggable/index.d.ts index a85da7a69534cb..322966b3c982ef 100644 --- a/x-pack/legacy/common/eui_draggable/index.d.ts +++ b/x-pack/legacy/common/eui_draggable/index.d.ts @@ -8,7 +8,7 @@ import React from 'react'; import { EuiDraggable, EuiDragDropContext } from '@elastic/eui'; type PropsOf = T extends React.ComponentType ? ComponentProps : never; -type FirstArgumentOf = Func extends ((arg1: infer FirstArgument, ...rest: any[]) => any) +type FirstArgumentOf = Func extends (arg1: infer FirstArgument, ...rest: any[]) => any ? FirstArgument : never; export type DragHandleProps = FirstArgumentOf< diff --git a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts index 3e71725713070d..a5bf42bc2cc019 100644 --- a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts @@ -111,11 +111,9 @@ test('executes the task by calling the executor with proper parameters', async ( expect(runnerResult).toBeUndefined(); expect(spaceIdToNamespace).toHaveBeenCalledWith('test'); - expect(mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser).toHaveBeenCalledWith( - 'action_task_params', - '3', - { namespace: 'namespace-test' } - ); + expect( + mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser + ).toHaveBeenCalledWith('action_task_params', '3', { namespace: 'namespace-test' }); expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ actionId: '2', params: { baz: true }, diff --git a/x-pack/legacy/plugins/apm/common/projections/util/merge_projection/index.ts b/x-pack/legacy/plugins/apm/common/projections/util/merge_projection/index.ts index 9a8f11c6493c50..522f6d39ac71a2 100644 --- a/x-pack/legacy/plugins/apm/common/projections/util/merge_projection/index.ts +++ b/x-pack/legacy/plugins/apm/common/projections/util/merge_projection/index.ts @@ -21,14 +21,14 @@ type SourceProjection = Omit, 'body'> & { }; type DeepMerge = U extends PlainObject - ? (T extends PlainObject - ? (Omit & - { - [key in keyof U]: T extends { [k in key]: any } - ? DeepMerge - : U[key]; - }) - : U) + ? T extends PlainObject + ? Omit & + { + [key in keyof U]: T extends { [k in key]: any } + ? DeepMerge + : U[key]; + } + : U : U; export function mergeProjection< diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx index 276d309cbb3e39..8005fc17f2a20c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx @@ -29,9 +29,7 @@ export function ServiceMetrics({ agentName }: ServiceMetricsProps) { const { data } = useServiceMetricCharts(urlParams, agentName); const { start, end } = urlParams; - const localFiltersConfig: React.ComponentProps< - typeof LocalUIFilters - > = useMemo( + const localFiltersConfig: React.ComponentProps = useMemo( () => ({ filterNames: ['host', 'containerId', 'podName'], params: { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx index b69076b3a1f704..a118871a5e268a 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx @@ -34,9 +34,7 @@ const ServiceNodeOverview = () => { const { uiFilters, urlParams } = useUrlParams(); const { serviceName, start, end } = urlParams; - const localFiltersConfig: React.ComponentProps< - typeof LocalUIFilters - > = useMemo( + const localFiltersConfig: React.ComponentProps = useMemo( () => ({ filterNames: ['host', 'containerId', 'podName'], params: { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx index d03e70fc99cc69..b696af040223b7 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx @@ -84,9 +84,7 @@ export function ServiceOverview() { useTrackPageview({ app: 'apm', path: 'services_overview' }); useTrackPageview({ app: 'apm', path: 'services_overview', delay: 15000 }); - const localFiltersConfig: React.ComponentProps< - typeof LocalUIFilters - > = useMemo( + const localFiltersConfig: React.ComponentProps = useMemo( () => ({ filterNames: ['host', 'agentName'], projection: PROJECTION.SERVICES diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx index db0ddb56e70880..fc86f4bb78afbe 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx @@ -195,10 +195,9 @@ export const TransactionDistribution: FunctionComponent = ( } backgroundHover={(bucket: IChartPoint) => bucket.y > 0 && bucket.sample} tooltipHeader={(bucket: IChartPoint) => - `${timeFormatter(bucket.x0, { withUnit: false })} - ${timeFormatter( - bucket.x, - { withUnit: false } - )} ${unit}` + `${timeFormatter(bucket.x0, { + withUnit: false + })} - ${timeFormatter(bucket.x, { withUnit: false })} ${unit}` } tooltipFooter={(bucket: IChartPoint) => !bucket.sample && diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx index d81b7417570a57..f016052df56a2b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -94,9 +94,7 @@ export function TransactionOverview() { } }, [http, serviceName, transactionType]); - const localFiltersConfig: React.ComponentProps< - typeof LocalUIFilters - > = useMemo( + const localFiltersConfig: React.ComponentProps = useMemo( () => ({ filterNames: ['transactionResult', 'host', 'containerId', 'podName'], params: { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 7c0b6f24f87a7b..9918f162a01f43 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -103,12 +103,14 @@ export function KueryBar() { const boolFilter = getBoolFilter(urlParams); try { - const suggestions = (await getSuggestions( - inputValue, - selectionStart, - indexPattern, - boolFilter - )) + const suggestions = ( + await getSuggestions( + inputValue, + selectionStart, + indexPattern, + boolFilter + ) + ) .filter(suggestion => !startsWith(suggestion.text, 'span.')) .slice(0, 15); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx index bdf895f423913e..4398c129aa7b84 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx @@ -21,7 +21,10 @@ describe('MetadataTable', () => { label: 'Bar', required: false, properties: ['props.A', 'props.B'], - rows: [{ key: 'props.A', value: 'A' }, { key: 'props.B', value: 'B' }] + rows: [ + { key: 'props.A', value: 'A' }, + { key: 'props.B', value: 'B' } + ] } ] as unknown) as SectionsWithRows; const output = render(); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx index ca14be237d22bb..b7963b5c75a927 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx @@ -78,29 +78,26 @@ interface StackframesGroup { } export function getGroupedStackframes(stackframes: IStackframe[]) { - return stackframes.reduce( - (acc, stackframe) => { - const prevGroup = last(acc); - const shouldAppend = - prevGroup && - prevGroup.isLibraryFrame === stackframe.library_frame && - !prevGroup.excludeFromGrouping && - !stackframe.exclude_from_grouping; + return stackframes.reduce((acc, stackframe) => { + const prevGroup = last(acc); + const shouldAppend = + prevGroup && + prevGroup.isLibraryFrame === stackframe.library_frame && + !prevGroup.excludeFromGrouping && + !stackframe.exclude_from_grouping; - // append to group - if (shouldAppend) { - prevGroup.stackframes.push(stackframe); - return acc; - } - - // create new group - acc.push({ - isLibraryFrame: Boolean(stackframe.library_frame), - excludeFromGrouping: Boolean(stackframe.exclude_from_grouping), - stackframes: [stackframe] - }); + // append to group + if (shouldAppend) { + prevGroup.stackframes.push(stackframe); return acc; - }, - [] as StackframesGroup[] - ); + } + + // create new group + acc.push({ + isLibraryFrame: Boolean(stackframe.library_frame), + excludeFromGrouping: Boolean(stackframe.exclude_from_grouping), + stackframes: [stackframe] + }); + return acc; + }, [] as StackframesGroup[]); } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js index 52afdffcb0839b..d765a57a56a180 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js @@ -32,7 +32,10 @@ class VoronoiPlot extends PureComponent { onMouseLeave={this.props.onMouseLeave} > { formatYShort={t => `${asDecimal(t)} occ.`} formatYLong={t => `${asDecimal(t)} occurrences`} tooltipHeader={bucket => - `${timeFormatter(bucket.x0, { withUnit: false })} - ${timeFormatter( - bucket.x, - { withUnit: false } - )} ${unit}` + `${timeFormatter(bucket.x0, { + withUnit: false + })} - ${timeFormatter(bucket.x, { withUnit: false })} ${unit}` } width={800} /> diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js index 7b9586634c7d0b..50c94fe88e6ad2 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js @@ -209,7 +209,10 @@ export class HistogramInner extends PureComponent { )} { return { ...bucket, diff --git a/x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts b/x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts index 80a1b96efb3d6d..2b0263f69db8fa 100644 --- a/x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts +++ b/x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts @@ -35,9 +35,18 @@ describe('chartSelectors', () => { describe('getResponseTimeSeries', () => { const apmTimeseries = { responseTimes: { - avg: [{ x: 0, y: 100 }, { x: 1000, y: 200 }], - p95: [{ x: 0, y: 200 }, { x: 1000, y: 300 }], - p99: [{ x: 0, y: 300 }, { x: 1000, y: 400 }] + avg: [ + { x: 0, y: 100 }, + { x: 1000, y: 200 } + ], + p95: [ + { x: 0, y: 200 }, + { x: 1000, y: 300 } + ], + p99: [ + { x: 0, y: 300 }, + { x: 1000, y: 400 } + ] }, tpmBuckets: [], overallAvgDuration: 200 @@ -49,21 +58,30 @@ describe('chartSelectors', () => { ).toEqual([ { color: '#3185fc', - data: [{ x: 0, y: 100 }, { x: 1000, y: 200 }], + data: [ + { x: 0, y: 100 }, + { x: 1000, y: 200 } + ], legendValue: '0 ms', title: 'Avg.', type: 'linemark' }, { color: '#e6c220', - data: [{ x: 0, y: 200 }, { x: 1000, y: 300 }], + data: [ + { x: 0, y: 200 }, + { x: 1000, y: 300 } + ], title: '95th percentile', titleShort: '95th', type: 'linemark' }, { color: '#f98510', - data: [{ x: 0, y: 300 }, { x: 1000, y: 400 }], + data: [ + { x: 0, y: 300 }, + { x: 1000, y: 400 } + ], title: '99th percentile', titleShort: '99th', type: 'linemark' @@ -87,7 +105,13 @@ describe('chartSelectors', () => { p99: [] }, tpmBuckets: [ - { key: 'HTTP 2xx', dataPoints: [{ x: 0, y: 5 }, { x: 0, y: 2 }] }, + { + key: 'HTTP 2xx', + dataPoints: [ + { x: 0, y: 5 }, + { x: 0, y: 2 } + ] + }, { key: 'HTTP 4xx', dataPoints: [{ x: 0, y: 1 }] }, { key: 'HTTP 5xx', dataPoints: [{ x: 0, y: 0 }] } ], @@ -99,7 +123,10 @@ describe('chartSelectors', () => { expect(getTpmSeries(apmTimeseries, transactionType)).toEqual([ { color: successColor, - data: [{ x: 0, y: 5 }, { x: 0, y: 2 }], + data: [ + { x: 0, y: 5 }, + { x: 0, y: 2 } + ], legendValue: '3.5 tpm', title: 'HTTP 2xx', type: 'linemark' @@ -220,9 +247,18 @@ describe('chartSelectors', () => { describe('when empty', () => { it('produces an empty series', () => { const responseTimes = { - avg: [{ x: 0, y: 1 }, { x: 100, y: 1 }], - p95: [{ x: 0, y: 1 }, { x: 100, y: 1 }], - p99: [{ x: 0, y: 1 }, { x: 100, y: 1 }] + avg: [ + { x: 0, y: 1 }, + { x: 100, y: 1 } + ], + p95: [ + { x: 0, y: 1 }, + { x: 100, y: 1 } + ], + p99: [ + { x: 0, y: 1 }, + { x: 100, y: 1 } + ] }; const series = getTpmSeries( { ...apmTimeseries, responseTimes, tpmBuckets: [] }, diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts index a21c4f38ac30cc..3d425415de8326 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -151,56 +151,53 @@ export async function getTransactionBreakdown({ const bucketsByDate = idx(resp.aggregations, _ => _.by_date.buckets) || []; - const timeseriesPerSubtype = bucketsByDate.reduce( - (prev, bucket) => { - const formattedValues = formatBucket(bucket); - const time = bucket.key; - - const updatedSeries = kpiNames.reduce((p, kpiName) => { - const { name, percentage } = formattedValues.find( - val => val.name === kpiName - ) || { - name: kpiName, - percentage: null - }; - - if (!p[name]) { - p[name] = []; - } - return { - ...p, - [name]: p[name].concat({ - x: time, - y: percentage - }) - }; - }, prev); - - const lastValues = Object.values(updatedSeries).map(last); - - // If for a given timestamp, some series have data, but others do not, - // we have to set any null values to 0 to make sure the stacked area chart - // is drawn correctly. - // If we set all values to 0, the chart always displays null values as 0, - // and the chart looks weird. - const hasAnyValues = lastValues.some(value => value.y !== null); - const hasNullValues = lastValues.some(value => value.y === null); - - if (hasAnyValues && hasNullValues) { - Object.values(updatedSeries).forEach(series => { - const value = series[series.length - 1]; - const isEmpty = value.y === null; - if (isEmpty) { - // local mutation to prevent complicated map/reduce calls - value.y = 0; - } - }); + const timeseriesPerSubtype = bucketsByDate.reduce((prev, bucket) => { + const formattedValues = formatBucket(bucket); + const time = bucket.key; + + const updatedSeries = kpiNames.reduce((p, kpiName) => { + const { name, percentage } = formattedValues.find( + val => val.name === kpiName + ) || { + name: kpiName, + percentage: null + }; + + if (!p[name]) { + p[name] = []; } + return { + ...p, + [name]: p[name].concat({ + x: time, + y: percentage + }) + }; + }, prev); + + const lastValues = Object.values(updatedSeries).map(last); + + // If for a given timestamp, some series have data, but others do not, + // we have to set any null values to 0 to make sure the stacked area chart + // is drawn correctly. + // If we set all values to 0, the chart always displays null values as 0, + // and the chart looks weird. + const hasAnyValues = lastValues.some(value => value.y !== null); + const hasNullValues = lastValues.some(value => value.y === null); + + if (hasAnyValues && hasNullValues) { + Object.values(updatedSeries).forEach(series => { + const value = series[series.length - 1]; + const isEmpty = value.y === null; + if (isEmpty) { + // local mutation to prevent complicated map/reduce calls + value.y = 0; + } + }); + } - return updatedSeries; - }, - {} as Record> - ); + return updatedSeries; + }, {} as Record>); const timeseries = kpis.map(kpi => ({ title: kpi.name, diff --git a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 5d10a4ae27060a..a0149bec728c5c 100644 --- a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -61,17 +61,14 @@ export const localUIFilterNames = Object.keys( filtersByName ) as LocalUIFilterName[]; -export const localUIFilters = localUIFilterNames.reduce( - (acc, key) => { - const field = filtersByName[key]; +export const localUIFilters = localUIFilterNames.reduce((acc, key) => { + const field = filtersByName[key]; - return { - ...acc, - [key]: { - ...field, - name: key - } - }; - }, - {} as LocalUIFilterMap -); + return { + ...acc, + [key]: { + ...field, + name: key + } + }; +}, {} as LocalUIFilterMap); diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts index 2ce27fbc5e5e49..66f28a9bf6d445 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts @@ -68,41 +68,38 @@ export function createApi() { const parsedParams = (Object.keys(rts) as Array< keyof typeof rts - >).reduce( - (acc, key) => { - const codec = rts[key]; - const value = paramMap[key]; + >).reduce((acc, key) => { + const codec = rts[key]; + const value = paramMap[key]; - const result = codec.decode(value); + const result = codec.decode(value); - if (isLeft(result)) { - throw Boom.badRequest(PathReporter.report(result)[0]); - } + if (isLeft(result)) { + throw Boom.badRequest(PathReporter.report(result)[0]); + } - const strippedKeys = difference( - Object.keys(value || {}), - Object.keys(result.right || {}) - ); + const strippedKeys = difference( + Object.keys(value || {}), + Object.keys(result.right || {}) + ); - if (strippedKeys.length) { - throw Boom.badRequest( - `Unknown keys specified: ${strippedKeys}` - ); - } + if (strippedKeys.length) { + throw Boom.badRequest( + `Unknown keys specified: ${strippedKeys}` + ); + } - // hide _debug from route handlers - const parsedValue = - key === 'query' - ? omit(result.right, '_debug') - : result.right; + // hide _debug from route handlers + const parsedValue = + key === 'query' + ? omit(result.right, '_debug') + : result.right; - return { - ...acc, - [key]: parsedValue - }; - }, - {} as Record - ); + return { + ...acc, + [key]: parsedValue + }; + }, {} as Record); return route.handler( request, diff --git a/x-pack/legacy/plugins/apm/server/routes/typings.ts b/x-pack/legacy/plugins/apm/server/routes/typings.ts index cf1a6cf7694523..77d96d3677494c 100644 --- a/x-pack/legacy/plugins/apm/server/routes/typings.ts +++ b/x-pack/legacy/plugins/apm/server/routes/typings.ts @@ -95,7 +95,9 @@ type GetOptionalParamKeys = keyof PickByValue< { [key in keyof TParams]: TParams[key] extends t.PartialType ? false - : (TParams[key] extends t.Any ? true : false); + : TParams[key] extends t.Any + ? true + : false; }, false >; diff --git a/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts b/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts index 9d36946d29cf65..36508e53acce76 100644 --- a/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts +++ b/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts @@ -45,9 +45,11 @@ export const uiFiltersEnvironmentsRoute = createRoute(() => ({ const filterNamesRt = t.type({ filterNames: jsonRt.pipe( t.array( - t.keyof(Object.fromEntries( - localUIFilterNames.map(filterName => [filterName, null]) - ) as Record) + t.keyof( + Object.fromEntries( + localUIFilterNames.map(filterName => [filterName, null]) + ) as Record + ) ) ) }); diff --git a/x-pack/legacy/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/legacy/plugins/apm/typings/elasticsearch/aggregations.ts index 9f17b0197a5b21..b694e9526e2b88 100644 --- a/x-pack/legacy/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/legacy/plugins/apm/typings/elasticsearch/aggregations.ts @@ -202,22 +202,19 @@ interface AggregationResponsePart< TDocument > > - : (TAggregationOptionsMap extends { + : TAggregationOptionsMap extends { filters: { filters: Record; }; } - ? { - buckets: { - [key in keyof TAggregationOptionsMap['filters']['filters']]: { - doc_count: number; - } & AggregationResponseMap< - TAggregationOptionsMap['aggs'], - TDocument - >; - }; - } - : never); + ? { + buckets: { + [key in keyof TAggregationOptionsMap['filters']['filters']]: { + doc_count: number; + } & AggregationResponseMap; + }; + } + : never; sampler: { doc_count: number; } & AggregationResponseMap; diff --git a/x-pack/legacy/plugins/apm/typings/elasticsearch/index.ts b/x-pack/legacy/plugins/apm/typings/elasticsearch/index.ts index 56cd0ff23a3fb5..eff39838bd957e 100644 --- a/x-pack/legacy/plugins/apm/typings/elasticsearch/index.ts +++ b/x-pack/legacy/plugins/apm/typings/elasticsearch/index.ts @@ -36,8 +36,7 @@ export type ESSearchResponse< TDocument >; } - : {}) & - ({ + : {}) & { hits: Omit['hits'], 'total'> & (TOptions['restTotalHitsAsInt'] extends true ? { @@ -49,7 +48,7 @@ export type ESSearchResponse< relation: 'eq' | 'gte'; }; }); - }); + }; export interface ESFilter { [key: string]: { diff --git a/x-pack/legacy/plugins/beats_management/common/config_block_validation.ts b/x-pack/legacy/plugins/beats_management/common/config_block_validation.ts index 92137bdf5cc6e6..8972084018d986 100644 --- a/x-pack/legacy/plugins/beats_management/common/config_block_validation.ts +++ b/x-pack/legacy/plugins/beats_management/common/config_block_validation.ts @@ -27,20 +27,17 @@ export const validateConfigurationBlocks = (configurationBlocks: ConfigurationBl ); } - const interfaceConfig = blockSchema.configs.reduce( - (props, config) => { - if (config.options) { - props[config.id] = t.keyof(Object.fromEntries( - config.options.map(opt => [opt.value, null]) - ) as Record); - } else if (config.validation) { - props[config.id] = validationMap[config.validation]; - } + const interfaceConfig = blockSchema.configs.reduce((props, config) => { + if (config.options) { + props[config.id] = t.keyof( + Object.fromEntries(config.options.map(opt => [opt.value, null])) as Record + ); + } else if (config.validation) { + props[config.id] = validationMap[config.validation]; + } - return props; - }, - {} as t.Props - ); + return props; + }, {} as t.Props); const runtimeInterface = createConfigurationBlockInterface( t.literal(blockSchema.id), diff --git a/x-pack/legacy/plugins/beats_management/common/domain_types.ts b/x-pack/legacy/plugins/beats_management/common/domain_types.ts index 0d5c67d09da8aa..bc77abc9815be8 100644 --- a/x-pack/legacy/plugins/beats_management/common/domain_types.ts +++ b/x-pack/legacy/plugins/beats_management/common/domain_types.ts @@ -13,9 +13,9 @@ export const OutputTypesArray = ['elasticsearch', 'logstash', 'kafka', 'redis']; // We can also pass in optional params to create spacific runtime checks that // can be used to validate blocs on the API and UI export const createConfigurationBlockInterface = ( - configType: t.LiteralType | t.KeyofC> = t.keyof(Object.fromEntries( - configBlockSchemas.map(s => [s.id, null]) - ) as Record), + configType: t.LiteralType | t.KeyofC> = t.keyof( + Object.fromEntries(configBlockSchemas.map(s => [s.id, null])) as Record + ), beatConfigInterface: t.Mixed = t.Dictionary ) => t.interface( diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx index 479be32ce1e127..3ac2ff72c0116d 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx @@ -265,13 +265,11 @@ const withSuggestionsHidden = (state: AutocompleteFieldState) => ({ selectedIndex: null, }); -const FixedEuiFieldSearch: React.SFC< - React.InputHTMLAttributes & - EuiFieldSearchProps & { - inputRef?: (element: HTMLInputElement | null) => void; - onSearch: (value: string) => void; - } -> = EuiFieldSearch as any; +const FixedEuiFieldSearch: React.SFC & + EuiFieldSearchProps & { + inputRef?: (element: HTMLInputElement | null) => void; + onSearch: (value: string) => void; + }> = EuiFieldSearch as any; const AutocompleteContainer = styled.div` position: relative; diff --git a/x-pack/legacy/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx b/x-pack/legacy/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx index 8736663dd08af8..f15e08c2ca230a 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx @@ -53,16 +53,13 @@ export class BreadcrumbProvider extends Component { - if (crumbStorageItem.parents) { - crumbs = crumbs.concat(crumbStorageItem.parents); - } - crumbs.push(crumbStorageItem.breadcrumb); - return crumbs; - }, - [] as Breadcrumb[] - ), + breadcrumbs: breadcrumbs.reduce((crumbs, crumbStorageItem) => { + if (crumbStorageItem.parents) { + crumbs = crumbs.concat(crumbStorageItem.parents); + } + crumbs.push(crumbStorageItem.breadcrumb); + return crumbs; + }, [] as Breadcrumb[]), addCrumb: this.addCrumb, removeCrumb: this.removeCrumb, }; diff --git a/x-pack/legacy/plugins/beats_management/public/components/table/table_type_configs.tsx b/x-pack/legacy/plugins/beats_management/public/components/table/table_type_configs.tsx index a93000a3e80f04..6f03f884563e16 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/table/table_type_configs.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/table/table_type_configs.tsx @@ -246,7 +246,10 @@ export const BeatsTableType: TableType = { name: i18n.translate('xpack.beatsManagement.beatsTable.typeLabel', { defaultMessage: 'Type', }), - options: uniq(data.map(({ type }: { type: any }) => ({ value: type })), 'value'), + options: uniq( + data.map(({ type }: { type: any }) => ({ value: type })), + 'value' + ), }, ], }), diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts index 4a7f768bd47408..b2e11461007fd2 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts @@ -26,9 +26,9 @@ export class RestBeatsAdapter implements CMBeatsAdapter { public async getBeatWithToken(enrollmentToken: string): Promise { try { - return (await this.REST.get>( - `/api/beats/agent/unknown/${enrollmentToken}` - )).item; + return ( + await this.REST.get>(`/api/beats/agent/unknown/${enrollmentToken}`) + ).item; } catch (e) { return null; } @@ -59,16 +59,20 @@ export class RestBeatsAdapter implements CMBeatsAdapter { public async removeTagsFromBeats( removals: BeatsTagAssignment[] ): Promise { - return (await this.REST.post(`/api/beats/agents_tags/removals`, { - removals, - })).results; + return ( + await this.REST.post(`/api/beats/agents_tags/removals`, { + removals, + }) + ).results; } public async assignTagsToBeats( assignments: BeatsTagAssignment[] ): Promise { - return (await this.REST.post(`/api/beats/agents_tags/assignments`, { - assignments, - })).results; + return ( + await this.REST.post(`/api/beats/agents_tags/assignments`, { + assignments, + }) + ).results; } } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts index 31c55b92721936..190c9e265463dc 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts @@ -20,9 +20,9 @@ export class RestTagsAdapter implements CMTagsAdapter { public async getTagsWithIds(tagIds: string[]): Promise { try { - return (await this.REST.get>( - `/api/beats/tags/${uniq(tagIds).join(',')}` - )).items; + return ( + await this.REST.get>(`/api/beats/tags/${uniq(tagIds).join(',')}`) + ).items; } catch (e) { return []; } @@ -37,9 +37,9 @@ export class RestTagsAdapter implements CMTagsAdapter { } public async delete(tagIds: string[]): Promise { - return (await this.REST.delete( - `/api/beats/tags/${uniq(tagIds).join(',')}` - )).success; + return ( + await this.REST.delete(`/api/beats/tags/${uniq(tagIds).join(',')}`) + ).success; } public async upsertTag(tag: BeatTag): Promise { @@ -53,9 +53,11 @@ export class RestTagsAdapter implements CMTagsAdapter { public async getAssignable(beats: CMBeat[]) { try { - return (await this.REST.get>( - `/api/beats/tags/assignable/${beats.map(beat => beat.id).join(',')}` - )).items; + return ( + await this.REST.get>( + `/api/beats/tags/assignable/${beats.map(beat => beat.id).join(',')}` + ) + ).items; } catch (e) { return []; } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts index 8274764e759aba..92cfcc935ad9b0 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts @@ -12,12 +12,11 @@ export class RestTokensAdapter implements CMTokensAdapter { constructor(private readonly REST: RestAPIAdapter) {} public async createEnrollmentTokens(numTokens: number = 1): Promise { - const results = (await this.REST.post>( - '/api/beats/enrollment_tokens', - { + const results = ( + await this.REST.post>('/api/beats/enrollment_tokens', { num_tokens: numTokens, - } - )).results; + }) + ).results; return results.map(result => result.item); } } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/compose/scripts.ts b/x-pack/legacy/plugins/beats_management/public/lib/compose/scripts.ts index 4718abc1b71537..83129384a77dfa 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/compose/scripts.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/compose/scripts.ts @@ -22,7 +22,11 @@ import { FrontendLibs } from '../types'; export function compose(basePath: string): FrontendLibs { const api = new NodeAxiosAPIAdapter('elastic', 'changeme', basePath); - const esAdapter = new MemoryElasticsearchAdapter(() => true, () => '', []); + const esAdapter = new MemoryElasticsearchAdapter( + () => true, + () => '', + [] + ); const elasticsearchLib = new ElasticsearchLib(esAdapter); const configBlocks = new ConfigBlocksLib( new RestConfigBlocksAdapter(api), diff --git a/x-pack/legacy/plugins/beats_management/server/lib/tags.ts b/x-pack/legacy/plugins/beats_management/server/lib/tags.ts index cfcc2c4eda3979..df9c65034115bb 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/tags.ts +++ b/x-pack/legacy/plugins/beats_management/server/lib/tags.ts @@ -40,15 +40,12 @@ export class CMTagsDomain { public async getNonConflictingTags(user: FrameworkUser, existingTagIds: string[]) { const tags = await this.adapter.getTagsWithIds(user, existingTagIds); const existingUniqueBlockTypes = uniq( - tags.reduce( - (existingUniqueTypes, tag) => { - if (tag.hasConfigurationBlocksTypes) { - existingUniqueTypes = existingUniqueTypes.concat(tag.hasConfigurationBlocksTypes); - } - return existingUniqueTypes; - }, - [] as string[] - ) + tags.reduce((existingUniqueTypes, tag) => { + if (tag.hasConfigurationBlocksTypes) { + existingUniqueTypes = existingUniqueTypes.concat(tag.hasConfigurationBlocksTypes); + } + return existingUniqueTypes; + }, [] as string[]) ).filter(type => UNIQUENESS_ENFORCING_TYPES.includes(type)); const safeTags = await this.adapter.getWithoutConfigTypes(user, existingUniqueBlockTypes); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/__tests__/beats_assignments.test.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/__tests__/beats_assignments.test.ts index bb0376ab87d290..156304443431d1 100644 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/__tests__/beats_assignments.test.ts +++ b/x-pack/legacy/plugins/beats_management/server/rest_api/__tests__/beats_assignments.test.ts @@ -73,7 +73,10 @@ describe('assign_tags_to_beats', () => { authorization: 'loggedin', }, payload: { - assignments: [{ beatId: 'foo', tag: 'development' }, { beatId: 'bar', tag: 'development' }], + assignments: [ + { beatId: 'foo', tag: 'development' }, + { beatId: 'bar', tag: 'development' }, + ], }, }); @@ -115,7 +118,10 @@ describe('assign_tags_to_beats', () => { authorization: 'loggedin', }, payload: { - assignments: [{ beatId: 'bar', tag: 'development' }, { beatId: 'bar', tag: 'production' }], + assignments: [ + { beatId: 'bar', tag: 'development' }, + { beatId: 'bar', tag: 'production' }, + ], }, }); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/browser/location.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/browser/location.ts index c80c37bb1ed560..e592c6d22ef737 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/browser/location.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/browser/location.ts @@ -32,7 +32,10 @@ export function location(): ExpressionFunction<'location', null, {}, Promise { const fn = functionWrapper(csv); const expected = { type: 'datatable', - columns: [{ name: 'name', type: 'string' }, { name: 'number', type: 'string' }], + columns: [ + { name: 'name', type: 'string' }, + { name: 'number', type: 'string' }, + ], rows: [ { name: 'one', number: '1' }, { name: 'two', number: '2' }, diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_flot_axis_config.test.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_flot_axis_config.test.js index bfc3212fa234ca..a5b65e6bdc62b9 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_flot_axis_config.test.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_flot_axis_config.test.js @@ -84,10 +84,16 @@ describe('getFlotAxisConfig', () => { describe('ticks', () => { it('adds a tick mark mapping for string columns', () => { let result = getFlotAxisConfig('x', true, { columns, ticks }); - expect(result.ticks).toEqual([[2, 'product1'], [1, 'product2']]); + expect(result.ticks).toEqual([ + [2, 'product1'], + [1, 'product2'], + ]); result = getFlotAxisConfig('x', xAxisConfig, { columns, ticks }); - expect(result.ticks).toEqual([[2, 'product1'], [1, 'product2']]); + expect(result.ticks).toEqual([ + [2, 'product1'], + [1, 'product2'], + ]); }); }); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_tick_hash.test.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_tick_hash.test.js index f44d37abe166f9..74c13be3abd7b9 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_tick_hash.test.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/get_tick_hash.test.js @@ -30,7 +30,12 @@ describe('getTickHash', () => { x: { type: 'number', role: 'dimension', expression: 'id' }, y: { type: 'boolean', role: 'dimension', expression: 'running' }, }; - const rows = [{ x: 1, y: true }, { x: 2, y: true }, { x: 1, y: false }, { x: 2, y: false }]; + const rows = [ + { x: 1, y: true }, + { x: 2, y: true }, + { x: 1, y: false }, + { x: 2, y: false }, + ]; expect(getTickHash(columns, rows)).toEqual({ x: { hash: {}, counter: 0 }, diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/math.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/math.ts index c180b6186ee921..718f2d8b11e1a9 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/math.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/math.ts @@ -44,7 +44,10 @@ export function math(): ExpressionFunction<'math', Context, Arguments, number> { } const mathContext = isDatatable(context) - ? pivotObjectArray(context.rows, context.columns.map(col => col.name)) + ? pivotObjectArray( + context.rows, + context.columns.map(col => col.name) + ) : { value: context }; try { diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts index 5889864df3c1df..5d5c3c1a735a02 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts @@ -187,7 +187,10 @@ export function pointseries(): ExpressionFunction< // Then compute that 1 value for each measure Object.values(measureKeys).forEach(valueRows => { const subtable = { type: 'datatable', columns: context.columns, rows: valueRows }; - const subScope = pivotObjectArray(subtable.rows, subtable.columns.map(col => col.name)); + const subScope = pivotObjectArray( + subtable.rows, + subtable.columns.map(col => col.name) + ); const measureValues = measureNames.map(measure => { try { const ev = evaluate(args[measure], subScope); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/pie/plugins/pie.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/pie/plugins/pie.js index 9229def146f8b0..042cbe83fb10fc 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/pie/plugins/pie.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/pie/plugins/pie.js @@ -683,7 +683,14 @@ function init(plot) { const p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5); const p5X = radius * Math.cos(s.startAngle + s.angle); const p5Y = radius * Math.sin(s.startAngle + s.angle); - const arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]]; + const arrPoly = [ + [0, 0], + [p1X, p1Y], + [p2X, p2Y], + [p3X, p3Y], + [p4X, p4Y], + [p5X, p5Y], + ]; const arrPoint = [x, y]; // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/views/pie.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/views/pie.js index 6a7a89231f2509..4bb68973e80eab 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/views/pie.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/views/pie.js @@ -14,7 +14,10 @@ const { Pie: strings } = ViewStrings; export const pie = () => ({ name: 'pie', displayName: strings.getDisplayName(), - modelArgs: [['color', { label: 'Slice Labels' }], ['size', { label: 'Slice Angles' }]], + modelArgs: [ + ['color', { label: 'Slice Labels' }], + ['size', { label: 'Slice Angles' }], + ], args: [ { name: 'palette', diff --git a/x-pack/legacy/plugins/canvas/public/apps/export/export/index.js b/x-pack/legacy/plugins/canvas/public/apps/export/export/index.js index 16ca644160c0a3..d40c5f787e44f8 100644 --- a/x-pack/legacy/plugins/canvas/public/apps/export/export/index.js +++ b/x-pack/legacy/plugins/canvas/public/apps/export/export/index.js @@ -25,9 +25,6 @@ const mapDispatchToProps = dispatch => ({ const branches = [branch(({ workpad }) => workpad == null, renderComponent(LoadWorkpad))]; export const ExportApp = compose( - connect( - mapStateToProps, - mapDispatchToProps - ), + connect(mapStateToProps, mapDispatchToProps), ...branches )(Component); diff --git a/x-pack/legacy/plugins/canvas/public/apps/home/home_app/index.js b/x-pack/legacy/plugins/canvas/public/apps/home/home_app/index.js index 8ecde2cc721e39..f26b3510c76826 100644 --- a/x-pack/legacy/plugins/canvas/public/apps/home/home_app/index.js +++ b/x-pack/legacy/plugins/canvas/public/apps/home/home_app/index.js @@ -14,7 +14,4 @@ const mapDispatchToProps = dispatch => ({ }, }); -export const HomeApp = connect( - null, - mapDispatchToProps -)(Component); +export const HomeApp = connect(null, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/index.js b/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/index.js index 8789577c92f63e..f0a5325baf3c04 100644 --- a/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/index.js +++ b/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/index.js @@ -35,10 +35,7 @@ const mapDispatchToProps = dispatch => ({ const branches = [branch(({ workpad }) => workpad == null, renderComponent(LoadWorkpad))]; export const WorkpadApp = compose( - connect( - mapStateToProps, - mapDispatchToProps - ), + connect(mapStateToProps, mapDispatchToProps), ...branches, withElementsLoadedTelemetry )(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/app/index.js b/x-pack/legacy/plugins/canvas/public/components/app/index.js index b3aa9c393096b3..65b811fe681348 100644 --- a/x-pack/legacy/plugins/canvas/public/components/app/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/app/index.js @@ -97,11 +97,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }; export const App = compose( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withProps(() => ({ onRouteChange: trackRouteChange, })) diff --git a/x-pack/legacy/plugins/canvas/public/components/asset_manager/index.js b/x-pack/legacy/plugins/canvas/public/components/asset_manager/index.js index 69c4463e7d210b..6c05eec0c3c09d 100644 --- a/x-pack/legacy/plugins/canvas/public/components/asset_manager/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/asset_manager/index.js @@ -89,10 +89,6 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }; export const AssetManager = compose( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withProps({ onAssetCopy: asset => notify.success(`Copied '${asset.id}' to clipboard`) }) )(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/datasource/index.js b/x-pack/legacy/plugins/canvas/public/components/datasource/index.js index 2c7820df26ca91..7fb73b1672eb1b 100644 --- a/x-pack/legacy/plugins/canvas/public/components/datasource/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/datasource/index.js @@ -82,11 +82,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }; export const Datasource = compose( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withState('stateArgs', 'updateArgs', ({ args }) => args), withState('selecting', 'setSelecting', false), withState('previewing', 'setPreviewing', false), diff --git a/x-pack/legacy/plugins/canvas/public/components/element_content/element_content.js b/x-pack/legacy/plugins/canvas/public/components/element_content/element_content.js index e85ce8c10da644..89c0b5b21c581a 100644 --- a/x-pack/legacy/plugins/canvas/public/components/element_content/element_content.js +++ b/x-pack/legacy/plugins/canvas/public/components/element_content/element_content.js @@ -21,9 +21,12 @@ import { InvalidElementType } from './invalid_element_type'; */ const branches = [ // no renderable or renderable config value, render loading - branch(({ renderable, state }) => { - return !state || !renderable; - }, renderComponent(({ backgroundColor }) => )), + branch( + ({ renderable, state }) => { + return !state || !renderable; + }, + renderComponent(({ backgroundColor }) => ) + ), // renderable is available, but no matching element is found, render invalid branch(({ renderable, renderFunction }) => { diff --git a/x-pack/legacy/plugins/canvas/public/components/element_types/element_types.js b/x-pack/legacy/plugins/canvas/public/components/element_types/element_types.js index 26a0d926553629..dabf06a24aeb64 100644 --- a/x-pack/legacy/plugins/canvas/public/components/element_types/element_types.js +++ b/x-pack/legacy/plugins/canvas/public/components/element_types/element_types.js @@ -116,7 +116,10 @@ export class ElementTypes extends Component { }; _sortElements = elements => - sortBy(map(elements, (element, name) => ({ name, ...element })), 'displayName'); + sortBy( + map(elements, (element, name) => ({ name, ...element })), + 'displayName' + ); render() { const { diff --git a/x-pack/legacy/plugins/canvas/public/components/element_types/index.js b/x-pack/legacy/plugins/canvas/public/components/element_types/index.js index 20d19d2fcbd828..8faaf278a07de3 100644 --- a/x-pack/legacy/plugins/canvas/public/components/element_types/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/element_types/index.js @@ -95,11 +95,7 @@ export const ElementTypes = compose( withState('customElements', 'setCustomElements', []), withState('filterTags', 'setFilterTags', []), withProps(() => ({ elements: elementsRegistry.toJS() })), - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ) + connect(mapStateToProps, mapDispatchToProps, mergeProps) )(Component); ElementTypes.propTypes = { diff --git a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx index 8a040c0c90c83e..612406c30f88ee 100644 --- a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx @@ -105,9 +105,5 @@ export class EmbeddableFlyoutPortal extends React.Component { } export const AddEmbeddablePanel = compose void }>( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ) + connect(mapStateToProps, mapDispatchToProps, mergeProps) )(EmbeddableFlyoutPortal); diff --git a/x-pack/legacy/plugins/canvas/public/components/expression/index.js b/x-pack/legacy/plugins/canvas/public/components/expression/index.js index 6ae4ef984264fd..4bcdb547186d15 100644 --- a/x-pack/legacy/plugins/canvas/public/components/expression/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/expression/index.js @@ -70,11 +70,7 @@ const expressionLifecycle = lifecycle({ }); export const Expression = compose( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withState('functionDefinitions', 'setFunctionDefinitions', []), withState('formState', 'setFormState', ({ expression }) => ({ expression, diff --git a/x-pack/legacy/plugins/canvas/public/components/function_form/index.js b/x-pack/legacy/plugins/canvas/public/components/function_form/index.js index 32e9cbbd1d91d6..774214cf68cecd 100644 --- a/x-pack/legacy/plugins/canvas/public/components/function_form/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/function_form/index.js @@ -105,11 +105,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }; }; -export const FunctionForm = connect( - mapStateToProps, - mapDispatchToProps, - mergeProps -)(Component); +export const FunctionForm = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); FunctionForm.propTypes = { expressionIndex: PropTypes.number, diff --git a/x-pack/legacy/plugins/canvas/public/components/page_config/index.js b/x-pack/legacy/plugins/canvas/public/components/page_config/index.js index a0692584d49864..a51e6b4b5d987c 100644 --- a/x-pack/legacy/plugins/canvas/public/components/page_config/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/page_config/index.js @@ -43,8 +43,4 @@ const mergeProps = (stateProps, dispatchProps) => { }; }; -export const PageConfig = connect( - mapStateToProps, - mapDispatchToProps, - mergeProps -)(Component); +export const PageConfig = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/page_manager/index.js b/x-pack/legacy/plugins/canvas/public/components/page_manager/index.js index 06507e4eb9a718..ef5de3feb575c1 100644 --- a/x-pack/legacy/plugins/canvas/public/components/page_manager/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/page_manager/index.js @@ -32,9 +32,6 @@ const mapDispatchToProps = dispatch => ({ }); export const PageManager = compose( - connect( - mapStateToProps, - mapDispatchToProps - ), + connect(mapStateToProps, mapDispatchToProps), withState('deleteId', 'setDeleteId', null) )(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/router/index.js b/x-pack/legacy/plugins/canvas/public/components/router/index.js index 51d856b0fc7a6a..430d6a53436624 100644 --- a/x-pack/legacy/plugins/canvas/public/components/router/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/router/index.js @@ -20,7 +20,4 @@ const mapDispatchToState = { setRefreshInterval, }; -export const Router = connect( - null, - mapDispatchToState -)(Component); +export const Router = connect(null, mapDispatchToState)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/sidebar/sidebar_content.js b/x-pack/legacy/plugins/canvas/public/components/sidebar/sidebar_content.js index 825ea8a4f24941..9de5f81b440ba8 100644 --- a/x-pack/legacy/plugins/canvas/public/components/sidebar/sidebar_content.js +++ b/x-pack/legacy/plugins/canvas/public/components/sidebar/sidebar_content.js @@ -93,10 +93,6 @@ const branches = [ ]; export const SidebarContent = compose( - connect( - mapStateToProps, - null, - mergeProps - ), + connect(mapStateToProps, null, mergeProps), ...branches )(GlobalConfig); diff --git a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/index.js b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/index.js index f60aad1fa3e72a..ac282962afb54a 100644 --- a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/index.js @@ -56,10 +56,7 @@ const mapDispatchToProps = dispatch => ({ }); export const SidebarHeader = compose( - connect( - mapStateToProps, - mapDispatchToProps - ), + connect(mapStateToProps, mapDispatchToProps), withHandlers(basicHandlerCreators), withHandlers(clipboardHandlerCreators), withHandlers(layerHandlerCreators), diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad/index.js b/x-pack/legacy/plugins/canvas/public/components/workpad/index.js index 723b30aac37fa8..fca663f8532d86 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad/index.js @@ -72,11 +72,7 @@ export const Workpad = compose( router: PropTypes.object, }), withState('grid', 'setGrid', false), - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withState('transition', 'setTransition', null), withState('prevSelectedPageNumber', 'setPrevSelectedPageNumber', 0), withProps(({ selectedPageNumber, prevSelectedPageNumber, transition }) => { diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_color_picker/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_color_picker/index.ts index 2b966e7bd6bb8b..c6dddab3b5dd16 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_color_picker/index.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_color_picker/index.ts @@ -21,7 +21,4 @@ const mapDispatchToProps = { onRemoveColor: removeColor, }; -export const WorkpadColorPicker = connect( - mapStateToProps, - mapDispatchToProps -)(Component); +export const WorkpadColorPicker = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_config/index.js b/x-pack/legacy/plugins/canvas/public/components/workpad_config/index.js index b13740f177a23f..aa3bbdce978630 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_config/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_config/index.js @@ -31,7 +31,4 @@ const mapDispatchToProps = { setWorkpadCSS: css => setWorkpadCSS(css), }; -export const WorkpadConfig = connect( - mapStateToProps, - mapDispatchToProps -)(Component); +export const WorkpadConfig = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts index dc4c4461c59218..316a49c85c09da 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts @@ -32,7 +32,4 @@ const mapDispatchToProps = { setAutoplayInterval, }; -export const ControlSettings = connect( - mapStateToProps, - mapDispatchToProps -)(Component); +export const ControlSettings = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/fullscreen_control/index.js b/x-pack/legacy/plugins/canvas/public/components/workpad_header/fullscreen_control/index.js index cf2e80cee03bf5..fc0bd4c74ba245 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/fullscreen_control/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/fullscreen_control/index.js @@ -68,11 +68,7 @@ export const FullscreenControl = compose( getContext({ router: PropTypes.object, }), - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withState('transition', 'setTransition', null), withState('prevSelectedPageNumber', 'setPrevSelectedPageNumber', 0), withProps(({ selectedPageNumber, prevSelectedPageNumber, transition }) => { diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/index.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/index.tsx index 6d3c9a0640ba2c..d2fece567a8ad9 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/index.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/index.tsx @@ -46,8 +46,4 @@ const mergeProps = ( toggleWriteable: () => dispatchProps.setWriteable(!stateProps.isWriteable), }); -export const WorkpadHeader = connect( - mapStateToProps, - mapDispatchToProps, - mergeProps -)(Component); +export const WorkpadHeader = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/index.ts index 718fec9f59f778..53c053811a273d 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/index.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/index.ts @@ -20,7 +20,4 @@ const mapDispatchToProps = { doRefresh: fetchAllRenderables, }; -export const RefreshControl = connect( - mapStateToProps, - mapDispatchToProps -)(Component); +export const RefreshControl = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_zoom/index.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_zoom/index.tsx index 406d6b54729b90..b22a9d35aa7935 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_zoom/index.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_zoom/index.tsx @@ -33,9 +33,6 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ }); export const WorkpadZoom = compose( - connect( - mapStateToProps, - mapDispatchToProps - ), + connect(mapStateToProps, mapDispatchToProps), withHandlers(zoomHandlerCreators) )(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_page/integration_utils.js b/x-pack/legacy/plugins/canvas/public/components/workpad_page/integration_utils.js index 34c3d446c5ca7d..731656dd4e0950 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_page/integration_utils.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_page/integration_utils.js @@ -135,7 +135,12 @@ export const globalStateUpdater = (dispatch, globalState) => state => { if (elementsToRemove.length) { // remove elements for groups that were ungrouped - dispatch(removeElements(elementsToRemove.map(e => e.id), page)); + dispatch( + removeElements( + elementsToRemove.map(e => e.id), + page + ) + ); } // set the selected element on the global store, if one element is selected diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js index 454fa6f917aec9..4ee3a65172a2ed 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/index.js @@ -161,11 +161,7 @@ const mergeProps = ( }); export const InteractivePage = compose( - connect( - mapStateToProps, - mapDispatchToProps, - mergeProps - ), + connect(mapStateToProps, mapDispatchToProps, mergeProps), withState('aeroStore', 'setAeroStore'), withProps(componentLayoutState), withProps(({ aeroStore, updateGlobalState }) => ({ diff --git a/x-pack/legacy/plugins/canvas/public/expression_types/arg_types/font.js b/x-pack/legacy/plugins/canvas/public/expression_types/arg_types/font.js index 893caba1465b8b..46a97f7c15d74f 100644 --- a/x-pack/legacy/plugins/canvas/public/expression_types/arg_types/font.js +++ b/x-pack/legacy/plugins/canvas/public/expression_types/arg_types/font.js @@ -24,7 +24,11 @@ export const FontArgInput = props => { const spec = mapValues(chainArgs, '[0]'); function handleChange(newSpec) { - const newValue = set(argValue, ['chain', 0, 'arguments'], mapValues(newSpec, v => [v])); + const newValue = set( + argValue, + ['chain', 0, 'arguments'], + mapValues(newSpec, v => [v]) + ); return onValueChange(newValue); } diff --git a/x-pack/legacy/plugins/canvas/public/lib/aeroelastic/layout_functions.js b/x-pack/legacy/plugins/canvas/public/lib/aeroelastic/layout_functions.js index 4b99a5ef298d89..d3da1b55539587 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/aeroelastic/layout_functions.js +++ b/x-pack/legacy/plugins/canvas/public/lib/aeroelastic/layout_functions.js @@ -62,17 +62,46 @@ const resizeVertexTuples = [ ]; const connectorVertices = [ - [[-1, -1], [0, -1]], - [[0, -1], [1, -1]], - [[1, -1], [1, 0]], - [[1, 0], [1, 1]], - [[1, 1], [0, 1]], - [[0, 1], [-1, 1]], - [[-1, 1], [-1, 0]], - [[-1, 0], [-1, -1]], + [ + [-1, -1], + [0, -1], + ], + [ + [0, -1], + [1, -1], + ], + [ + [1, -1], + [1, 0], + ], + [ + [1, 0], + [1, 1], + ], + [ + [1, 1], + [0, 1], + ], + [ + [0, 1], + [-1, 1], + ], + [ + [-1, 1], + [-1, 0], + ], + [ + [-1, 0], + [-1, -1], + ], ]; -const cornerVertices = [[-1, -1], [1, -1], [-1, 1], [1, 1]]; +const cornerVertices = [ + [-1, -1], + [1, -1], + [-1, 1], + [1, 1], +]; const resizeMultiplierHorizontal = { left: -1, center: 0, right: 1 }; const resizeMultiplierVertical = { top: -1, center: 0, bottom: 1 }; @@ -91,7 +120,10 @@ const bidirectionalCursors = { '315': 'nwse-resize', }; -const identityAABB = () => [[Infinity, Infinity], [-Infinity, -Infinity]]; +const identityAABB = () => [ + [Infinity, Infinity], + [-Infinity, -Infinity], +]; const extend = ([[xMin, yMin], [xMax, yMax]], [x0, y0], [x1, y1]) => [ [Math.min(xMin, x0, x1), Math.min(yMin, y0, y1)], @@ -547,14 +579,18 @@ export const applyLocalTransforms = (shapes, transformIntents) => { // eslint-disable-next-line const getUpstreamTransforms = (shapes, shape) => shape.parent - ? getUpstreamTransforms(shapes, shapes.find(s => s.id === shape.parent)).concat([ - shape.localTransformMatrix, - ]) + ? getUpstreamTransforms( + shapes, + shapes.find(s => s.id === shape.parent) + ).concat([shape.localTransformMatrix]) : [shape.localTransformMatrix]; const getUpstreams = (shapes, shape) => shape.parent - ? getUpstreams(shapes, shapes.find(s => s.id === shape.parent)).concat([shape]) + ? getUpstreams( + shapes, + shapes.find(s => s.id === shape.parent) + ).concat([shape]) : [shape]; const snappedA = shape => shape.a + (shape.snapResizeVector ? shape.snapResizeVector[0] : 0); @@ -877,7 +913,12 @@ function resizeAnnotation(config, shapes, selectedShapes, shape) { const b = snappedB(properShape); const allowResize = properShape.type !== 'group' || - (config.groupResize && magic(config, properShape, shapes.filter(s => s.type !== 'annotation'))); + (config.groupResize && + magic( + config, + properShape, + shapes.filter(s => s.type !== 'annotation') + )); const resizeVertices = allowResize ? resizeVertexTuples : []; const resizePoints = resizeVertices.map(resizePointAnnotations(config, shape, a, b)); const connectors = connectorVertices.map(resizeEdgeAnnotations(config, shape, a, b)); @@ -1235,7 +1276,10 @@ export const getGrouping = (config, shapes, selectedShapes, groupAction, tuple) return config.groupResize ? { shapes: [ - ...resizeGroup(shapes.filter(s => s.type !== 'annotation'), elements[0]), + ...resizeGroup( + shapes.filter(s => s.type !== 'annotation'), + elements[0] + ), ...shapes.filter(s => s.type === 'annotation'), ], selectedShapes, diff --git a/x-pack/legacy/plugins/canvas/public/state/actions/elements.js b/x-pack/legacy/plugins/canvas/public/state/actions/elements.js index 1005cc60e50ba3..7b7e87b027af53 100644 --- a/x-pack/legacy/plugins/canvas/public/state/actions/elements.js +++ b/x-pack/legacy/plugins/canvas/public/state/actions/elements.js @@ -227,9 +227,12 @@ export const removeElements = createThunk( // todo consider doing the group membership collation in aeroelastic, or the Redux reducer, when adding templates const allElements = getNodes(state, pageId); const allRoots = rootElementIds.map(id => allElements.find(e => id === e.id)).filter(d => d); - const elementIds = subMultitree(e => e.id, e => e.position.parent, allElements, allRoots).map( - e => e.id - ); + const elementIds = subMultitree( + e => e.id, + e => e.position.parent, + allElements, + allRoots + ).map(e => e.id); const shouldRefresh = elementIds.some(elementId => { const element = getNodeById(state, elementId, pageId); diff --git a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.ts b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.ts index 87b33cbe35f82c..d7df3513dba8d2 100644 --- a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.ts +++ b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.ts @@ -95,9 +95,11 @@ export async function fetchTopNodes( .reduce((allAggs, subAgg) => ({ ...allAggs, ...subAgg })); const body = createSamplerSearchBody(aggs); - const response: TopTermsAggResponse = (await post('../api/graph/searchProxy', { - body: JSON.stringify({ index, body }), - })).resp; + const response: TopTermsAggResponse = ( + await post('../api/graph/searchProxy', { + body: JSON.stringify({ index, body }), + }) + ).resp; const nodes: ServerResultNode[] = []; diff --git a/x-pack/legacy/plugins/graph/public/state_management/fields.ts b/x-pack/legacy/plugins/graph/public/state_management/fields.ts index 62bb62c1f6125c..865de323332c46 100644 --- a/x-pack/legacy/plugins/graph/public/state_management/fields.ts +++ b/x-pack/legacy/plugins/graph/public/state_management/fields.ts @@ -51,17 +51,12 @@ export const fieldsReducer = reducerWithInitialState(initialFields) .build(); export const fieldMapSelector = (state: GraphState) => state.fields; -export const fieldsSelector = createSelector( - fieldMapSelector, - fields => Object.values(fields) +export const fieldsSelector = createSelector(fieldMapSelector, fields => Object.values(fields)); +export const selectedFieldsSelector = createSelector(fieldsSelector, fields => + fields.filter(field => field.selected) ); -export const selectedFieldsSelector = createSelector( - fieldsSelector, - fields => fields.filter(field => field.selected) -); -export const liveResponseFieldsSelector = createSelector( - selectedFieldsSelector, - fields => fields.filter(field => field.hopSize && field.hopSize > 0) +export const liveResponseFieldsSelector = createSelector(selectedFieldsSelector, fields => + fields.filter(field => field.hopSize && field.hopSize > 0) ); export const hasFieldsSelector = createSelector( selectedFieldsSelector, diff --git a/x-pack/legacy/plugins/infra/common/utility_types.ts b/x-pack/legacy/plugins/infra/common/utility_types.ts index 1d1148f8716a13..93fc9b729ca745 100644 --- a/x-pack/legacy/plugins/infra/common/utility_types.ts +++ b/x-pack/legacy/plugins/infra/common/utility_types.ts @@ -5,10 +5,10 @@ */ export type Pick2 = { - [P1 in K1]: { [P2 in K2]: (T[K1])[P2] }; + [P1 in K1]: { [P2 in K2]: T[K1][P2] }; }; export type Pick3 = { - [P1 in K1]: { [P2 in K2]: { [P3 in K3]: ((T[K1])[K2])[P3] } }; + [P1 in K1]: { [P2 in K2]: { [P3 in K3]: T[K1][K2][P3] } }; }; export type MandatoryProperty = T & diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx index 54147c24ceec0f..255e5b75c13903 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx @@ -302,13 +302,11 @@ const withUnfocused = (state: AutocompleteFieldState) => ({ isFocused: false, }); -const FixedEuiFieldSearch: React.SFC< - React.InputHTMLAttributes & - EuiFieldSearchProps & { - inputRef?: (element: HTMLInputElement | null) => void; - onSearch: (value: string) => void; - } -> = EuiFieldSearch as any; +const FixedEuiFieldSearch: React.SFC & + EuiFieldSearchProps & { + inputRef?: (element: HTMLInputElement | null) => void; + onSearch: (value: string) => void; + }> = EuiFieldSearch as any; const AutocompleteContainer = euiStyled.div` position: relative; diff --git a/x-pack/legacy/plugins/infra/public/components/loading_overlay_wrapper.tsx b/x-pack/legacy/plugins/infra/public/components/loading_overlay_wrapper.tsx index 0f70c40059c932..a99b265fc3ea96 100644 --- a/x-pack/legacy/plugins/infra/public/components/loading_overlay_wrapper.tsx +++ b/x-pack/legacy/plugins/infra/public/components/loading_overlay_wrapper.tsx @@ -10,12 +10,10 @@ import React from 'react'; import { euiStyled } from '../../../../common/eui_styled_components'; -export const LoadingOverlayWrapper: React.FC< - React.HTMLAttributes & { - isLoading: boolean; - loadingChildren?: React.ReactNode; - } -> = ({ children, isLoading, loadingChildren, ...rest }) => { +export const LoadingOverlayWrapper: React.FC & { + isLoading: boolean; + loadingChildren?: React.ReactNode; +}> = ({ children, isLoading, loadingChildren, ...rest }) => { return ( {children} diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_icon_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_icon_column.tsx index f2adc507e7b997..8e55caae738e70 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_icon_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_icon_column.tsx @@ -29,11 +29,9 @@ export const LogEntryIconColumn: React.FunctionComponent void; - } -> = ({ isHighlighted, isHovered, openFlyout }) => { +export const LogEntryDetailsIconColumn: React.FunctionComponent void; +}> = ({ isHighlighted, isHovered, openFlyout }) => { const label = i18n.translate('xpack.infra.logEntryItemView.viewDetailsToolTip', { defaultMessage: 'View Details', }); diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/vertical_scroll_panel.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/vertical_scroll_panel.tsx index dd368ef4d8f925..62db9d517c9d23 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/vertical_scroll_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/vertical_scroll_panel.tsx @@ -80,18 +80,15 @@ export class VerticalScrollPanel extends React.PureComponent< public updateChildDimensions = () => { this.childDimensions = new Map( sortDimensionsByTop( - Array.from(this.childRefs.entries()).reduce( - (accumulatedDimensions, [key, child]) => { - const currentOffsetRect = child.getOffsetRect(); - - if (currentOffsetRect !== null) { - accumulatedDimensions.push([key, currentOffsetRect]); - } - - return accumulatedDimensions; - }, - [] as Array<[any, Rect]> - ) + Array.from(this.childRefs.entries()).reduce((accumulatedDimensions, [key, child]) => { + const currentOffsetRect = child.getOffsetRect(); + + if (currentOffsetRect !== null) { + accumulatedDimensions.push([key, currentOffsetRect]); + } + + return accumulatedDimensions; + }, [] as Array<[any, Rect]>) ) ); }; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts b/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts index bfc1385c0431a2..2e8d6b056caef4 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts @@ -35,17 +35,11 @@ export const getMaxMinTimestamp = (metric: InfraMetricData): [number, number] => if (metric.series.some(seriesHasLessThen2DataPoints)) { return [0, 0]; } - const values = metric.series.reduce( - (acc, item) => { - const firstRow = first(item.data); - const lastRow = last(item.data); - return acc.concat([ - (firstRow && firstRow.timestamp) || 0, - (lastRow && lastRow.timestamp) || 0, - ]); - }, - [] as number[] - ); + const values = metric.series.reduce((acc, item) => { + const firstRow = first(item.data); + const lastRow = last(item.data); + return acc.concat([(firstRow && firstRow.timestamp) || 0, (lastRow && lastRow.timestamp) || 0]); + }, [] as number[]); return [min(values), max(values)]; }; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts index 2f6097a1514fa0..fd18adea3aad0a 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts @@ -13,21 +13,18 @@ export const calculateDomain = ( stacked = false ): { min: number; max: number } => { const values = series.rows - .reduce( - (acc, row) => { - const rowValues = metrics - .map((m, index) => { - return (row[`metric_${index}`] as number) || null; - }) - .filter(v => v); - const minValue = min(rowValues); - // For stacked domains we want to add 10% head room so the charts have - // enough room to draw the 2 pixel line as well. - const maxValue = stacked ? sum(rowValues) * 1.1 : max(rowValues); - return acc.concat([minValue || null, maxValue || null]); - }, - [] as Array - ) + .reduce((acc, row) => { + const rowValues = metrics + .map((m, index) => { + return (row[`metric_${index}`] as number) || null; + }) + .filter(v => v); + const minValue = min(rowValues); + // For stacked domains we want to add 10% head room so the charts have + // enough room to draw the 2 pixel line as well. + const maxValue = stacked ? sum(rowValues) * 1.1 : max(rowValues); + return acc.concat([minValue || null, maxValue || null]); + }, [] as Array) .filter(v => v); return { min: min(values) || 0, max: max(values) || 0 }; }; diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx index 708fd34f23257d..90361a5c2b5419 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx @@ -39,9 +39,13 @@ interface LogColumnsConfigurationPanelProps { moveLogColumn: (sourceIndex: number, destinationIndex: number) => void; } -export const LogColumnsConfigurationPanel: React.FunctionComponent< - LogColumnsConfigurationPanelProps -> = ({ addLogColumn, moveLogColumn, availableFields, isLoading, logColumnConfiguration }) => { +export const LogColumnsConfigurationPanel: React.FunctionComponent = ({ + addLogColumn, + moveLogColumn, + availableFields, + isLoading, + logColumnConfiguration, +}) => { const onDragEnd = useCallback( ({ source, destination }: DropResult) => destination && moveLogColumn(source.index, destination.index), @@ -104,9 +108,7 @@ interface LogColumnConfigurationPanelProps { dragHandleProps: DragHandleProps; } -const LogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = props => ( +const LogColumnConfigurationPanel: React.FunctionComponent = props => ( <> {props.logColumnConfigurationProps.type === 'timestamp' ? ( @@ -122,9 +124,10 @@ const LogColumnConfigurationPanel: React.FunctionComponent< ); -const TimestampLogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = ({ logColumnConfigurationProps, dragHandleProps }) => ( +const TimestampLogColumnConfigurationPanel: React.FunctionComponent = ({ + logColumnConfigurationProps, + dragHandleProps, +}) => ( ); -const MessageLogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = ({ logColumnConfigurationProps, dragHandleProps }) => ( +const MessageLogColumnConfigurationPanel: React.FunctionComponent = ({ + logColumnConfigurationProps, + dragHandleProps, +}) => ( { endTime: 'now', }, decodeUrlState: (value: unknown) => - pipe( - urlTimeRangeRT.decode(value), - fold(constant(undefined), identity) - ), + pipe(urlTimeRangeRT.decode(value), fold(constant(undefined), identity)), encodeUrlState: urlTimeRangeRT.encode, urlStateKey: TIME_RANGE_URL_STATE_KEY, }); @@ -55,10 +52,7 @@ export const useLogAnalysisResultsUrlState = () => { interval: 30000, }, decodeUrlState: (value: unknown) => - pipe( - autoRefreshRT.decode(value), - fold(constant(undefined), identity) - ), + pipe(autoRefreshRT.decode(value), fold(constant(undefined), identity)), encodeUrlState: autoRefreshRT.encode, urlStateKey: AUTOREFRESH_URL_STATE_KEY, }); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx index 927ce4c3e1f589..1f4c924ea3da58 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx @@ -308,9 +308,10 @@ const getSetupStatus = ( } else if ( setupStatus === 'skippedButUpdatable' || (jobDefinition && - !isJobRevisionCurrent(jobId, jobDefinition.config.custom_settings.job_revision || 0)( - jobSummaries - )) + !isJobRevisionCurrent( + jobId, + jobDefinition.config.custom_settings.job_revision || 0 + )(jobSummaries)) ) { return 'skippedButUpdatable'; } else if ( diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_position.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_position.tsx index bbcec36e17f9d3..075f3904d994c2 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_position.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_position.tsx @@ -110,7 +110,7 @@ const mapToUrlState = (value: any): LogPositionUrlState | undefined => : undefined; const mapToPositionUrlState = (value: any) => - value && (typeof value.time === 'number' && typeof value.tiebreaker === 'number') + value && typeof value.time === 'number' && typeof value.tiebreaker === 'number' ? pickTimeKey(value) : undefined; diff --git a/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts b/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts index 540e32a27b319a..718178ecb4fa20 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts +++ b/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts @@ -22,10 +22,7 @@ export function useMetadata( sourceId: string ) { const decodeResponse = (response: any) => { - return pipe( - InfraMetadataRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return pipe(InfraMetadataRT.decode(response), fold(throwErrors(createPlainError), identity)); }; const { error, loading, response, makeRequest } = useHTTPRequest( diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx b/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx index 95f130878fc52b..67356236ef8f1e 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx @@ -47,12 +47,9 @@ export const WithMetrics = ({ nodeId, cloudId, }: WithMetricsProps) => { - const metrics = layouts.reduce( - (acc, item) => { - return acc.concat(item.sections.map(s => s.id)); - }, - [] as InventoryMetric[] - ); + const metrics = layouts.reduce((acc, item) => { + return acc.concat(item.sections.map(s => s.id)); + }, [] as InventoryMetric[]); if (!isInfraMetrics(metrics)) { throw new Error( diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx index 2d809521dc9e85..d2fa49e8d5d9fc 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx @@ -80,10 +80,9 @@ function isMetricExplorerOptions(subject: any): subject is MetricsExplorerOption const MetricOptional = t.partial({ field: t.string, rate: t.boolean, - color: t.keyof(Object.fromEntries(values(MetricsExplorerColor).map(c => [c, null])) as Record< - string, - null - >), + color: t.keyof( + Object.fromEntries(values(MetricsExplorerColor).map(c => [c, null])) as Record + ), label: t.string, }); @@ -114,12 +113,18 @@ function isMetricExplorerOptions(subject: any): subject is MetricsExplorerOption function isMetricExplorerChartOptions(subject: any): subject is MetricsExplorerChartOptions { const ChartOptions = t.type({ - yAxisMode: t.keyof(Object.fromEntries( - values(MetricsExplorerYAxisMode).map(v => [v, null]) - ) as Record), - type: t.keyof(Object.fromEntries( - values(MetricsExplorerChartType).map(v => [v, null]) - ) as Record), + yAxisMode: t.keyof( + Object.fromEntries(values(MetricsExplorerYAxisMode).map(v => [v, null])) as Record< + string, + null + > + ), + type: t.keyof( + Object.fromEntries(values(MetricsExplorerChartType).map(v => [v, null])) as Record< + string, + null + > + ), stack: t.boolean, }); const result = ChartOptions.decode(subject); diff --git a/x-pack/legacy/plugins/infra/public/containers/source_id/source_id.ts b/x-pack/legacy/plugins/infra/public/containers/source_id/source_id.ts index 41be5dd9eee9fa..e4163eed9f61c4 100644 --- a/x-pack/legacy/plugins/infra/public/containers/source_id/source_id.ts +++ b/x-pack/legacy/plugins/infra/public/containers/source_id/source_id.ts @@ -28,7 +28,4 @@ export const replaceSourceIdInQueryString = (sourceId: string) => const sourceIdRuntimeType = runtimeTypes.union([runtimeTypes.string, runtimeTypes.undefined]); const encodeSourceIdUrlState = sourceIdRuntimeType.encode; const decodeSourceIdUrlState = (value: unknown) => - pipe( - sourceIdRuntimeType.decode(value), - fold(constant(undefined), identity) - ); + pipe(sourceIdRuntimeType.decode(value), fold(constant(undefined), identity)); diff --git a/x-pack/legacy/plugins/infra/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/public/lib/adapters/framework/kibana_framework_adapter.ts index 5f763b3199a91e..d70a42473b710c 100644 --- a/x-pack/legacy/plugins/infra/public/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/infra/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -122,16 +122,18 @@ export class InfraKibanaFrameworkAdapter implements InfraFrameworkAdapter { `, })); - adapterModule.run(( - config: InfraKibanaUIConfig, - kbnVersion: string, - Private: (provider: Provider) => Provider, - // @ts-ignore: inject kibanaAdapter to force eager instatiation - kibanaAdapter: any - ) => { - this.timezone = Private(this.timezoneProvider)(); - this.kbnVersion = kbnVersion; - }); + adapterModule.run( + ( + config: InfraKibanaUIConfig, + kbnVersion: string, + Private: (provider: Provider) => Provider, + // @ts-ignore: inject kibanaAdapter to force eager instatiation + kibanaAdapter: any + ) => { + this.timezone = Private(this.timezoneProvider)(); + this.kbnVersion = kbnVersion; + } + ); uiRoutes.enable(); diff --git a/x-pack/legacy/plugins/infra/public/store/local/waffle_time/epic.ts b/x-pack/legacy/plugins/infra/public/store/local/waffle_time/epic.ts index d9c1c825f1a250..986d6b17a24242 100644 --- a/x-pack/legacy/plugins/infra/public/store/local/waffle_time/epic.ts +++ b/x-pack/legacy/plugins/infra/public/store/local/waffle_time/epic.ts @@ -21,10 +21,7 @@ export const createWaffleTimeEpic = (): Epic< State, WaffleTimeEpicDependencies > => (action$, state$, { selectWaffleTimeUpdatePolicyInterval }) => { - const updateInterval$ = state$.pipe( - map(selectWaffleTimeUpdatePolicyInterval), - filter(isNotNull) - ); + const updateInterval$ = state$.pipe(map(selectWaffleTimeUpdatePolicyInterval), filter(isNotNull)); return action$.pipe( filter(startAutoReload.match), diff --git a/x-pack/legacy/plugins/infra/public/store/local/waffle_time/selectors.ts b/x-pack/legacy/plugins/infra/public/store/local/waffle_time/selectors.ts index ec9c0a1584f138..0b6d01bdf52883 100644 --- a/x-pack/legacy/plugins/infra/public/store/local/waffle_time/selectors.ts +++ b/x-pack/legacy/plugins/infra/public/store/local/waffle_time/selectors.ts @@ -16,11 +16,8 @@ export const selectIsAutoReloading = (state: WaffleTimeState) => export const selectTimeUpdatePolicyInterval = (state: WaffleTimeState) => state.updatePolicy.policy === 'interval' ? state.updatePolicy.interval : null; -export const selectCurrentTimeRange = createSelector( - selectCurrentTime, - currentTime => ({ - from: currentTime - 1000 * 60 * 5, - interval: '1m', - to: currentTime, - }) -); +export const selectCurrentTimeRange = createSelector(selectCurrentTime, currentTime => ({ + from: currentTime - 1000 * 60 * 5, + interval: '1m', + to: currentTime, +})); diff --git a/x-pack/legacy/plugins/infra/public/store/remote/log_entries/selectors.ts b/x-pack/legacy/plugins/infra/public/store/remote/log_entries/selectors.ts index 7520803f93ac70..0306efc334a514 100644 --- a/x-pack/legacy/plugins/infra/public/store/remote/log_entries/selectors.ts +++ b/x-pack/legacy/plugins/infra/public/store/remote/log_entries/selectors.ts @@ -11,9 +11,8 @@ import { LogEntriesRemoteState } from './state'; const entriesGraphlStateSelectors = createGraphqlStateSelectors(); -export const selectEntries = createSelector( - entriesGraphlStateSelectors.selectData, - data => (data ? data.entries : []) +export const selectEntries = createSelector(entriesGraphlStateSelectors.selectData, data => + data ? data.entries : [] ); export const selectIsLoadingEntries = entriesGraphlStateSelectors.selectIsLoading; @@ -32,14 +31,12 @@ export const selectIsLoadingMoreEntries = createSelector( isLoading && operationInfo ? operationInfo.operationKey === 'load_more' : false ); -export const selectEntriesStart = createSelector( - entriesGraphlStateSelectors.selectData, - data => (data && data.start ? data.start : null) +export const selectEntriesStart = createSelector(entriesGraphlStateSelectors.selectData, data => + data && data.start ? data.start : null ); -export const selectEntriesEnd = createSelector( - entriesGraphlStateSelectors.selectData, - data => (data && data.end ? data.end : null) +export const selectEntriesEnd = createSelector(entriesGraphlStateSelectors.selectData, data => + data && data.end ? data.end : null ); export const selectHasMoreBeforeStart = createSelector( @@ -47,9 +44,8 @@ export const selectHasMoreBeforeStart = createSelector( data => (data ? data.hasMoreBefore : true) ); -export const selectHasMoreAfterEnd = createSelector( - entriesGraphlStateSelectors.selectData, - data => (data ? data.hasMoreAfter : true) +export const selectHasMoreAfterEnd = createSelector(entriesGraphlStateSelectors.selectData, data => + data ? data.hasMoreAfter : true ); export const selectEntriesLastLoadedTime = entriesGraphlStateSelectors.selectLoadingResultTime; @@ -58,14 +54,12 @@ export const selectEntriesStartLoadingState = entriesGraphlStateSelectors.select export const selectEntriesEndLoadingState = entriesGraphlStateSelectors.selectLoadingState; -export const selectFirstEntry = createSelector( - selectEntries, - entries => (entries.length > 0 ? entries[0] : null) +export const selectFirstEntry = createSelector(selectEntries, entries => + entries.length > 0 ? entries[0] : null ); -export const selectLastEntry = createSelector( - selectEntries, - entries => (entries.length > 0 ? entries[entries.length - 1] : null) +export const selectLastEntry = createSelector(selectEntries, entries => + entries.length > 0 ? entries[entries.length - 1] : null ); export const selectLoadedEntriesTimeInterval = createSelector( diff --git a/x-pack/legacy/plugins/infra/public/utils/is_displayable.ts b/x-pack/legacy/plugins/infra/public/utils/is_displayable.ts index f79ce792cac3d6..6af6bce3155993 100644 --- a/x-pack/legacy/plugins/infra/public/utils/is_displayable.ts +++ b/x-pack/legacy/plugins/infra/public/utils/is_displayable.ts @@ -19,12 +19,9 @@ export const isDisplayable = (field: DisplayableFieldType, additionalPrefixes: s // We need to start with at least one prefix, even if it's empty const prefixes = additionalPrefixes && additionalPrefixes.length ? additionalPrefixes : ['']; // Create a set of allowed list based on the prefixes - const allowedList = prefixes.reduce( - (acc, prefix) => { - return uniq([...acc, ...getAllowedListForPrefix(prefix)]); - }, - [] as string[] - ); + const allowedList = prefixes.reduce((acc, prefix) => { + return uniq([...acc, ...getAllowedListForPrefix(prefix)]); + }, [] as string[]); // If the field is displayable and part of the allowed list or covered by the prefix return ( (field.displayable && prefixes.some(fieldStartsWith(field))) || diff --git a/x-pack/legacy/plugins/infra/public/utils/remote_state/remote_graphql_state.ts b/x-pack/legacy/plugins/infra/public/utils/remote_state/remote_graphql_state.ts index 9735b1e1cb8393..0cbc94516617b2 100644 --- a/x-pack/legacy/plugins/infra/public/utils/remote_state/remote_graphql_state.ts +++ b/x-pack/legacy/plugins/infra/public/utils/remote_state/remote_graphql_state.ts @@ -165,52 +165,25 @@ export const createGraphqlQueryEpic = ( export const createGraphqlStateSelectors = ( selectState: (parentState: any) => GraphqlState = parentState => parentState ) => { - const selectData = createSelector( - selectState, - state => state.data - ); + const selectData = createSelector(selectState, state => state.data); - const selectLoadingProgress = createSelector( - selectState, - state => state.current - ); - const selectLoadingProgressOperationInfo = createSelector( - selectLoadingProgress, - progress => (isRunningLoadingProgress(progress) ? progress.parameters : null) - ); - const selectIsLoading = createSelector( - selectLoadingProgress, - isRunningLoadingProgress - ); - const selectIsIdle = createSelector( - selectLoadingProgress, - isIdleLoadingProgress + const selectLoadingProgress = createSelector(selectState, state => state.current); + const selectLoadingProgressOperationInfo = createSelector(selectLoadingProgress, progress => + isRunningLoadingProgress(progress) ? progress.parameters : null ); + const selectIsLoading = createSelector(selectLoadingProgress, isRunningLoadingProgress); + const selectIsIdle = createSelector(selectLoadingProgress, isIdleLoadingProgress); - const selectLoadingResult = createSelector( - selectState, - state => state.last - ); - const selectLoadingResultOperationInfo = createSelector( - selectLoadingResult, - result => (!isUninitializedLoadingResult(result) ? result.parameters : null) - ); - const selectLoadingResultTime = createSelector( - selectLoadingResult, - result => (!isUninitializedLoadingResult(result) ? result.time : null) - ); - const selectIsUninitialized = createSelector( - selectLoadingResult, - isUninitializedLoadingResult - ); - const selectIsSuccess = createSelector( - selectLoadingResult, - isSuccessLoadingResult + const selectLoadingResult = createSelector(selectState, state => state.last); + const selectLoadingResultOperationInfo = createSelector(selectLoadingResult, result => + !isUninitializedLoadingResult(result) ? result.parameters : null ); - const selectIsFailure = createSelector( - selectLoadingResult, - isFailureLoadingResult + const selectLoadingResultTime = createSelector(selectLoadingResult, result => + !isUninitializedLoadingResult(result) ? result.time : null ); + const selectIsUninitialized = createSelector(selectLoadingResult, isUninitializedLoadingResult); + const selectIsSuccess = createSelector(selectLoadingResult, isSuccessLoadingResult); + const selectIsFailure = createSelector(selectLoadingResult, isFailureLoadingResult); const selectLoadingState = createSelector( selectLoadingProgress, diff --git a/x-pack/legacy/plugins/infra/public/utils/use_kibana_space_id.ts b/x-pack/legacy/plugins/infra/public/utils/use_kibana_space_id.ts index 3a27051755446d..4642f7fd26f21f 100644 --- a/x-pack/legacy/plugins/infra/public/utils/use_kibana_space_id.ts +++ b/x-pack/legacy/plugins/infra/public/utils/use_kibana_space_id.ts @@ -15,7 +15,10 @@ export const useKibanaSpaceId = (): string => { return pipe( activeSpaceRT.decode(activeSpace), - fold(() => 'default', decodedActiveSpace => decodedActiveSpace.space.id) + fold( + () => 'default', + decodedActiveSpace => decodedActiveSpace.space.id + ) ); }; diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts index 179bfef6f1bd81..a6881a05f6f931 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts @@ -115,13 +115,10 @@ export class FrameworkFieldsAdapter implements FieldsAdapter { handleAfterKey ); const dataSets = buckets.map(bucket => bucket.key.dataset); - const modules = dataSets.reduce( - (acc, dataset) => { - const module = first(dataset.split(/\./)); - return module ? uniq([...acc, module]) : acc; - }, - [] as string[] - ); + const modules = dataSets.reduce((acc, dataset) => { + const module = first(dataset.split(/\./)); + return module ? uniq([...acc, module]) : acc; + }, [] as string[]); return { modules, dataSets }; } } diff --git a/x-pack/legacy/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts b/x-pack/legacy/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts index d46ebbb26fbb8e..98d1e2cd89b013 100644 --- a/x-pack/legacy/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts +++ b/x-pack/legacy/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts @@ -17,7 +17,10 @@ describe('convertDocumentSourceToLogItemFields', () => { version: '7.0.0', }, tags: ['prod', 'web'], - metadata: [{ key: 'env', value: 'prod' }, { key: 'stack', value: 'web' }], + metadata: [ + { key: 'env', value: 'prod' }, + { key: 'stack', value: 'web' }, + ], host: { hostname: 'packer-virtualbox-iso-1546820004', name: 'demo-stack-client-01', diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts index 4f51677a04449b..95d5381d44ab20 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts @@ -83,7 +83,10 @@ export const populateSeriesWithTSVBData = ( // MetricsExplorerRow. const timestamps = tsvbResults.custom.series.reduce( (currentTimestamps, tsvbSeries) => - union(currentTimestamps, tsvbSeries.data.map(row => row[0])).sort(), + union( + currentTimestamps, + tsvbSeries.data.map(row => row[0]) + ).sort(), [] as number[] ); // Combine the TSVB series for multiple metrics. diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 31d622c7089a86..157537ad574c1f 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -312,9 +312,9 @@ describe('Lens App', () => { instance.update(); - const handler = instance.findWhere(el => el.prop('onSave')).prop('onSave') as (( + const handler = instance.findWhere(el => el.prop('onSave')).prop('onSave') as ( p: unknown - ) => void); + ) => void; handler(saveProps); } diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/editor_frame/expression_helpers.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/editor_frame/expression_helpers.ts index f03b64295641bd..6b15bc5c2ef300 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/editor_frame/expression_helpers.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/editor_frame/expression_helpers.ts @@ -38,9 +38,13 @@ export function prependDatasourceExpression( if (datasourceExpressions.length === 0 || visualizationExpression === null) { return null; } - const parsedDatasourceExpressions: Array<[string, Ast]> = datasourceExpressions.map( - ([layerId, expr]) => [layerId, typeof expr === 'string' ? fromExpression(expr) : expr] - ); + const parsedDatasourceExpressions: Array<[ + string, + Ast + ]> = datasourceExpressions.map(([layerId, expr]) => [ + layerId, + typeof expr === 'string' ? fromExpression(expr) : expr, + ]); const datafetchExpression: ExpressionFunctionAST = { type: 'function', diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/embeddable/embeddable_factory.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/embeddable/embeddable_factory.ts index 9ad6864b64853a..79cea1fb58cc61 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/embeddable/embeddable_factory.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/embeddable/embeddable_factory.ts @@ -81,8 +81,10 @@ export class EmbeddableFactory extends AbstractEmbeddableFactory { } } ); - const indexPatterns = (await Promise.all(promises)).filter( - (indexPattern: IndexPattern | null): indexPattern is IndexPattern => Boolean(indexPattern) + const indexPatterns = ( + await Promise.all(promises) + ).filter((indexPattern: IndexPattern | null): indexPattern is IndexPattern => + Boolean(indexPattern) ); return new Embeddable( diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts index 03ba2e5b84d931..c74b729e4fb7e0 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts @@ -11,14 +11,26 @@ describe('lens_merge_tables', () => { it('should produce a row with the nested table as defined', () => { const sampleTable1: KibanaDatatable = { type: 'kibana_datatable', - columns: [{ id: 'bucket', name: 'A' }, { id: 'count', name: 'Count' }], - rows: [{ bucket: 'a', count: 5 }, { bucket: 'b', count: 10 }], + columns: [ + { id: 'bucket', name: 'A' }, + { id: 'count', name: 'Count' }, + ], + rows: [ + { bucket: 'a', count: 5 }, + { bucket: 'b', count: 10 }, + ], }; const sampleTable2: KibanaDatatable = { type: 'kibana_datatable', - columns: [{ id: 'bucket', name: 'C' }, { id: 'avg', name: 'Average' }], - rows: [{ bucket: 'a', avg: 2.5 }, { bucket: 'b', avg: 9 }], + columns: [ + { id: 'bucket', name: 'C' }, + { id: 'avg', name: 'Average' }, + ], + rows: [ + { bucket: 'a', avg: 2.5 }, + { bucket: 'b', avg: 9 }, + ], }; expect( diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/popover_editor.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/popover_editor.tsx index 0555787ec840dc..c44d63b01c1b3f 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/popover_editor.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/popover_editor.tsx @@ -269,7 +269,8 @@ export function PopoverEditor(props: PopoverEditorProps) { if ( !incompatibleSelectedOperationType && selectedColumn && - ('field' in choice && choice.operationType === selectedColumn.operationType) + 'field' in choice && + choice.operationType === selectedColumn.operationType ) { // If we just changed the field are not in an error state and the operation didn't change, // we use the operations onFieldChange method to calculate the new column. diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.ts index d83777b758da63..40d9d25869c7a7 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.ts @@ -75,9 +75,9 @@ export async function loadIndexPatterns({ return resp.savedObjects.reduce( (acc, savedObject) => { - const indexPattern = fromSavedObject(savedObject as SimpleSavedObject< - SavedIndexPatternAttributes - >); + const indexPattern = fromSavedObject( + savedObject as SimpleSavedObject + ); acc[indexPattern.id] = indexPattern; return acc; }, @@ -263,13 +263,10 @@ export async function syncExistingFields({ } function booleanMap(keys: string[]) { - return keys.reduce( - (acc, key) => { - acc[key] = true; - return acc; - }, - {} as Record - ); + return keys.reduce((acc, key) => { + acc[key] = true; + return acc; + }, {} as Record); } function isSingleEmptyLayer(layerMap: IndexPatternPrivateState['layers']) { diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/index.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/index.ts index 6456250157148a..9ad3fb679471e6 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/index.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/index.ts @@ -162,14 +162,14 @@ type ColumnFromOperationDefinition = D extends OperationDefinition ? * typeguards possible that consider all available column types. */ export type IndexPatternColumn = ColumnFromOperationDefinition< - (typeof internalOperationDefinitions)[number] + typeof internalOperationDefinitions[number] >; /** * A union type of all available operation types. The operation type is a unique id of an operation. * Each column is assigned to exactly one operation type. */ -export type OperationType = (typeof internalOperationDefinitions)[number]['type']; +export type OperationType = typeof internalOperationDefinitions[number]['type']; /** * This is an operation definition of an unspecified column out of all possible diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/rename_columns.test.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/rename_columns.test.ts index 61823fd09c9677..9147483247c2e2 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/rename_columns.test.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/rename_columns.test.ts @@ -11,8 +11,16 @@ describe('rename_columns', () => { it('should rename columns of a given datatable', () => { const input: KibanaDatatable = { type: 'kibana_datatable', - columns: [{ id: 'a', name: 'A' }, { id: 'b', name: 'B' }], - rows: [{ a: 1, b: 2 }, { a: 3, b: 4 }, { a: 5, b: 6 }, { a: 7, b: 8 }], + columns: [ + { id: 'a', name: 'A' }, + { id: 'b', name: 'B' }, + ], + rows: [ + { a: 1, b: 2 }, + { a: 3, b: 4 }, + { a: 5, b: 6 }, + { a: 7, b: 8 }, + ], }; const idMap = { @@ -83,8 +91,16 @@ describe('rename_columns', () => { it('should keep columns which are not mapped', () => { const input: KibanaDatatable = { type: 'kibana_datatable', - columns: [{ id: 'a', name: 'A' }, { id: 'b', name: 'B' }], - rows: [{ a: 1, b: 2 }, { a: 3, b: 4 }, { a: 5, b: 6 }, { a: 7, b: 8 }], + columns: [ + { id: 'a', name: 'A' }, + { id: 'b', name: 'B' }, + ], + rows: [ + { a: 1, b: 2 }, + { a: 3, b: 4 }, + { a: 5, b: 6 }, + { a: 7, b: 8 }, + ], }; const idMap = { @@ -129,8 +145,16 @@ describe('rename_columns', () => { it('should rename date histograms', () => { const input: KibanaDatatable = { type: 'kibana_datatable', - columns: [{ id: 'a', name: 'A' }, { id: 'b', name: 'banana per 30 seconds' }], - rows: [{ a: 1, b: 2 }, { a: 3, b: 4 }, { a: 5, b: 6 }, { a: 7, b: 8 }], + columns: [ + { id: 'a', name: 'A' }, + { id: 'b', name: 'banana per 30 seconds' }, + ], + rows: [ + { a: 1, b: 2 }, + { a: 3, b: 4 }, + { a: 5, b: 6 }, + { a: 7, b: 8 }, + ], }; const idMap = { diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/to_expression.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/to_expression.ts index f4fa9b38627339..96006ae6b6ed16 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/to_expression.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/to_expression.ts @@ -30,18 +30,15 @@ function getExpressionForLayer( return getEsAggsConfig(col, colId); }); - const idMap = columnEntries.reduce( - (currentIdMap, [colId], index) => { - return { - ...currentIdMap, - [`col-${index}-${colId}`]: { - ...columns[colId], - id: colId, - }, - }; - }, - {} as Record - ); + const idMap = columnEntries.reduce((currentIdMap, [colId], index) => { + return { + ...currentIdMap, + [`col-${index}-${colId}`]: { + ...columns[colId], + id: colId, + }, + }; + }, {} as Record); return `esaggs index="${indexPattern.id}" diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization_plugin/metric_expression.test.tsx b/x-pack/legacy/plugins/lens/public/metric_visualization_plugin/metric_expression.test.tsx index f82def178261b0..ba1ac461161b17 100644 --- a/x-pack/legacy/plugins/lens/public/metric_visualization_plugin/metric_expression.test.tsx +++ b/x-pack/legacy/plugins/lens/public/metric_visualization_plugin/metric_expression.test.tsx @@ -17,7 +17,11 @@ function sampleArgs() { tables: { l1: { type: 'kibana_datatable', - columns: [{ id: 'a', name: 'a' }, { id: 'b', name: 'b' }, { id: 'c', name: 'c' }], + columns: [ + { id: 'a', name: 'a' }, + { id: 'b', name: 'b' }, + { id: 'c', name: 'c' }, + ], rows: [{ a: 10110, b: 2, c: 3 }], }, }, diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization_plugin/xy_expression.test.tsx b/x-pack/legacy/plugins/lens/public/xy_visualization_plugin/xy_expression.test.tsx index 31f1870ee54b49..9b6dcfa8d0f56f 100644 --- a/x-pack/legacy/plugins/lens/public/xy_visualization_plugin/xy_expression.test.tsx +++ b/x-pack/legacy/plugins/lens/public/xy_visualization_plugin/xy_expression.test.tsx @@ -28,7 +28,10 @@ function sampleArgs() { { id: 'c', name: 'c', formatHint: { id: 'string' } }, { id: 'd', name: 'ColD', formatHint: { id: 'string' } }, ], - rows: [{ a: 1, b: 2, c: 'I', d: 'Foo' }, { a: 1, b: 5, c: 'J', d: 'Bar' }], + rows: [ + { a: 1, b: 2, c: 'I', d: 'Foo' }, + { a: 1, b: 5, c: 'J', d: 'Bar' }, + ], }, }, }; diff --git a/x-pack/legacy/plugins/ml/common/util/es_utils.ts b/x-pack/legacy/plugins/ml/common/util/es_utils.ts index c52b99c350e38a..bed7ba8bc77367 100644 --- a/x-pack/legacy/plugins/ml/common/util/es_utils.ts +++ b/x-pack/legacy/plugins/ml/common/util/es_utils.ts @@ -33,7 +33,8 @@ export function isValidIndexName(indexName: string) { // Cannot start with -, _, + /^[^-_\+]+$/.test(indexName.charAt(0)) && // Cannot be . or .. - (indexName !== '.' && indexName !== '..') && + indexName !== '.' && + indexName !== '..' && // Cannot be longer than 255 bytes (note it is bytes, // so multi-byte characters will count towards the 255 limit faster) isValidIndexNameLength(indexName) diff --git a/x-pack/legacy/plugins/ml/public/components/annotations/annotation_flyout/index.tsx b/x-pack/legacy/plugins/ml/public/components/annotations/annotation_flyout/index.tsx index 5086b29a857250..586e503632eb92 100644 --- a/x-pack/legacy/plugins/ml/public/components/annotations/annotation_flyout/index.tsx +++ b/x-pack/legacy/plugins/ml/public/components/annotations/annotation_flyout/index.tsx @@ -344,6 +344,7 @@ class AnnotationFlyoutIntl extends Component { - const item = dataFrameAnalytics.find(analytics => analytics.config.id === analyticsId); - if (item !== undefined) { - m[analyticsId] = ; - } - return m; - }, - {} as ItemIdToExpandedRowMap - ); + return itemIds.reduce((m: ItemIdToExpandedRowMap, analyticsId: DataFrameAnalyticsId) => { + const item = dataFrameAnalytics.find(analytics => analytics.config.id === analyticsId); + if (item !== undefined) { + m[analyticsId] = ; + } + return m; + }, {} as ItemIdToExpandedRowMap); } function stringMatch(str: string | undefined, substr: string) { diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/page.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/page.tsx index 9123858eef4e54..0e72bf41f177b4 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/page.tsx +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/page.tsx @@ -403,7 +403,8 @@ export const Page: FC = () => { let allMetricFields = indexPatternFields.filter(f => { return ( f.type === KBN_FIELD_TYPES.NUMBER && - (f.displayName !== undefined && dataLoader.isDisplayField(f.displayName) === true) + f.displayName !== undefined && + dataLoader.isDisplayField(f.displayName) === true ); }); if (metricFieldQuery !== undefined) { @@ -477,7 +478,8 @@ export const Page: FC = () => { allNonMetricFields = indexPatternFields.filter(f => { return ( f.type !== KBN_FIELD_TYPES.NUMBER && - (f.displayName !== undefined && dataLoader.isDisplayField(f.displayName) === true) + f.displayName !== undefined && + dataLoader.isDisplayField(f.displayName) === true ); }); } else { diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts index 59a33db1da2e93..eb2f50b8e92509 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts @@ -49,7 +49,10 @@ export function newJobLineChartProvider(callWithRequest: callWithRequestType) { ); const results = await callWithRequest('search', json); - return processSearchResults(results, aggFieldNamePairs.map(af => af.field)); + return processSearchResults( + results, + aggFieldNamePairs.map(af => af.field) + ); } return { diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/population_chart.ts b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/population_chart.ts index 69a0472800bf65..812a135f6cf08a 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/population_chart.ts +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/population_chart.ts @@ -54,7 +54,10 @@ export function newJobPopulationChartProvider(callWithRequest: callWithRequestTy try { const results = await callWithRequest('search', json); - return processSearchResults(results, aggFieldNamePairs.map(af => af.field)); + return processSearchResults( + results, + aggFieldNamePairs.map(af => af.field) + ); } catch (error) { return { error }; } diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/create_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/create_job.ts index b1713e1753eea2..f9542279f52d92 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/create_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/create_job.ts @@ -34,6 +34,6 @@ function createJobFn(server: ServerFacade) { }; } -export const createJobFactory: CreateJobFactory = oncePerServer(createJobFn as ( - server: ServerFacade -) => ESQueueCreateJobFnDiscoverCsv); +export const createJobFactory: CreateJobFactory = oncePerServer( + createJobFn as (server: ServerFacade) => ESQueueCreateJobFnDiscoverCsv +); diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/create_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/server/create_job/index.ts index 4176a1351d6542..f1008a4866fd70 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/create_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/create_job/index.ts @@ -40,6 +40,6 @@ function createJobFn(server: ServerFacade) { }; } -export const createJobFactory: CreateJobFactory = oncePerServer(createJobFn as ( - server: ServerFacade -) => ESQueueCreateJobFnPNG); +export const createJobFactory: CreateJobFactory = oncePerServer( + createJobFn as (server: ServerFacade) => ESQueueCreateJobFnPNG +); diff --git a/x-pack/legacy/plugins/reporting/server/browsers/safe_child_process.ts b/x-pack/legacy/plugins/reporting/server/browsers/safe_child_process.ts index 72bd3c47ead35b..e22d3662a33b47 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/safe_child_process.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/safe_child_process.ts @@ -22,10 +22,7 @@ export function safeChildProcess( Rx.fromEvent(process as NodeJS.EventEmitter, 'SIGTERM').pipe(mapTo('SIGTERM')), Rx.fromEvent(process as NodeJS.EventEmitter, 'SIGINT').pipe(mapTo('SIGINT')), Rx.fromEvent(process as NodeJS.EventEmitter, 'SIGBREAK').pipe(mapTo('SIGBREAK')) - ).pipe( - take(1), - share() - ); + ).pipe(take(1), share()); const ownTerminateMapToKill$ = ownTerminateSignal$.pipe( tap(signal => { diff --git a/x-pack/legacy/plugins/searchprofiler/public/np_ready/application/components/profile_tree/init_data.ts b/x-pack/legacy/plugins/searchprofiler/public/np_ready/application/components/profile_tree/init_data.ts index d7990b1204b217..642b2b741abf05 100644 --- a/x-pack/legacy/plugins/searchprofiler/public/np_ready/application/components/profile_tree/init_data.ts +++ b/x-pack/legacy/plugins/searchprofiler/public/np_ready/application/components/profile_tree/init_data.ts @@ -105,10 +105,4 @@ export const normalize = (target: Targets) => (data: IndexMap) => }); export const initDataFor = (target: Targets) => - flow( - initShards, - calculateShardValues(target), - initIndices, - normalize(target), - sortIndices - ); + flow(initShards, calculateShardValues(target), initIndices, normalize(target), sortIndices); diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx index 1025a340b2d86c..37ee43c5473b0d 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx @@ -61,26 +61,23 @@ const getTableFromComponent = ( const table = component.find(EuiInMemoryTable); const rows = table.find('tr'); const dataRows = rows.slice(1); - return dataRows.reduce( - (acc, row) => { - const cells = row.find('td'); - const spacesCell = cells.at(0); - const spacesBadge = spacesCell.find(EuiBadge); - const privilegesCell = cells.at(1); - const privilegesDisplay = privilegesCell.find(PrivilegeDisplay); - return [ - ...acc, - { - spaces: spacesBadge.map(badge => badge.text().trim()), - privileges: { - summary: privilegesDisplay.text().trim(), - overridden: privilegesDisplay.find(EuiIconTip).exists('[type="lock"]'), - }, + return dataRows.reduce((acc, row) => { + const cells = row.find('td'); + const spacesCell = cells.at(0); + const spacesBadge = spacesCell.find(EuiBadge); + const privilegesCell = cells.at(1); + const privilegesDisplay = privilegesCell.find(PrivilegeDisplay); + return [ + ...acc, + { + spaces: spacesBadge.map(badge => badge.text().trim()), + privileges: { + summary: privilegesDisplay.text().trim(), + overridden: privilegesDisplay.find(EuiIconTip).exists('[type="lock"]'), }, - ]; - }, - [] as TableRow[] - ); + }, + ]; + }, [] as TableRow[]); }; describe('only global', () => { diff --git a/x-pack/legacy/plugins/siem/common/utility_types.ts b/x-pack/legacy/plugins/siem/common/utility_types.ts index 619ccc7e408fc7..c7bbdbfccf0822 100644 --- a/x-pack/legacy/plugins/siem/common/utility_types.ts +++ b/x-pack/legacy/plugins/siem/common/utility_types.ts @@ -7,7 +7,7 @@ import { ReactNode } from 'react'; export type Pick3 = { - [P1 in K1]: { [P2 in K2]: { [P3 in K3]: ((T[K1])[K2])[P3] } }; + [P1 in K1]: { [P2 in K2]: { [P3 in K3]: T[K1][K2][P3] } }; }; export type Omit = Pick>; diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx index 8770048b5b0e82..408743d2617971 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx @@ -307,14 +307,11 @@ const withUnfocused = (state: AutocompleteFieldState) => ({ isFocused: false, }); -export const FixedEuiFieldSearch: React.SFC< - React.InputHTMLAttributes & - EuiFieldSearchProps & { - inputRef?: (element: HTMLInputElement | null) => void; - onSearch: (value: string) => void; - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -> = EuiFieldSearch as any; +export const FixedEuiFieldSearch: React.SFC & + EuiFieldSearchProps & { + inputRef?: (element: HTMLInputElement | null) => void; + onSearch: (value: string) => void; + }> = EuiFieldSearch as any; // eslint-disable-line @typescript-eslint/no-explicit-any const AutocompleteContainer = euiStyled.div` position: relative; diff --git a/x-pack/legacy/plugins/siem/public/components/charts/chart_place_holder.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/chart_place_holder.test.tsx index 7674fd09739f5e..4050b4f9d70a87 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/chart_place_holder.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/chart_place_holder.test.tsx @@ -15,24 +15,36 @@ describe('ChartPlaceHolder', () => { { key: 'mockKeyA', color: 'mockColor', - value: [{ x: 'a', y: 0 }, { x: 'b', y: 0 }], + value: [ + { x: 'a', y: 0 }, + { x: 'b', y: 0 }, + ], }, { key: 'mockKeyB', color: 'mockColor', - value: [{ x: 'a', y: 0 }, { x: 'b', y: 0 }], + value: [ + { x: 'a', y: 0 }, + { x: 'b', y: 0 }, + ], }, ]; const mockDataUnexpectedValue = [ { key: 'mockKeyA', color: 'mockColor', - value: [{ x: 'a', y: '' }, { x: 'b', y: 0 }], + value: [ + { x: 'a', y: '' }, + { x: 'b', y: 0 }, + ], }, { key: 'mockKeyB', color: 'mockColor', - value: [{ x: 'a', y: {} }, { x: 'b', y: 0 }], + value: [ + { x: 'a', y: {} }, + { x: 'b', y: 0 }, + ], }, ]; diff --git a/x-pack/legacy/plugins/siem/public/components/charts/common.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/common.test.tsx index 0fc7bc6afc2161..e069c1a8b8be72 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/common.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/common.test.tsx @@ -109,20 +109,70 @@ describe('getChartWidth', () => { describe('checkIfAllValuesAreZero', () => { const mockInvalidDataSets: Array<[ChartSeriesData[]]> = [ - [[{ key: 'mockKey', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 1 }] }]], [ [ - { key: 'mockKeyA', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 1 }] }, - { key: 'mockKeyB', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 0 }] }, + { + key: 'mockKey', + color: 'mockColor', + value: [ + { x: 1, y: 0 }, + { x: 1, y: 1 }, + ], + }, + ], + ], + [ + [ + { + key: 'mockKeyA', + color: 'mockColor', + value: [ + { x: 1, y: 0 }, + { x: 1, y: 1 }, + ], + }, + { + key: 'mockKeyB', + color: 'mockColor', + value: [ + { x: 1, y: 0 }, + { x: 1, y: 0 }, + ], + }, ], ], ]; const mockValidDataSets: Array<[ChartSeriesData[]]> = [ - [[{ key: 'mockKey', color: 'mockColor', value: [{ x: 0, y: 0 }, { x: 1, y: 0 }] }]], [ [ - { key: 'mockKeyA', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 3, y: 0 }] }, - { key: 'mockKeyB', color: 'mockColor', value: [{ x: 2, y: 0 }, { x: 4, y: 0 }] }, + { + key: 'mockKey', + color: 'mockColor', + value: [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + ], + }, + ], + ], + [ + [ + { + key: 'mockKeyA', + color: 'mockColor', + value: [ + { x: 1, y: 0 }, + { x: 3, y: 0 }, + ], + }, + { + key: 'mockKeyB', + color: 'mockColor', + value: [ + { x: 2, y: 0 }, + { x: 4, y: 0 }, + ], + }, ], ], ]; diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx index b9e32ee8979103..35d54414944f43 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx @@ -230,13 +230,10 @@ const DraggableWrapperComponent = React.memo( DraggableWrapperComponent.displayName = 'DraggableWrapperComponent'; -export const DraggableWrapper = connect( - null, - { - registerProvider: dragAndDropActions.registerProvider, - unRegisterProvider: dragAndDropActions.unRegisterProvider, - } -)(DraggableWrapperComponent); +export const DraggableWrapper = connect(null, { + registerProvider: dragAndDropActions.registerProvider, + unRegisterProvider: dragAndDropActions.unRegisterProvider, +})(DraggableWrapperComponent); /** * Conditionally wraps children in an EuiPortal to ensure drag offsets are correct when dragging diff --git a/x-pack/legacy/plugins/siem/public/components/error_toast_dispatcher/index.tsx b/x-pack/legacy/plugins/siem/public/components/error_toast_dispatcher/index.tsx index 998b90d11a4d8b..3628330fbd4592 100644 --- a/x-pack/legacy/plugins/siem/public/components/error_toast_dispatcher/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/error_toast_dispatcher/index.tsx @@ -58,9 +58,6 @@ const makeMapStateToProps = () => { return (state: State) => getErrorSelector(state); }; -export const ErrorToastDispatcher = connect( - makeMapStateToProps, - { - removeError: appActions.removeError, - } -)(ErrorToastDispatcherComponent); +export const ErrorToastDispatcher = connect(makeMapStateToProps, { + removeError: appActions.removeError, +})(ErrorToastDispatcherComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx index 5681588cb44b71..68ad6c4e796238 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx @@ -205,14 +205,11 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulEventsViewer = connect( - makeMapStateToProps, - { - createTimeline: timelineActions.createTimeline, - deleteEventQuery: inputsActions.deleteOneQuery, - updateItemsPerPage: timelineActions.updateItemsPerPage, - updateSort: timelineActions.updateSort, - removeColumn: timelineActions.removeColumn, - upsertColumn: timelineActions.upsertColumn, - } -)(StatefulEventsViewerComponent); +export const StatefulEventsViewer = connect(makeMapStateToProps, { + createTimeline: timelineActions.createTimeline, + deleteEventQuery: inputsActions.deleteOneQuery, + updateItemsPerPage: timelineActions.updateItemsPerPage, + updateSort: timelineActions.updateSort, + removeColumn: timelineActions.removeColumn, + upsertColumn: timelineActions.upsertColumn, +})(StatefulEventsViewerComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/index.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/index.tsx index 2c8092a3295ad8..3958cd463d56ef 100644 --- a/x-pack/legacy/plugins/siem/public/components/fields_browser/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/index.tsx @@ -214,10 +214,7 @@ export const StatefulFieldsBrowserComponent = React.memo ({ }, }); -export const FlyoutHeader = connect( - makeMapStateToProps, - mapDispatchToProps -)(StatefulFlyoutHeader); +export const FlyoutHeader = connect(makeMapStateToProps, mapDispatchToProps)(StatefulFlyoutHeader); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx index d96d161fc0e80b..aae8f67997156a 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -121,9 +121,6 @@ const mapStateToProps = (state: State, { timelineId }: OwnProps) => { return { dataProviders, show, width }; }; -export const Flyout = connect( - mapStateToProps, - { - showTimeline: timelineActions.showTimeline, - } -)(FlyoutComponent); +export const Flyout = connect(mapStateToProps, { + showTimeline: timelineActions.showTimeline, +})(FlyoutComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx index ba5275ed79aef0..4b5ceb25befa47 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx @@ -179,9 +179,6 @@ const FlyoutPaneComponent = React.memo( FlyoutPaneComponent.displayName = 'FlyoutPaneComponent'; -export const Pane = connect( - null, - { - applyDeltaToWidth: timelineActions.applyDeltaToWidth, - } -)(FlyoutPaneComponent); +export const Pane = connect(null, { + applyDeltaToWidth: timelineActions.applyDeltaToWidth, +})(FlyoutPaneComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx index 7f835e0e937e60..56bd86310acadc 100644 --- a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx @@ -152,9 +152,6 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const InspectButton = connect( - makeMapStateToProps, - { - setIsInspected: inputsActions.setInspectionParameter, - } -)(InspectButtonComponent); +export const InspectButton = connect(makeMapStateToProps, { + setIsInspected: inputsActions.setInspectionParameter, +})(InspectButtonComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/ml/conditional_links/replace_kql_parts.ts b/x-pack/legacy/plugins/siem/public/components/ml/conditional_links/replace_kql_parts.ts index b2b21129f188c0..5907d16e68f57c 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/conditional_links/replace_kql_parts.ts +++ b/x-pack/legacy/plugins/siem/public/components/ml/conditional_links/replace_kql_parts.ts @@ -9,8 +9,5 @@ import { replaceKqlCommasWithOr } from './replace_kql_commas_with_or'; import { removeKqlVariables } from './remove_kql_variables'; export const replaceKQLParts = (kqlQuery: string): string => { - return flow( - replaceKqlCommasWithOr, - removeKqlVariables - )(kqlQuery); + return flow(replaceKqlCommasWithOr, removeKqlVariables)(kqlQuery); }; diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/hooks/use_siem_jobs_helpers.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/hooks/use_siem_jobs_helpers.tsx index 81b7914b81742d..c53407a9f2f03b 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/hooks/use_siem_jobs_helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/hooks/use_siem_jobs_helpers.tsx @@ -123,9 +123,10 @@ export const composeModuleAndInstalledJobs = ( ): SiemJob[] => { const installedJobsIds = installedJobs.map(installedJob => installedJob.id); - return [...installedJobs, ...moduleSiemJobs.filter(mj => !installedJobsIds.includes(mj.id))].sort( - (a, b) => a.id.localeCompare(b.id) - ); + return [ + ...installedJobs, + ...moduleSiemJobs.filter(mj => !installedJobsIds.includes(mj.id)), + ].sort((a, b) => a.id.localeCompare(b.id)); }; /** * Creates a list of SiemJobs by composing JobSummary jobs (installed jobs) and Module diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts b/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts index 0c44b8d44c3177..23cd855cc028ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts @@ -51,9 +51,10 @@ export const getSearch = (tab: SearchNavTab, urlState: TabNavigationProps): stri } return replaceQueryStringInLocation( myLocation, - replaceStateKeyInQueryString(urlKey, urlStateToReplace)( - getQueryStringFromLocation(myLocation) - ) + replaceStateKeyInQueryString( + urlKey, + urlStateToReplace + )(getQueryStringFromLocation(myLocation)) ); }, { diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx index b9b132b4f50a44..c0d11deec94eda 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx @@ -143,13 +143,10 @@ const makeMapStateToProps = () => { }; }; -export const AuthenticationTable = connect( - makeMapStateToProps, - { - updateTableActivePage: hostsActions.updateTableActivePage, - updateTableLimit: hostsActions.updateTableLimit, - } -)(AuthenticationTableComponent); +export const AuthenticationTable = connect(makeMapStateToProps, { + updateTableActivePage: hostsActions.updateTableActivePage, + updateTableLimit: hostsActions.updateTableLimit, +})(AuthenticationTableComponent); const getAuthenticationColumns = (): AuthTableColumns => [ { @@ -339,7 +336,10 @@ export const getAuthenticationColumnsCurated = ( // Columns to exclude from host details pages if (pageType === hostsModel.HostsType.details) { return [i18n.LAST_FAILED_DESTINATION, i18n.LAST_SUCCESSFUL_DESTINATION].reduce((acc, name) => { - acc.splice(acc.findIndex(column => column.name === name), 1); + acc.splice( + acc.findIndex(column => column.name === name), + 1 + ); return acc; }, columns); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx index cdc84c513737d7..502fa0583536a8 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx @@ -209,11 +209,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const HostsTable = connect( - makeMapStateToProps, - { - updateHostsSort: hostsActions.updateHostsSort, - updateTableActivePage: hostsActions.updateTableActivePage, - updateTableLimit: hostsActions.updateTableLimit, - } -)(HostsTableComponent); +export const HostsTable = connect(makeMapStateToProps, { + updateHostsSort: hostsActions.updateHostsSort, + updateTableActivePage: hostsActions.updateTableActivePage, + updateTableLimit: hostsActions.updateTableLimit, +})(HostsTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx index 2f2d84306e25e9..00eec3fe3a754f 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx @@ -139,13 +139,10 @@ const makeMapStateToProps = () => { return (state: State, { type }: OwnProps) => getUncommonProcessesSelector(state, type); }; -export const UncommonProcessTable = connect( - makeMapStateToProps, - { - updateTableActivePage: hostsActions.updateTableActivePage, - updateTableLimit: hostsActions.updateTableLimit, - } -)(UncommonProcessTableComponent); +export const UncommonProcessTable = connect(makeMapStateToProps, { + updateTableActivePage: hostsActions.updateTableActivePage, + updateTableLimit: hostsActions.updateTableLimit, +})(UncommonProcessTableComponent); const getUncommonColumns = (): UncommonProcessTableColumns => [ { @@ -229,7 +226,10 @@ export const getUncommonColumnsCurated = (pageType: HostsType): UncommonProcessT const columns: UncommonProcessTableColumns = getUncommonColumns(); if (pageType === HostsType.details) { return [i18n.HOSTS, i18n.NUMBER_OF_HOSTS].reduce((acc, name) => { - acc.splice(acc.findIndex(column => column.name === name), 1); + acc.splice( + acc.findIndex(column => column.name === name), + 1 + ); return acc; }, columns); } else { diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/flow_target_select_connected/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/flow_target_select_connected/index.tsx index a5e0977ab9eefd..b5e07809f2e125 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/flow_target_select_connected/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/flow_target_select_connected/index.tsx @@ -63,9 +63,6 @@ const makeMapStateToProps = () => { }; }; -export const FlowTargetSelectConnected = connect( - makeMapStateToProps, - { - updateIpDetailsFlowTarget: networkActions.updateIpDetailsFlowTarget, - } -)(FlowTargetSelectComponent); +export const FlowTargetSelectConnected = connect(makeMapStateToProps, { + updateIpDetailsFlowTarget: networkActions.updateIpDetailsFlowTarget, +})(FlowTargetSelectComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx index ac5470ee4f236f..cc7a8956233035 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx @@ -159,9 +159,6 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const NetworkDnsTable = connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } -)(NetworkDnsTableComponent); +export const NetworkDnsTable = connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, +})(NetworkDnsTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx index 71807280ebcb45..e5ad39b814caac 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx @@ -140,10 +140,7 @@ const makeMapStateToProps = () => { }; export const NetworkHttpTable = compose>( - connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } - ) + connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, + }) )(NetworkHttpTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx index 107863e6067dff..15c48ddf32cd67 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx @@ -185,10 +185,7 @@ const makeMapStateToProps = () => { }; export const NetworkTopCountriesTable = compose>( - connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } - ) + connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, + }) )(NetworkTopCountriesTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx index a41b59b3c6528c..b37a3dce808bd7 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx @@ -176,10 +176,7 @@ const makeMapStateToProps = () => { }; export const NetworkTopNFlowTable = compose>( - connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } - ) + connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, + }) )(NetworkTopNFlowTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx index 6adb335839982b..7dd9ca0273c5b8 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx @@ -144,12 +144,9 @@ const makeMapStateToProps = () => { }; export const TlsTable = compose>( - connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } - ) + connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, + }) )(TlsTableComponent); const getSortField = (sortField: TlsSortField): SortingBasicTable => ({ diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx index ce1376d753f708..8da41fca8f3841 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx @@ -145,12 +145,9 @@ const makeMapStateToProps = () => { }); }; -export const UsersTable = connect( - makeMapStateToProps, - { - updateNetworkTable: networkActions.updateNetworkTable, - } -)(UsersTableComponent); +export const UsersTable = connect(makeMapStateToProps, { + updateNetworkTable: networkActions.updateNetworkTable, +})(UsersTableComponent); const getSortField = (sortField: UsersSortField): SortingBasicTable => { switch (sortField.field) { diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index 5b60b625212936..f5a99c631131f3 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -401,7 +401,4 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(inputsActions.setSearchBarFilter({ id, filters })), }); -export const SiemSearchBar = connect( - makeMapStateToProps, - mapDispatchToProps -)(SearchBarComponent); +export const SiemSearchBar = connect(makeMapStateToProps, mapDispatchToProps)(SearchBarComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/selectors.ts b/x-pack/legacy/plugins/siem/public/components/search_bar/selectors.ts index cfd7cd840dac8e..acf91067c42918 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/selectors.ts @@ -24,14 +24,6 @@ export const getFilterQuery = (inputState: InputsRange): Query => inputState.que export const getSavedQuery = (inputState: InputsRange): SavedQuery | undefined => inputState.savedQuery; -export const filterQuerySelector = () => - createSelector( - getFilterQuery, - filterQuery => filterQuery - ); +export const filterQuerySelector = () => createSelector(getFilterQuery, filterQuery => filterQuery); -export const savedQuerySelector = () => - createSelector( - getSavedQuery, - savedQuery => savedQuery - ); +export const savedQuerySelector = () => createSelector(getSavedQuery, savedQuery => savedQuery); diff --git a/x-pack/legacy/plugins/siem/public/components/super_date_picker/selectors.ts b/x-pack/legacy/plugins/siem/public/components/super_date_picker/selectors.ts index 59f55f33842fe9..2e1a3f1a7f3a12 100644 --- a/x-pack/legacy/plugins/siem/public/components/super_date_picker/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/components/super_date_picker/selectors.ts @@ -13,62 +13,25 @@ export const getTimerange = (inputState: InputsRange): TimeRange => inputState.t export const getQueries = (inputState: InputsRange): GlobalQuery[] => inputState.queries; -export const policySelector = () => - createSelector( - getPolicy, - policy => policy.kind - ); +export const policySelector = () => createSelector(getPolicy, policy => policy.kind); -export const durationSelector = () => - createSelector( - getPolicy, - policy => policy.duration - ); +export const durationSelector = () => createSelector(getPolicy, policy => policy.duration); -export const kindSelector = () => - createSelector( - getTimerange, - timerange => timerange.kind - ); +export const kindSelector = () => createSelector(getTimerange, timerange => timerange.kind); -export const startSelector = () => - createSelector( - getTimerange, - timerange => timerange.from - ); +export const startSelector = () => createSelector(getTimerange, timerange => timerange.from); -export const endSelector = () => - createSelector( - getTimerange, - timerange => timerange.to - ); +export const endSelector = () => createSelector(getTimerange, timerange => timerange.to); -export const fromStrSelector = () => - createSelector( - getTimerange, - timerange => timerange.fromStr - ); +export const fromStrSelector = () => createSelector(getTimerange, timerange => timerange.fromStr); -export const toStrSelector = () => - createSelector( - getTimerange, - timerange => timerange.toStr - ); +export const toStrSelector = () => createSelector(getTimerange, timerange => timerange.toStr); export const isLoadingSelector = () => - createSelector( - getQueries, - queries => queries.some(i => i.loading === true) - ); + createSelector(getQueries, queries => queries.some(i => i.loading === true)); export const queriesSelector = () => - createSelector( - getQueries, - queries => queries.filter(q => q.id !== 'kql') - ); + createSelector(getQueries, queries => queries.filter(q => q.id !== 'kql')); export const kqlQuerySelector = () => - createSelector( - getQueries, - queries => queries.find(q => q.id === 'kql') - ); + createSelector(getQueries, queries => queries.find(q => q.id === 'kql')); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/auto_save_warning/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/auto_save_warning/index.tsx index 2cba2a4b39f1b9..d16e446a879a61 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/auto_save_warning/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/auto_save_warning/index.tsx @@ -107,11 +107,8 @@ const mapStateToProps = (state: State) => { }; }; -export const AutoSaveWarningMsg = connect( - mapStateToProps, - { - setTimelineRangeDatePicker: dispatchSetTimelineRangeDatePicker, - updateAutoSaveMsg: timelineActions.updateAutoSaveMsg, - updateTimeline: timelineActions.updateTimeline, - } -)(AutoSaveWarningMsgComponent); +export const AutoSaveWarningMsg = connect(mapStateToProps, { + setTimelineRangeDatePicker: dispatchSetTimelineRangeDatePicker, + updateAutoSaveMsg: timelineActions.updateAutoSaveMsg, + updateTimeline: timelineActions.updateTimeline, +})(AutoSaveWarningMsgComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/stateful_body.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/stateful_body.tsx index 531e61dd7dc60b..e5656455623b52 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/stateful_body.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/stateful_body.tsx @@ -216,17 +216,14 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulBody = connect( - makeMapStateToProps, - { - addNoteToEvent: timelineActions.addNoteToEvent, - applyDeltaToColumnWidth: timelineActions.applyDeltaToColumnWidth, - pinEvent: timelineActions.pinEvent, - removeColumn: timelineActions.removeColumn, - removeProvider: timelineActions.removeProvider, - unPinEvent: timelineActions.unPinEvent, - updateColumns: timelineActions.updateColumns, - updateNote: appActions.updateNote, - updateSort: timelineActions.updateSort, - } -)(StatefulBodyComponent); +export const StatefulBody = connect(makeMapStateToProps, { + addNoteToEvent: timelineActions.addNoteToEvent, + applyDeltaToColumnWidth: timelineActions.applyDeltaToColumnWidth, + pinEvent: timelineActions.pinEvent, + removeColumn: timelineActions.removeColumn, + removeProvider: timelineActions.removeProvider, + unPinEvent: timelineActions.unPinEvent, + updateColumns: timelineActions.updateColumns, + updateNote: appActions.updateNote, + updateSort: timelineActions.updateSort, +})(StatefulBodyComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx index e5f50c332a7c21..e97a8c0860d361 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx @@ -71,9 +71,6 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const TimelineKqlFetch = connect( - makeMapStateToProps, - { - setTimelineQuery: inputsActions.setQuery, - } -)(TimelineKqlFetchComponent); +export const TimelineKqlFetch = connect(makeMapStateToProps, { + setTimelineQuery: inputsActions.setQuery, +})(TimelineKqlFetchComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx index 78a9488b2fdbbe..e4afef9a351e84 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx @@ -341,22 +341,19 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulTimeline = connect( - makeMapStateToProps, - { - addProvider: timelineActions.addProvider, - createTimeline: timelineActions.createTimeline, - onDataProviderEdited: timelineActions.dataProviderEdited, - removeColumn: timelineActions.removeColumn, - removeProvider: timelineActions.removeProvider, - updateColumns: timelineActions.updateColumns, - updateDataProviderEnabled: timelineActions.updateDataProviderEnabled, - updateDataProviderExcluded: timelineActions.updateDataProviderExcluded, - updateDataProviderKqlQuery: timelineActions.updateDataProviderKqlQuery, - updateHighlightedDropAndProviderId: timelineActions.updateHighlightedDropAndProviderId, - updateItemsPerPage: timelineActions.updateItemsPerPage, - updateItemsPerPageOptions: timelineActions.updateItemsPerPageOptions, - updateSort: timelineActions.updateSort, - upsertColumn: timelineActions.upsertColumn, - } -)(StatefulTimelineComponent); +export const StatefulTimeline = connect(makeMapStateToProps, { + addProvider: timelineActions.addProvider, + createTimeline: timelineActions.createTimeline, + onDataProviderEdited: timelineActions.dataProviderEdited, + removeColumn: timelineActions.removeColumn, + removeProvider: timelineActions.removeProvider, + updateColumns: timelineActions.updateColumns, + updateDataProviderEnabled: timelineActions.updateDataProviderEnabled, + updateDataProviderExcluded: timelineActions.updateDataProviderExcluded, + updateDataProviderKqlQuery: timelineActions.updateDataProviderKqlQuery, + updateHighlightedDropAndProviderId: timelineActions.updateHighlightedDropAndProviderId, + updateItemsPerPage: timelineActions.updateItemsPerPage, + updateItemsPerPageOptions: timelineActions.updateItemsPerPageOptions, + updateSort: timelineActions.updateSort, + upsertColumn: timelineActions.upsertColumn, +})(StatefulTimelineComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx index 7e549a08f95118..8a78d04c883117 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx @@ -44,10 +44,7 @@ const TimelineRefetchComponent = memo( ); export const TimelineRefetch = compose>( - connect( - null, - { - setTimelineQuery: inputsActions.setQuery, - } - ) + connect(null, { + setTimelineQuery: inputsActions.setQuery, + }) )(TimelineRefetchComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx index 0ebceccfa90c50..ec491fe50407a2 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx @@ -114,11 +114,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulSearchOrFilter = connect( - makeMapStateToProps, - { - applyKqlFilterQuery: timelineActions.applyKqlFilterQuery, - setKqlFilterQueryDraft: timelineActions.setKqlFilterQueryDraft, - updateKqlMode: timelineActions.updateKqlMode, - } -)(StatefulSearchOrFilterComponent); +export const StatefulSearchOrFilter = connect(makeMapStateToProps, { + applyKqlFilterQuery: timelineActions.applyKqlFilterQuery, + setKqlFilterQueryDraft: timelineActions.setKqlFilterQueryDraft, + updateKqlMode: timelineActions.updateKqlMode, +})(StatefulSearchOrFilterComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx index b58b60587c8639..8164348620b507 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx @@ -38,10 +38,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ }); export const UrlStateRedux = compose>( - connect( - makeMapStateToProps, - mapDispatchToProps - ) + connect(makeMapStateToProps, mapDispatchToProps) )(UrlStateContainer); export const UseUrlState = React.memo(props => { diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts index f548fe9ee8d486..39c540b3bd3557 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts +++ b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts @@ -265,9 +265,15 @@ export const getMockPropsObj = ({ // silly that this needs to be an array and not an object // https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout -export const testCases: Array< - [LocationTypes, string, string, string, string | null, string, undefined | string] -> = [ +export const testCases: Array<[ + LocationTypes, + string, + string, + string, + string | null, + string, + undefined | string +]> = [ [ /* page */ CONSTANTS.networkPage, /* namespaceLower */ 'network', diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx index f1eeb4e6fbec40..d7fece57319729 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx @@ -75,9 +75,10 @@ export const useUrlStateHooks = ({ search, state: '', }, - replaceStateKeyInQueryString(urlStateKey, urlStateToReplace)( - getQueryStringFromLocation(latestLocation) - ) + replaceStateKeyInQueryString( + urlStateKey, + urlStateToReplace + )(getQueryStringFromLocation(latestLocation)) ); if (history) { history.replace(newLocation); diff --git a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx index 78e03a36f40cb7..665148b7ad650f 100644 --- a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx @@ -83,11 +83,8 @@ const mapStateToProps = (state: State) => { }; }; -export const GlobalTime = connect( - mapStateToProps, - { - deleteAllQuery: inputsActions.deleteAllQuery, - deleteOneQuery: inputsActions.deleteOneQuery, - setGlobalQuery: inputsActions.setQuery, - } -)(GlobalTimeComponent); +export const GlobalTime = connect(mapStateToProps, { + deleteAllQuery: inputsActions.deleteAllQuery, + deleteOneQuery: inputsActions.deleteOneQuery, + setGlobalQuery: inputsActions.setQuery, +})(GlobalTimeComponent); diff --git a/x-pack/legacy/plugins/siem/public/lib/keury/index.ts b/x-pack/legacy/plugins/siem/public/lib/keury/index.ts index bf8726d5ed377f..e9f4c95a80b743 100644 --- a/x-pack/legacy/plugins/siem/public/lib/keury/index.ts +++ b/x-pack/legacy/plugins/siem/public/lib/keury/index.ts @@ -61,12 +61,7 @@ const escapeAndOr = (val: string) => val.replace(/(\s+)(and|or)(\s+)/gi, '$1\\$2 const escapeNot = (val: string) => val.replace(/not(\s+)/gi, '\\$&'); -export const escapeKuery = flow( - escapeSpecialCharacters, - escapeAndOr, - escapeNot, - escapeWhitespace -); +export const escapeKuery = flow(escapeSpecialCharacters, escapeAndOr, escapeNot, escapeWhitespace); export interface EsQueryConfig { allowLeadingWildcards: boolean; @@ -88,10 +83,15 @@ export const convertToBuildEsQuery = ({ }) => { try { return JSON.stringify( - buildEsQuery(indexPattern, queries, filters.filter(f => f.meta.disabled === false), { - ...config, - dateFormatTZ: null, - }) + buildEsQuery( + indexPattern, + queries, + filters.filter(f => f.meta.disabled === false), + { + ...config, + dateFormatTZ: null, + } + ) ); } catch (exp) { return ''; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx index 2cb193fb47c6b9..453f26240a87fa 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx @@ -232,11 +232,8 @@ export const makeMapStateToProps = () => { }; export const HostDetails = compose>( - connect( - makeMapStateToProps, - { - setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, - setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, - } - ) + connect(makeMapStateToProps, { + setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, + setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, + }) )(HostDetailsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx index 1dc21c9d0284f1..f616abbac5745f 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -154,10 +154,7 @@ interface HostsProps extends GlobalTimeArgs { // eslint-disable-next-line @typescript-eslint/no-explicit-any export const Hosts = compose>( - connect( - makeMapStateToProps, - { - setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, - } - ) + connect(makeMapStateToProps, { + setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, + }) )(HostsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx index b1751cca0b3d09..d160e4f57be6b0 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx @@ -290,10 +290,7 @@ const makeMapStateToProps = () => { }); }; -export const IPDetails = connect( - makeMapStateToProps, - { - setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, - setIpDetailsTablesActivePageToZero: dispatchIpDetailsTablesActivePageToZero, - } -)(IPDetailsComponent); +export const IPDetails = connect(makeMapStateToProps, { + setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, + setIpDetailsTablesActivePageToZero: dispatchIpDetailsTablesActivePageToZero, +})(IPDetailsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index 6b4c54737eb100..b919985fecb04f 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -161,9 +161,6 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const Network = connect( - makeMapStateToProps, - { - setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, - } -)(NetworkComponent); +export const Network = connect(makeMapStateToProps, { + setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, +})(NetworkComponent); diff --git a/x-pack/legacy/plugins/siem/public/store/app/selectors.ts b/x-pack/legacy/plugins/siem/public/store/app/selectors.ts index 9037583d278a7a..16f02fd85cbc22 100644 --- a/x-pack/legacy/plugins/siem/public/store/app/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/app/selectors.ts @@ -33,13 +33,6 @@ export const selectNotesByIdSelector = createSelector( ); export const notesByIdsSelector = () => - createSelector( - selectNotesById, - (notesById: NotesById) => notesById - ); - -export const errorsSelector = () => - createSelector( - getErrors, - errors => ({ errors }) - ); + createSelector(selectNotesById, (notesById: NotesById) => notesById); + +export const errorsSelector = () => createSelector(getErrors, errors => ({ errors })); diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts b/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts index 7d00569f9a0ea2..8ebeae4bba392b 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts @@ -15,25 +15,12 @@ const selectHosts = (state: State, hostsType: HostsType): GenericHostsModel => get(hostsType, state.hosts); export const authenticationsSelector = () => - createSelector( - selectHosts, - hosts => hosts.queries.authentications - ); + createSelector(selectHosts, hosts => hosts.queries.authentications); export const hostsSelector = () => - createSelector( - selectHosts, - hosts => hosts.queries[HostsTableType.hosts] - ); + createSelector(selectHosts, hosts => hosts.queries[HostsTableType.hosts]); -export const eventsSelector = () => - createSelector( - selectHosts, - hosts => hosts.queries.events - ); +export const eventsSelector = () => createSelector(selectHosts, hosts => hosts.queries.events); export const uncommonProcessesSelector = () => - createSelector( - selectHosts, - hosts => hosts.queries.uncommonProcesses - ); + createSelector(selectHosts, hosts => hosts.queries.uncommonProcesses); diff --git a/x-pack/legacy/plugins/siem/public/store/inputs/selectors.ts b/x-pack/legacy/plugins/siem/public/store/inputs/selectors.ts index 7c33c0f7876943..cb2d357b740078 100644 --- a/x-pack/legacy/plugins/siem/public/store/inputs/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/inputs/selectors.ts @@ -37,49 +37,24 @@ const selectTimelineQuery = (state: State, id: string): GlobalQuery => selectedInspectIndex: 0, }; -export const inputsSelector = () => - createSelector( - selectInputs, - inputs => inputs - ); +export const inputsSelector = () => createSelector(selectInputs, inputs => inputs); export const timelineTimeRangeSelector = createSelector( selectTimeline, timeline => timeline.timerange ); -export const globalTimeRangeSelector = createSelector( - selectGlobal, - global => global.timerange -); +export const globalTimeRangeSelector = createSelector(selectGlobal, global => global.timerange); -export const globalPolicySelector = createSelector( - selectGlobal, - global => global.policy -); +export const globalPolicySelector = createSelector(selectGlobal, global => global.policy); -export const globalQuery = createSelector( - selectGlobal, - global => global.queries -); +export const globalQuery = createSelector(selectGlobal, global => global.queries); -export const globalQueryByIdSelector = () => - createSelector( - selectGlobalQuery, - query => query - ); +export const globalQueryByIdSelector = () => createSelector(selectGlobalQuery, query => query); -export const timelineQueryByIdSelector = () => - createSelector( - selectTimelineQuery, - query => query - ); +export const timelineQueryByIdSelector = () => createSelector(selectTimelineQuery, query => query); -export const globalSelector = () => - createSelector( - selectGlobal, - global => global - ); +export const globalSelector = () => createSelector(selectGlobal, global => global); export const globalQuerySelector = () => createSelector( @@ -92,19 +67,9 @@ export const globalQuerySelector = () => ); export const globalSavedQuerySelector = () => - createSelector( - selectGlobal, - global => global.savedQuery || null - ); + createSelector(selectGlobal, global => global.savedQuery || null); export const globalFiltersQuerySelector = () => - createSelector( - selectGlobal, - global => global.filters || [] - ); + createSelector(selectGlobal, global => global.filters || []); -export const getTimelineSelector = () => - createSelector( - selectTimeline, - timeline => timeline - ); +export const getTimelineSelector = () => createSelector(selectTimeline, timeline => timeline); diff --git a/x-pack/legacy/plugins/siem/public/store/network/selectors.ts b/x-pack/legacy/plugins/siem/public/store/network/selectors.ts index cf57c0d07c43e0..a33684472b279b 100644 --- a/x-pack/legacy/plugins/siem/public/store/network/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/network/selectors.ts @@ -23,11 +23,7 @@ const selectNetworkPage = (state: State): NetworkPageModel => state.network.page const selectNetworkDetails = (state: State): NetworkDetailsModel => state.network.details; // Network Page Selectors -export const dnsSelector = () => - createSelector( - selectNetworkPage, - network => network.queries.dns - ); +export const dnsSelector = () => createSelector(selectNetworkPage, network => network.queries.dns); const selectTopNFlowByType = ( state: State, @@ -44,10 +40,7 @@ const selectTopNFlowByType = ( }; export const topNFlowSelector = () => - createSelector( - selectTopNFlowByType, - topNFlowQueries => topNFlowQueries - ); + createSelector(selectTopNFlowByType, topNFlowQueries => topNFlowQueries); const selectTlsByType = (state: State, networkType: NetworkType) => { const tlsType = networkType === NetworkType.page ? NetworkTableType.tls : IpDetailsTableType.tls; return ( @@ -56,11 +49,7 @@ const selectTlsByType = (state: State, networkType: NetworkType) => { ); }; -export const tlsSelector = () => - createSelector( - selectTlsByType, - tlsQueries => tlsQueries - ); +export const tlsSelector = () => createSelector(selectTlsByType, tlsQueries => tlsQueries); const selectTopCountriesByType = ( state: State, @@ -79,10 +68,7 @@ const selectTopCountriesByType = ( }; export const topCountriesSelector = () => - createSelector( - selectTopCountriesByType, - topCountriesQueries => topCountriesQueries - ); + createSelector(selectTopCountriesByType, topCountriesQueries => topCountriesQueries); const selectHttpByType = (state: State, networkType: NetworkType) => { const httpType = @@ -93,21 +79,11 @@ const selectHttpByType = (state: State, networkType: NetworkType) => { ); }; -export const httpSelector = () => - createSelector( - selectHttpByType, - httpQueries => httpQueries - ); +export const httpSelector = () => createSelector(selectHttpByType, httpQueries => httpQueries); // IP Details Selectors export const ipDetailsFlowTargetSelector = () => - createSelector( - selectNetworkDetails, - network => network.flowTarget - ); + createSelector(selectNetworkDetails, network => network.flowTarget); export const usersSelector = () => - createSelector( - selectNetworkDetails, - network => network.queries.users - ); + createSelector(selectNetworkDetails, network => network.queries.users); diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/epic.ts b/x-pack/legacy/plugins/siem/public/store/timeline/epic.ts index 8d4a93ca97eb35..6957db5578af57 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/epic.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/epic.ts @@ -107,20 +107,11 @@ export const createTimelineEpic = (): Epic< state$, { selectNotesByIdSelector, timelineByIdSelector, timelineTimeRangeSelector, apolloClient$ } ) => { - const timeline$ = state$.pipe( - map(timelineByIdSelector), - filter(isNotNull) - ); + const timeline$ = state$.pipe(map(timelineByIdSelector), filter(isNotNull)); - const notes$ = state$.pipe( - map(selectNotesByIdSelector), - filter(isNotNull) - ); + const notes$ = state$.pipe(map(selectNotesByIdSelector), filter(isNotNull)); - const timelineTimeRange$ = state$.pipe( - map(timelineTimeRangeSelector), - filter(isNotNull) - ); + const timelineTimeRange$ = state$.pipe(map(timelineTimeRangeSelector), filter(isNotNull)); return merge( action$.pipe( diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/model.ts b/x-pack/legacy/plugins/siem/public/store/timeline/model.ts index 50cfd89fd057a5..3b10314f72531c 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/model.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/model.ts @@ -71,35 +71,33 @@ export interface TimelineModel { version: string | null; } -export const timelineDefaults: Readonly< - Pick< - TimelineModel, - | 'columns' - | 'dataProviders' - | 'description' - | 'eventIdToNoteIds' - | 'highlightedDropAndProviderId' - | 'historyIds' - | 'isFavorite' - | 'isLive' - | 'itemsPerPage' - | 'itemsPerPageOptions' - | 'kqlMode' - | 'kqlQuery' - | 'title' - | 'noteIds' - | 'pinnedEventIds' - | 'pinnedEventsSaveObject' - | 'dateRange' - | 'show' - | 'sort' - | 'width' - | 'isSaving' - | 'isLoading' - | 'savedObjectId' - | 'version' - > -> = { +export const timelineDefaults: Readonly> = { columns: defaultHeaders, dataProviders: [], description: '', @@ -135,32 +133,30 @@ export const timelineDefaults: Readonly< version: null, }; -export const eventsDefaults: Readonly< - Pick< - TimelineModel, - | 'columns' - | 'dataProviders' - | 'description' - | 'eventIdToNoteIds' - | 'highlightedDropAndProviderId' - | 'historyIds' - | 'isFavorite' - | 'isLive' - | 'itemsPerPage' - | 'itemsPerPageOptions' - | 'kqlMode' - | 'kqlQuery' - | 'title' - | 'noteIds' - | 'pinnedEventIds' - | 'pinnedEventsSaveObject' - | 'dateRange' - | 'show' - | 'sort' - | 'width' - | 'isSaving' - | 'isLoading' - | 'savedObjectId' - | 'version' - > -> = { ...timelineDefaults, columns: eventsDefaultHeaders }; +export const eventsDefaults: Readonly> = { ...timelineDefaults, columns: eventsDefaultHeaders }; diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/selectors.ts b/x-pack/legacy/plugins/siem/public/store/timeline/selectors.ts index 14f51a601fa7f5..c248387e6b3fd2 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/selectors.ts @@ -22,10 +22,7 @@ const selectCallOutUnauthorizedMsg = (state: State): boolean => export const selectTimeline = (state: State, timelineId: string): TimelineModel => state.timeline.timelineById[timelineId]; -export const autoSaveMsgSelector = createSelector( - selectAutoSaveMsg, - autoSaveMsg => autoSaveMsg -); +export const autoSaveMsgSelector = createSelector(selectAutoSaveMsg, autoSaveMsg => autoSaveMsg); export const timelineByIdSelector = createSelector( selectTimelineById, @@ -41,45 +38,34 @@ export const getShowCallOutUnauthorizedMsg = () => export const getTimelines = () => timelineByIdSelector; export const getTimelineByIdSelector = () => - createSelector( - selectTimeline, - timeline => timeline || timelineDefaults - ); + createSelector(selectTimeline, timeline => timeline || timelineDefaults); export const getEventsByIdSelector = () => - createSelector( - selectTimeline, - timeline => timeline || eventsDefaults - ); + createSelector(selectTimeline, timeline => timeline || eventsDefaults); export const getKqlFilterQuerySelector = () => - createSelector( - selectTimeline, - timeline => - timeline && - timeline.kqlQuery && - timeline.kqlQuery.filterQuery && - timeline.kqlQuery.filterQuery.kuery - ? timeline.kqlQuery.filterQuery.kuery.expression - : null + createSelector(selectTimeline, timeline => + timeline && + timeline.kqlQuery && + timeline.kqlQuery.filterQuery && + timeline.kqlQuery.filterQuery.kuery + ? timeline.kqlQuery.filterQuery.kuery.expression + : null ); export const getKqlFilterQueryDraftSelector = () => - createSelector( - selectTimeline, - timeline => (timeline && timeline.kqlQuery ? timeline.kqlQuery.filterQueryDraft : null) + createSelector(selectTimeline, timeline => + timeline && timeline.kqlQuery ? timeline.kqlQuery.filterQueryDraft : null ); export const getKqlFilterKuerySelector = () => - createSelector( - selectTimeline, - timeline => - timeline && - timeline.kqlQuery && - timeline.kqlQuery.filterQuery && - timeline.kqlQuery.filterQuery.kuery - ? timeline.kqlQuery.filterQuery.kuery - : null + createSelector(selectTimeline, timeline => + timeline && + timeline.kqlQuery && + timeline.kqlQuery.filterQuery && + timeline.kqlQuery.filterQuery.kuery + ? timeline.kqlQuery.filterQuery.kuery + : null ); export const isFilterQueryDraftValidSelector = () => diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/delete_signals.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/delete_signals.ts index 007d8b9325a869..7a69c11ecf2e59 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/delete_signals.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/delete_signals.ts @@ -26,7 +26,7 @@ export const deleteSignals = async ({ alertsClient, actionsClient, id }: DeleteS // TODO: Remove this as cast as soon as signal.actions TypeScript bug is fixed // where it is trying to return AlertAction[] or RawAlertAction[] - const actions = (signal.actions as (AlertAction[] | undefined)) || []; + const actions = (signal.actions as AlertAction[] | undefined) || []; const actionsErrors = await deleteAllSignalActions(actionsClient, actions); const deletedAlert = await alertsClient.delete({ id: signal.id }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts index 456a79efe874a7..1045826bf488f2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts @@ -1153,7 +1153,9 @@ describe('update_signals', () => { }); test('page validates', () => { - expect(findSignalsSchema.validate>({ page: 5 }).error).toBeFalsy(); + expect( + findSignalsSchema.validate>({ page: 5 }).error + ).toBeFalsy(); }); test('sort_field validates', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/index_fields/elasticsearch_adapter.ts b/x-pack/legacy/plugins/siem/server/lib/index_fields/elasticsearch_adapter.ts index 2bae05dbe3b938..83eecc459cd6eb 100644 --- a/x-pack/legacy/plugins/siem/server/lib/index_fields/elasticsearch_adapter.ts +++ b/x-pack/legacy/plugins/siem/server/lib/index_fields/elasticsearch_adapter.ts @@ -44,9 +44,10 @@ export class ElasticsearchIndexFieldAdapter implements FieldsAdapter { }) ) ); - return formatIndexFields(responsesIndexFields, Object.keys( - indexesAliasIndices - ) as IndexAlias[]); + return formatIndexFields( + responsesIndexFields, + Object.keys(indexesAliasIndices) as IndexAlias[] + ); } } diff --git a/x-pack/legacy/plugins/siem/server/lib/uncommon_processes/elasticsearch_adapter.test.ts b/x-pack/legacy/plugins/siem/server/lib/uncommon_processes/elasticsearch_adapter.test.ts index 208681d002b5be..90839f5ac01c41 100644 --- a/x-pack/legacy/plugins/siem/server/lib/uncommon_processes/elasticsearch_adapter.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/uncommon_processes/elasticsearch_adapter.test.ts @@ -161,7 +161,10 @@ describe('elasticsearch_adapter', () => { test('will return two hosts correctly', () => { const hosts = getHosts(bucket2.hosts.buckets); - expect(hosts).toEqual([{ id: ['123'], name: ['host-1'] }, { id: ['345'], name: ['host-2'] }]); + expect(hosts).toEqual([ + { id: ['123'], name: ['host-1'] }, + { id: ['345'], name: ['host-2'] }, + ]); }); test('will return a dot notation host', () => { diff --git a/x-pack/legacy/plugins/siem/server/utils/build_query/fields.ts b/x-pack/legacy/plugins/siem/server/utils/build_query/fields.ts index 574ec2d03bcf94..979262c7faff31 100644 --- a/x-pack/legacy/plugins/siem/server/utils/build_query/fields.ts +++ b/x-pack/legacy/plugins/siem/server/utils/build_query/fields.ts @@ -15,21 +15,18 @@ export const getFields = ( if (data.kind === 'Field' && data.selectionSet && !isEmpty(data.selectionSet.selections)) { return getFields(data.selectionSet, fields); } else if (data.kind === 'SelectionSet') { - return data.selections.reduce( - (res: string[], item: SelectionNode) => { - if (item.kind === 'Field') { - const field: FieldNode = item as FieldNode; - if (field.name.kind === 'Name' && field.name.value.includes('kpi')) { - return [...res, field.name.value]; - } else if (field.selectionSet && !isEmpty(field.selectionSet.selections)) { - return getFields(field.selectionSet, res, postFields.concat(field.name.value)); - } - return [...res, [...postFields, field.name.value].join('.')]; + return data.selections.reduce((res: string[], item: SelectionNode) => { + if (item.kind === 'Field') { + const field: FieldNode = item as FieldNode; + if (field.name.kind === 'Name' && field.name.value.includes('kpi')) { + return [...res, field.name.value]; + } else if (field.selectionSet && !isEmpty(field.selectionSet.selections)) { + return getFields(field.selectionSet, res, postFields.concat(field.name.value)); } - return res; - }, - fields as string[] - ); + return [...res, [...postFields, field.name.value].join('.')]; + } + return res; + }, fields as string[]); } return fields; diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/lib/authorization/components/with_privileges.tsx index 004ec8b9c05175..797e7480454a3d 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/lib/authorization/components/with_privileges.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/lib/authorization/components/with_privileges.tsx @@ -59,22 +59,19 @@ export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Pro return !privileges.missingPrivileges[section]!.includes(requiredPrivilege); }); - const privilegesMissing = privilegesToArray.reduce( - (acc, [section, privilege]) => { - if (privilege === '*') { - acc[section] = privileges.missingPrivileges[section] || []; - } else if ( - privileges.missingPrivileges[section] && - privileges.missingPrivileges[section]!.includes(privilege) - ) { - const missing: string[] = acc[section] || []; - acc[section] = [...missing, privilege]; - } + const privilegesMissing = privilegesToArray.reduce((acc, [section, privilege]) => { + if (privilege === '*') { + acc[section] = privileges.missingPrivileges[section] || []; + } else if ( + privileges.missingPrivileges[section] && + privileges.missingPrivileges[section]!.includes(privilege) + ) { + const missing: string[] = acc[section] || []; + acc[section] = [...missing, privilege]; + } - return acc; - }, - {} as MissingPrivileges - ); + return acc; + }, {} as MissingPrivileges); return children({ isLoading, hasPrivileges, privilegesMissing }); }; diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/sections/home/policy_list/policy_table/policy_table.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/sections/home/policy_list/policy_table/policy_table.tsx index 01fc904906bf14..62038f99638366 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/sections/home/policy_list/policy_table/policy_table.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/sections/home/policy_list/policy_table/policy_table.tsx @@ -308,7 +308,10 @@ export const PolicyTable: React.FunctionComponent = ({ return ( - deletePolicyPrompt(selectedItems.map(({ name }) => name), onPolicyDeleted) + deletePolicyPrompt( + selectedItems.map(({ name }) => name), + onPolicyDeleted + ) } color="danger" data-test-subj="srPolicyListBulkDeleteActionButton" diff --git a/x-pack/legacy/plugins/task_manager/lib/fill_pool.test.ts b/x-pack/legacy/plugins/task_manager/lib/fill_pool.test.ts index d7ac8d227fc4c0..c4927475d586ba 100644 --- a/x-pack/legacy/plugins/task_manager/lib/fill_pool.test.ts +++ b/x-pack/legacy/plugins/task_manager/lib/fill_pool.test.ts @@ -11,7 +11,10 @@ import { TaskPoolRunResult } from '../task_pool'; describe('fillPool', () => { test('stops filling when there are no more tasks in the store', async () => { - const tasks = [[1, 2, 3], [4, 5]]; + const tasks = [ + [1, 2, 3], + [4, 5], + ]; let index = 0; const fetchAvailableTasks = async () => tasks[index++] || []; const run = sinon.spy(async () => TaskPoolRunResult.RunningAllClaimedTasks); @@ -23,7 +26,10 @@ describe('fillPool', () => { }); test('stops filling when the pool has no more capacity', async () => { - const tasks = [[1, 2, 3], [4, 5]]; + const tasks = [ + [1, 2, 3], + [4, 5], + ]; let index = 0; const fetchAvailableTasks = async () => tasks[index++] || []; const run = sinon.spy(async () => TaskPoolRunResult.RanOutOfCapacity); @@ -35,7 +41,10 @@ describe('fillPool', () => { }); test('calls the converter on the records prior to running', async () => { - const tasks = [[1, 2, 3], [4, 5]]; + const tasks = [ + [1, 2, 3], + [4, 5], + ]; let index = 0; const fetchAvailableTasks = async () => tasks[index++] || []; const run = sinon.spy(async () => TaskPoolRunResult.RanOutOfCapacity); @@ -66,7 +75,10 @@ describe('fillPool', () => { const converter = (x: number) => x.toString(); try { - const tasks = [[1, 2, 3], [4, 5]]; + const tasks = [ + [1, 2, 3], + [4, 5], + ]; let index = 0; const fetchAvailableTasks = async () => tasks[index++] || []; @@ -78,7 +90,10 @@ describe('fillPool', () => { test('throws exception from converter', async () => { try { - const tasks = [[1, 2, 3], [4, 5]]; + const tasks = [ + [1, 2, 3], + [4, 5], + ]; let index = 0; const fetchAvailableTasks = async () => tasks[index++] || []; const run = sinon.spy(async () => TaskPoolRunResult.RanOutOfCapacity); diff --git a/x-pack/legacy/plugins/task_manager/lib/sanitize_task_definitions.ts b/x-pack/legacy/plugins/task_manager/lib/sanitize_task_definitions.ts index 24cb50a59adc83..f5856aa6fac334 100644 --- a/x-pack/legacy/plugins/task_manager/lib/sanitize_task_definitions.ts +++ b/x-pack/legacy/plugins/task_manager/lib/sanitize_task_definitions.ts @@ -16,13 +16,10 @@ import { TaskDefinition, TaskDictionary, validateTaskDefinition } from '../task' export function sanitizeTaskDefinitions( taskDefinitions: TaskDictionary = {} ): TaskDictionary { - return Object.keys(taskDefinitions).reduce( - (acc, type) => { - const rawDefinition = taskDefinitions[type]; - rawDefinition.type = type; - acc[type] = Joi.attempt(rawDefinition, validateTaskDefinition) as TaskDefinition; - return acc; - }, - {} as TaskDictionary - ); + return Object.keys(taskDefinitions).reduce((acc, type) => { + const rawDefinition = taskDefinitions[type]; + rawDefinition.type = type; + acc[type] = Joi.attempt(rawDefinition, validateTaskDefinition) as TaskDefinition; + return acc; + }, {} as TaskDictionary); } diff --git a/x-pack/legacy/plugins/transform/common/utils/es_utils.ts b/x-pack/legacy/plugins/transform/common/utils/es_utils.ts index c52b99c350e38a..bed7ba8bc77367 100644 --- a/x-pack/legacy/plugins/transform/common/utils/es_utils.ts +++ b/x-pack/legacy/plugins/transform/common/utils/es_utils.ts @@ -33,7 +33,8 @@ export function isValidIndexName(indexName: string) { // Cannot start with -, _, + /^[^-_\+]+$/.test(indexName.charAt(0)) && // Cannot be . or .. - (indexName !== '.' && indexName !== '..') && + indexName !== '.' && + indexName !== '..' && // Cannot be longer than 255 bytes (note it is bytes, // so multi-byte characters will count towards the 255 limit faster) isValidIndexNameLength(indexName) diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts index df2ce6b56a5af4..eec93d4e089969 100644 --- a/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -70,32 +70,27 @@ export const useGetTransforms = ( const transformConfigs: GetTransformsResponse = await api.getTransforms(); const transformStats: GetTransformsStatsResponse = await api.getTransformsStats(); - const tableRows = transformConfigs.transforms.reduce( - (reducedtableRows, config) => { - const stats = isGetTransformsStatsResponseOk(transformStats) - ? transformStats.transforms.find(d => config.id === d.id) - : undefined; - - // A newly created transform might not have corresponding stats yet. - // If that's the case we just skip the transform and don't add it to the transform list yet. - if (!isTransformStats(stats)) { - return reducedtableRows; - } - - // Table with expandable rows requires `id` on the outer most level - reducedtableRows.push({ - id: config.id, - config, - mode: - typeof config.sync !== 'undefined' - ? TRANSFORM_MODE.CONTINUOUS - : TRANSFORM_MODE.BATCH, - stats, - }); + const tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { + const stats = isGetTransformsStatsResponseOk(transformStats) + ? transformStats.transforms.find(d => config.id === d.id) + : undefined; + + // A newly created transform might not have corresponding stats yet. + // If that's the case we just skip the transform and don't add it to the transform list yet. + if (!isTransformStats(stats)) { return reducedtableRows; - }, - [] as TransformListRow[] - ); + } + + // Table with expandable rows requires `id` on the outer most level + reducedtableRows.push({ + id: config.id, + config, + mode: + typeof config.sync !== 'undefined' ? TRANSFORM_MODE.CONTINUOUS : TRANSFORM_MODE.BATCH, + stats, + }); + return reducedtableRows; + }, [] as TransformListRow[]); setTransforms(tableRows); setErrorMessage(undefined); diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx index 8bf7ea66d28b13..91e5be53312037 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx @@ -45,22 +45,19 @@ export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Pro const hasPrivilege = hasPrivilegeFactory(privileges); const hasPrivileges = isLoading ? false : privilegesToArray.every(hasPrivilege); - const privilegesMissing = privilegesToArray.reduce( - (acc, [section, privilege]) => { - if (privilege === '*') { - acc[section] = privileges.missingPrivileges[section] || []; - } else if ( - privileges.missingPrivileges[section] && - privileges.missingPrivileges[section]!.includes(privilege) - ) { - const missing: string[] = acc[section] || []; - acc[section] = [...missing, privilege]; - } + const privilegesMissing = privilegesToArray.reduce((acc, [section, privilege]) => { + if (privilege === '*') { + acc[section] = privileges.missingPrivileges[section] || []; + } else if ( + privileges.missingPrivileges[section] && + privileges.missingPrivileges[section]!.includes(privilege) + ) { + const missing: string[] = acc[section] || []; + acc[section] = [...missing, privilege]; + } - return acc; - }, - {} as MissingPrivileges - ); + return acc; + }, {} as MissingPrivileges); return children({ isLoading, hasPrivileges, privilegesMissing }); }; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx index ea81b33afbd235..bfde8f171874ed 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx @@ -24,16 +24,13 @@ describe('Transform: ', () => { arrayObject: [{ object1: 'the-object-1' }, { object2: 'the-objects-2' }], } as Record; - const flattenedSource = getFlattenedFields(source).reduce( - (p, c) => { - p[c] = getNestedProperty(source, c); - if (p[c] === undefined) { - p[c] = source[`"${c}"`]; - } - return p; - }, - {} as Record - ); + const flattenedSource = getFlattenedFields(source).reduce((p, c) => { + p[c] = getNestedProperty(source, c); + if (p[c] === undefined) { + p[c] = source[`"${c}"`]; + } + return p; + }, {} as Record); const props = { item: { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index a7e4e494400893..c6bae80e6de967 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -48,16 +48,13 @@ function getItemIdToExpandedRowMap( itemIds: TransformId[], transforms: TransformListRow[] ): ItemIdToExpandedRowMap { - return itemIds.reduce( - (m: ItemIdToExpandedRowMap, transformId: TransformId) => { - const item = transforms.find(transform => transform.config.id === transformId); - if (item !== undefined) { - m[transformId] = ; - } - return m; - }, - {} as ItemIdToExpandedRowMap - ); + return itemIds.reduce((m: ItemIdToExpandedRowMap, transformId: TransformId) => { + const item = transforms.find(transform => transform.config.id === transformId); + if (item !== undefined) { + m[transformId] = ; + } + return m; + }, {} as ItemIdToExpandedRowMap); } function stringMatch(str: string | undefined, substr: string) { diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/components/error_banner.tsx b/x-pack/legacy/plugins/upgrade_assistant/public/components/error_banner.tsx index cb796230bf9423..527f2b6486d7ff 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/components/error_banner.tsx +++ b/x-pack/legacy/plugins/upgrade_assistant/public/components/error_banner.tsx @@ -12,9 +12,10 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { UpgradeAssistantTabProps } from './types'; -export const LoadingErrorBanner: React.StatelessComponent< - Pick -> = ({ loadingError }) => { +export const LoadingErrorBanner: React.StatelessComponent> = ({ loadingError }) => { if (get(loadingError, 'response.status') === 403) { return ( { - checkedIds[idForWarning(warning)] = false; - return checkedIds; - }, - {} as { [id: string]: boolean } - ), + checkedIds: props.warnings.reduce((checkedIds, warning) => { + checkedIds[idForWarning(warning)] = false; + return checkedIds; + }, {} as { [id: string]: boolean }), }; } diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/filter_bar.tsx b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/filter_bar.tsx index e04acfd5bf51ee..0921b5e7e5cfaf 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/filter_bar.tsx +++ b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/filter_bar.tsx @@ -37,13 +37,10 @@ export const FilterBar: React.StatelessComponent = ({ onFilterChange, }) => { const levelGroups = groupBy(allDeprecations, 'level'); - const levelCounts = Object.keys(levelGroups).reduce( - (counts, level) => { - counts[level] = levelGroups[level].length; - return counts; - }, - {} as { [level: string]: number } - ); + const levelCounts = Object.keys(levelGroups).reduce((counts, level) => { + counts[level] = levelGroups[level].length; + return counts; + }, {} as { [level: string]: number }); const allCount = allDeprecations.length; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/overview/steps.tsx b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/overview/steps.tsx index 13d267cc5c31e3..d43a86d2b0e061 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/overview/steps.tsx +++ b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/overview/steps.tsx @@ -92,17 +92,13 @@ const START_UPGRADE_STEP = { ), }; -export const StepsUI: StatelessComponent< - UpgradeAssistantTabProps & ReactIntl.InjectedIntlProps -> = ({ checkupData, setSelectedTabIndex, intl }) => { +export const StepsUI: StatelessComponent = ({ checkupData, setSelectedTabIndex, intl }) => { const checkupDataTyped = (checkupData! as unknown) as { [checkupType: string]: any[] }; - const countByType = Object.keys(checkupDataTyped).reduce( - (counts, checkupType) => { - counts[checkupType] = checkupDataTyped[checkupType].length; - return counts; - }, - {} as { [checkupType: string]: number } - ); + const countByType = Object.keys(checkupDataTyped).reduce((counts, checkupType) => { + counts[checkupType] = checkupDataTyped[checkupType].length; + return counts; + }, {} as { [checkupType: string]: number }); return ( - Object.keys(deprecations.index_settings).reduce( - (indexDeprecations, indexName) => { - return indexDeprecations.concat( - deprecations.index_settings[indexName].map( - d => - ({ - ...d, - index: indexName, - reindex: /Index created before/.test(d.message), - } as EnrichedDeprecationInfo) - ) - ); - }, - [] as EnrichedDeprecationInfo[] - ); + Object.keys(deprecations.index_settings).reduce((indexDeprecations, indexName) => { + return indexDeprecations.concat( + deprecations.index_settings[indexName].map( + d => + ({ + ...d, + index: indexName, + reindex: /Index created before/.test(d.message), + } as EnrichedDeprecationInfo) + ) + ); + }, [] as EnrichedDeprecationInfo[]); const getClusterDeprecations = (deprecations: DeprecationAPIResponse, isCloudEnabled: boolean) => { const combined = deprecations.cluster_settings diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts b/x-pack/legacy/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts index 6fe4d72db3f16b..41a4552b722de6 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts +++ b/x-pack/legacy/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts @@ -393,9 +393,11 @@ export const reindexServiceFactory = ( const switchAlias = async (reindexOp: ReindexSavedObject) => { const { indexName, newIndexName } = reindexOp.attributes; - const existingAliases = (await callCluster('indices.getAlias', { - index: indexName, - }))[indexName].aliases; + const existingAliases = ( + await callCluster('indices.getAlias', { + index: indexName, + }) + )[indexName].aliases; const extraAlises = Object.keys(existingAliases).map(aliasName => ({ add: { index: newIndexName, alias: aliasName, ...existingAliases[aliasName] }, diff --git a/x-pack/legacy/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx b/x-pack/legacy/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx index 3228b15297974e..219f92ce36e634 100644 --- a/x-pack/legacy/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx @@ -51,14 +51,16 @@ export function withUptimeGraphQL(WrappedComponent: any, query: any) const { client, implementsCustomErrorState, variables } = props; const fetch = () => { setLoading(true); - client.query({ fetchPolicy: 'network-only', query, variables }).then( - (result: any) => { - updateState(result.loading, result.data, result.errors); - }, - (result: any) => { - updateState(false, undefined, result.graphQLErrors); - } - ); + client + .query({ fetchPolicy: 'network-only', query, variables }) + .then( + (result: any) => { + updateState(result.loading, result.data, result.errors); + }, + (result: any) => { + updateState(false, undefined, result.graphQLErrors); + } + ); }; useEffect(() => { fetch(); diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts index 23ead8271f6ff5..b739575a1dd4a0 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts @@ -18,7 +18,10 @@ describe('seriesHasDownValues', () => { it('identifies that a series does not have down values', () => { expect( - seriesHasDownValues([{ timestamp: 123, down: 0, up: 0 }, { timestamp: 125, down: 0, up: 0 }]) + seriesHasDownValues([ + { timestamp: 123, down: 0, up: 0 }, + { timestamp: 125, down: 0, up: 0 }, + ]) ).toBe(false); }); }); diff --git a/x-pack/legacy/plugins/uptime/server/kibana.index.ts b/x-pack/legacy/plugins/uptime/server/kibana.index.ts index 099bbe2fc7185e..874fb2e37e9021 100644 --- a/x-pack/legacy/plugins/uptime/server/kibana.index.ts +++ b/x-pack/legacy/plugins/uptime/server/kibana.index.ts @@ -31,10 +31,7 @@ export interface KibanaServer extends Server { export const initServerWithKibana = (server: UptimeCoreSetup, plugins: UptimeCorePlugins) => { const { usageCollector, xpack } = plugins; - const libs = compose( - server, - plugins - ); + const libs = compose(server, plugins); usageCollector.collectorSet.register(KibanaTelemetryAdapter.initUsageCollector(usageCollector)); initUptimeServer(libs); diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts index cad8b412f3e589..6c71d917940036 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts @@ -166,13 +166,19 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { const buckets: any[] = get(result, 'aggregations.by_id.buckets', []); // @ts-ignore TODO fix destructuring implicit any - return buckets.map(({ latest: { hits: { hits } } }) => { - const timestamp = hits[0]._source[`@timestamp`]; - return { - ...hits[0]._source, - timestamp, - }; - }); + return buckets.map( + ({ + latest: { + hits: { hits }, + }, + }) => { + const timestamp = hits[0]._source[`@timestamp`]; + return { + ...hits[0]._source, + timestamp, + }; + } + ); } /** diff --git a/x-pack/legacy/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx b/x-pack/legacy/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx index f281408c9d4397..aa7cca67745484 100644 --- a/x-pack/legacy/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx +++ b/x-pack/legacy/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx @@ -33,7 +33,11 @@ const SETTINGS = { }; const WATCH_VISUALIZE_DATA = { - count: [[1559404800000, 14], [1559448000000, 196], [1559491200000, 44]], + count: [ + [1559404800000, 14], + [1559448000000, 196], + [1559491200000, 44], + ], }; const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); diff --git a/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/threshold_watch_edit/threshold_watch_edit.tsx b/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/threshold_watch_edit/threshold_watch_edit.tsx index ee89d9bfc176ac..910d4f1e0b15c2 100644 --- a/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/threshold_watch_edit/threshold_watch_edit.tsx +++ b/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/threshold_watch_edit/threshold_watch_edit.tsx @@ -320,7 +320,10 @@ export const ThresholdWatchEdit = ({ pageTitle }: { pageTitle: string }) => { }; })} onChange={async (selected: EuiComboBoxOptionProps[]) => { - setWatchProperty('index', selected.map(aSelected => aSelected.value)); + setWatchProperty( + 'index', + selected.map(aSelected => aSelected.value) + ); const indices = selected.map(s => s.value as string); // reset time field and expression fields if indices are deleted diff --git a/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/watch_edit.tsx b/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/watch_edit.tsx index f3ebee479b664e..25daf190dc1b12 100644 --- a/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/watch_edit.tsx +++ b/x-pack/legacy/plugins/watcher/public/sections/watch_edit/components/watch_edit.tsx @@ -60,7 +60,7 @@ const watchReducer = (state: any, action: any) => { } else { return { ...state, - watch: new (Watch.getWatchTypes())[watch.type]({ + watch: new (Watch.getWatchTypes()[watch.type])({ ...watch, [property]: value, }), @@ -69,7 +69,7 @@ const watchReducer = (state: any, action: any) => { case 'addAction': const { type, defaults } = payload; - const newWatch = new (Watch.getWatchTypes())[watch.type](watch); + const newWatch = new (Watch.getWatchTypes()[watch.type])(watch); newWatch.createAction(type, defaults); return { ...state, diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts index b1795b9439808e..54a4203b89191f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts @@ -14,7 +14,7 @@ export const encryptedSavedObjectsServiceMock = { create(registrations: EncryptedSavedObjectTypeRegistration[] = []) { const mock: jest.Mocked = new (jest.requireMock( './encrypted_saved_objects_service' - )).EncryptedSavedObjectsService(); + ).EncryptedSavedObjectsService)(); function processAttributes>( descriptor: Pick, diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts index 8574293e3e6a66..d101b55d6ad372 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts @@ -370,7 +370,12 @@ describe('#bulkUpdate', () => { mockBaseClient.bulkUpdate.mockResolvedValue(mockedResponse); - await expect(wrapper.bulkUpdate(docs.map(doc => ({ ...doc })), {})).resolves.toEqual({ + await expect( + wrapper.bulkUpdate( + docs.map(doc => ({ ...doc })), + {} + ) + ).resolves.toEqual({ saved_objects: [ { id: 'some-id', diff --git a/x-pack/plugins/features/server/ui_capabilities_for_features.ts b/x-pack/plugins/features/server/ui_capabilities_for_features.ts index 0b3bdfb5993431..22c9379686b348 100644 --- a/x-pack/plugins/features/server/ui_capabilities_for_features.ts +++ b/x-pack/plugins/features/server/ui_capabilities_for_features.ts @@ -56,27 +56,21 @@ function getCapabilitiesFromFeature(feature: Feature): FeatureCapabilities { } function buildCapabilities(...allFeatureCapabilities: FeatureCapabilities[]): UICapabilities { - return allFeatureCapabilities.reduce( - (acc, capabilities) => { - const mergableCapabilities: UICapabilities = _.omit( - capabilities, - ...ELIGIBLE_FLAT_MERGE_KEYS - ); + return allFeatureCapabilities.reduce((acc, capabilities) => { + const mergableCapabilities: UICapabilities = _.omit(capabilities, ...ELIGIBLE_FLAT_MERGE_KEYS); - const mergedFeatureCapabilities = { - ...mergableCapabilities, - ...acc, - }; + const mergedFeatureCapabilities = { + ...mergableCapabilities, + ...acc, + }; - ELIGIBLE_FLAT_MERGE_KEYS.forEach(key => { - mergedFeatureCapabilities[key] = { - ...mergedFeatureCapabilities[key], - ...capabilities[key], - }; - }); + ELIGIBLE_FLAT_MERGE_KEYS.forEach(key => { + mergedFeatureCapabilities[key] = { + ...mergedFeatureCapabilities[key], + ...capabilities[key], + }; + }); - return mergedFeatureCapabilities; - }, - {} as UICapabilities - ); + return mergedFeatureCapabilities; + }, {} as UICapabilities); } diff --git a/x-pack/plugins/licensing/server/__fixtures__/setup.ts b/x-pack/plugins/licensing/server/__fixtures__/setup.ts index a0cb1ea1a2b678..02574d0851ba09 100644 --- a/x-pack/plugins/licensing/server/__fixtures__/setup.ts +++ b/x-pack/plugins/licensing/server/__fixtures__/setup.ts @@ -99,12 +99,7 @@ export async function setup(xpackInfo = {}, pluginInitializerContext: any = {}) clusterClient.callAsInternalUser.mockResolvedValueOnce(licenseMerge(xpackInfo)); const { license$ } = await plugin.setup(coreSetup); - const license = await license$ - .pipe( - skip(1), - take(1) - ) - .toPromise(); + const license = await license$.pipe(skip(1), take(1)).toPromise(); return { plugin, diff --git a/x-pack/plugins/licensing/server/plugin.test.ts b/x-pack/plugins/licensing/server/plugin.test.ts index 355aeef7f20c79..a85e1fb0e8f8f2 100644 --- a/x-pack/plugins/licensing/server/plugin.test.ts +++ b/x-pack/plugins/licensing/server/plugin.test.ts @@ -30,12 +30,7 @@ describe('licensing plugin', () => { clusterClient.callAsInternalUser.mockRejectedValue(new Error('test')); const { license$ } = await plugin.setup(coreSetup); - const finalLicense = await license$ - .pipe( - skip(1), - take(1) - ) - .toPromise(); + const finalLicense = await license$.pipe(skip(1), take(1)).toPromise(); expect(finalLicense).toBeInstanceOf(License); }); diff --git a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts index 60f032652221b8..6f339a6fc9c958 100644 --- a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts +++ b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts @@ -42,7 +42,10 @@ it(`logs out 401 responses`, async () => { let fetchResolved = false; let fetchRejected = false; - http.fetch('/foo-api').then(() => (fetchResolved = true), () => (fetchRejected = true)); + http.fetch('/foo-api').then( + () => (fetchResolved = true), + () => (fetchRejected = true) + ); await logoutPromise; await drainPromiseQueue(); diff --git a/x-pack/plugins/security/server/authentication/api_keys.test.ts b/x-pack/plugins/security/server/authentication/api_keys.test.ts index 3fca1007413d4c..dfddf2036f1b8a 100644 --- a/x-pack/plugins/security/server/authentication/api_keys.test.ts +++ b/x-pack/plugins/security/server/authentication/api_keys.test.ts @@ -24,9 +24,9 @@ describe('API Keys', () => { beforeEach(() => { mockClusterClient = elasticsearchServiceMock.createClusterClient(); mockScopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); - mockClusterClient.asScoped.mockReturnValue((mockScopedClusterClient as unknown) as jest.Mocked< - IScopedClusterClient - >); + mockClusterClient.asScoped.mockReturnValue( + (mockScopedClusterClient as unknown) as jest.Mocked + ); mockLicense = licenseMock.create(); mockLicense.isEnabled.mockReturnValue(true); diff --git a/x-pack/plugins/security/server/authentication/providers/kerberos.ts b/x-pack/plugins/security/server/authentication/providers/kerberos.ts index 2caba6ee20f61f..0e31dd3d51abaf 100644 --- a/x-pack/plugins/security/server/authentication/providers/kerberos.ts +++ b/x-pack/plugins/security/server/authentication/providers/kerberos.ts @@ -54,7 +54,8 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider { const authenticationScheme = getRequestAuthenticationScheme(request); if ( authenticationScheme && - (authenticationScheme !== 'negotiate' && authenticationScheme !== 'bearer') + authenticationScheme !== 'negotiate' && + authenticationScheme !== 'bearer' ) { this.logger.debug(`Unsupported authentication scheme: ${authenticationScheme}`); return AuthenticationResult.notHandled(); diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.ts b/x-pack/plugins/security/server/authentication/providers/oidc.ts index ac8f6cc61edfa1..824189fa77a264 100644 --- a/x-pack/plugins/security/server/authentication/providers/oidc.ts +++ b/x-pack/plugins/security/server/authentication/providers/oidc.ts @@ -250,7 +250,9 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider { // user usually doesn't have `cluster:admin/xpack/security/oidc/prepare`. const { state, nonce, redirect } = await this.options.client.callAsInternalUser( 'shield.oidcPrepare', - { body: oidcPrepareParams } + { + body: oidcPrepareParams, + } ); this.logger.debug('Redirecting to OpenID Connect Provider with authentication request.'); diff --git a/x-pack/plugins/security/server/authentication/providers/pki.ts b/x-pack/plugins/security/server/authentication/providers/pki.ts index 788395feae442a..fa3e1959ba7de1 100644 --- a/x-pack/plugins/security/server/authentication/providers/pki.ts +++ b/x-pack/plugins/security/server/authentication/providers/pki.ts @@ -214,9 +214,11 @@ export class PKIAuthenticationProvider extends BaseAuthenticationProvider { const certificateChain = this.getCertificateChain(peerCertificate); let accessToken: string; try { - accessToken = (await this.options.client.callAsInternalUser('shield.delegatePKI', { - body: { x509_certificate_chain: certificateChain }, - })).access_token; + accessToken = ( + await this.options.client.callAsInternalUser('shield.delegatePKI', { + body: { x509_certificate_chain: certificateChain }, + }) + ).access_token; } catch (err) { this.logger.debug( `Failed to exchange peer certificate chain to an access token: ${err.message}` diff --git a/x-pack/plugins/security/server/authentication/providers/saml.ts b/x-pack/plugins/security/server/authentication/providers/saml.ts index b21a23718f8612..a8683796293afe 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.ts @@ -502,7 +502,9 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider { // user usually doesn't have `cluster:admin/xpack/security/saml/prepare`. const { id: requestId, redirect } = await this.options.client.callAsInternalUser( 'shield.samlPrepare', - { body: { realm: this.realm } } + { + body: { realm: this.realm }, + } ); this.logger.debug('Redirecting to Identity Provider with SAML request.'); diff --git a/x-pack/plugins/security/server/authentication/tokens.ts b/x-pack/plugins/security/server/authentication/tokens.ts index 8e91faa95b459c..2906f28912d5bd 100644 --- a/x-pack/plugins/security/server/authentication/tokens.ts +++ b/x-pack/plugins/security/server/authentication/tokens.ts @@ -96,10 +96,11 @@ export class Tokens { if (refreshToken) { let invalidatedTokensCount; try { - invalidatedTokensCount = (await this.options.client.callAsInternalUser( - 'shield.deleteAccessToken', - { body: { refresh_token: refreshToken } } - )).invalidated_tokens; + invalidatedTokensCount = ( + await this.options.client.callAsInternalUser('shield.deleteAccessToken', { + body: { refresh_token: refreshToken }, + }) + ).invalidated_tokens; } catch (err) { this.logger.debug(`Failed to invalidate refresh token: ${err.message}`); // We don't re-throw the error here to have a chance to invalidate access token if it's provided. @@ -120,10 +121,11 @@ export class Tokens { if (accessToken) { let invalidatedTokensCount; try { - invalidatedTokensCount = (await this.options.client.callAsInternalUser( - 'shield.deleteAccessToken', - { body: { token: accessToken } } - )).invalidated_tokens; + invalidatedTokensCount = ( + await this.options.client.callAsInternalUser('shield.deleteAccessToken', { + body: { token: accessToken }, + }) + ).invalidated_tokens; } catch (err) { this.logger.debug(`Failed to invalidate access token: ${err.message}`); invalidationError = err; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts index 99a4d11fb13b77..0180554a47ccc9 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts @@ -15,11 +15,8 @@ export class FeaturePrivilegeManagementBuilder extends BaseFeaturePrivilegeBuild return []; } - return Object.entries(managementSections).reduce( - (acc, [sectionId, items]) => { - return [...acc, ...items.map(item => this.actions.ui.get('management', sectionId, item))]; - }, - [] as string[] - ); + return Object.entries(managementSections).reduce((acc, [sectionId, items]) => { + return [...acc, ...items.map(item => this.actions.ui.get('management', sectionId, item))]; + }, [] as string[]); } } diff --git a/x-pack/plugins/security/server/authorization/privileges_serializer.ts b/x-pack/plugins/security/server/authorization/privileges_serializer.ts index 3a101324ec196c..0c5b37883bfb14 100644 --- a/x-pack/plugins/security/server/authorization/privileges_serializer.ts +++ b/x-pack/plugins/security/server/authorization/privileges_serializer.ts @@ -28,64 +28,52 @@ export const serializePrivileges = ( ): SerializedPrivileges => { return { [application]: { - ...Object.entries(privilegeMap.global).reduce( - (acc, [privilegeName, privilegeActions]) => { - const name = PrivilegeSerializer.serializeGlobalBasePrivilege(privilegeName); - acc[name] = { - application, - name: privilegeName, - actions: privilegeActions, - metadata: {}, - }; - return acc; - }, - {} as Record - ), - ...Object.entries(privilegeMap.space).reduce( - (acc, [privilegeName, privilegeActions]) => { - const name = PrivilegeSerializer.serializeSpaceBasePrivilege(privilegeName); + ...Object.entries(privilegeMap.global).reduce((acc, [privilegeName, privilegeActions]) => { + const name = PrivilegeSerializer.serializeGlobalBasePrivilege(privilegeName); + acc[name] = { + application, + name: privilegeName, + actions: privilegeActions, + metadata: {}, + }; + return acc; + }, {} as Record), + ...Object.entries(privilegeMap.space).reduce((acc, [privilegeName, privilegeActions]) => { + const name = PrivilegeSerializer.serializeSpaceBasePrivilege(privilegeName); + acc[name] = { + application, + name, + actions: privilegeActions, + metadata: {}, + }; + return acc; + }, {} as Record), + ...Object.entries(privilegeMap.features).reduce((acc, [featureName, featurePrivileges]) => { + Object.entries(featurePrivileges).forEach(([privilegeName, privilegeActions]) => { + const name = PrivilegeSerializer.serializeFeaturePrivilege(featureName, privilegeName); + if (Object.keys(acc).includes(name)) { + throw new Error(`Detected duplicate feature privilege name: ${name}`); + } acc[name] = { application, name, actions: privilegeActions, metadata: {}, }; - return acc; - }, - {} as Record - ), - ...Object.entries(privilegeMap.features).reduce( - (acc, [featureName, featurePrivileges]) => { - Object.entries(featurePrivileges).forEach(([privilegeName, privilegeActions]) => { - const name = PrivilegeSerializer.serializeFeaturePrivilege(featureName, privilegeName); - if (Object.keys(acc).includes(name)) { - throw new Error(`Detected duplicate feature privilege name: ${name}`); - } - acc[name] = { - application, - name, - actions: privilegeActions, - metadata: {}, - }; - }); + }); - return acc; - }, - {} as Record - ), - ...Object.entries(privilegeMap.reserved).reduce( - (acc, [privilegeName, privilegeActions]) => { - const name = PrivilegeSerializer.serializeReservedPrivilege(privilegeName); - acc[name] = { - application, - name, - actions: privilegeActions, - metadata: {}, - }; - return acc; - }, - {} as Record - ), + return acc; + }, {} as Record), + ...Object.entries(privilegeMap.reserved).reduce((acc, [privilegeName, privilegeActions]) => { + const name = PrivilegeSerializer.serializeReservedPrivilege(privilegeName); + acc[name] = { + application, + name, + actions: privilegeActions, + metadata: {}, + }; + return acc; + }, {} as Record), }, }; }; diff --git a/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts b/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts index c590c24923a8c0..609b7d2f35c4b0 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts @@ -208,19 +208,16 @@ function transformRoleApplicationsToKibanaPrivileges( base: basePrivileges.map(privilege => PrivilegeSerializer.serializeGlobalBasePrivilege(privilege) ), - feature: featurePrivileges.reduce( - (acc, privilege) => { - const featurePrivilege = PrivilegeSerializer.deserializeFeaturePrivilege(privilege); - return { - ...acc, - [featurePrivilege.featureId]: getUniqueList([ - ...(acc[featurePrivilege.featureId] || []), - featurePrivilege.privilege, - ]), - }; - }, - {} as RoleKibanaPrivilege['feature'] - ), + feature: featurePrivileges.reduce((acc, privilege) => { + const featurePrivilege = PrivilegeSerializer.deserializeFeaturePrivilege(privilege); + return { + ...acc, + [featurePrivilege.featureId]: getUniqueList([ + ...(acc[featurePrivilege.featureId] || []), + featurePrivilege.privilege, + ]), + }; + }, {} as RoleKibanaPrivilege['feature']), spaces: ['*'], }; } @@ -235,19 +232,16 @@ function transformRoleApplicationsToKibanaPrivileges( base: basePrivileges.map(privilege => PrivilegeSerializer.deserializeSpaceBasePrivilege(privilege) ), - feature: featurePrivileges.reduce( - (acc, privilege) => { - const featurePrivilege = PrivilegeSerializer.deserializeFeaturePrivilege(privilege); - return { - ...acc, - [featurePrivilege.featureId]: getUniqueList([ - ...(acc[featurePrivilege.featureId] || []), - featurePrivilege.privilege, - ]), - }; - }, - {} as RoleKibanaPrivilege['feature'] - ), + feature: featurePrivileges.reduce((acc, privilege) => { + const featurePrivilege = PrivilegeSerializer.deserializeFeaturePrivilege(privilege); + return { + ...acc, + [featurePrivilege.featureId]: getUniqueList([ + ...(acc[featurePrivilege.featureId] || []), + featurePrivilege.privilege, + ]), + }; + }, {} as RoleKibanaPrivilege['feature']), spaces: resources.map(resource => ResourceSerializer.deserializeSpaceResource(resource)), }; }), diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts index f802c011f207e2..3c04508e3a74ac 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts @@ -171,7 +171,10 @@ describe(`spaces disabled`, () => { const client = new SecureSavedObjectsClientWrapper(options); - const objects = [{ type: type1, attributes: {} }, { type: type2, attributes: {} }]; + const objects = [ + { type: type1, attributes: {} }, + { type: type2, attributes: {} }, + ]; const apiCallOptions = Object.freeze({ namespace: 'some-ns' }); await expect(client.bulkCreate(objects, apiCallOptions)).rejects.toThrowError( options.forbiddenError @@ -483,7 +486,10 @@ describe(`spaces disabled`, () => { const client = new SecureSavedObjectsClientWrapper(options); - const objects = [{ type: type1, id: `bar-${type1}` }, { type: type2, id: `bar-${type2}` }]; + const objects = [ + { type: type1, id: `bar-${type1}` }, + { type: type2, id: `bar-${type2}` }, + ]; const apiCallOptions = Object.freeze({ namespace: 'some-ns' }); await expect(client.bulkGet(objects, apiCallOptions)).rejects.toThrowError( options.forbiddenError @@ -526,7 +532,10 @@ describe(`spaces disabled`, () => { const client = new SecureSavedObjectsClientWrapper(options); - const objects = [{ type: type1, id: `id-${type1}` }, { type: type2, id: `id-${type2}` }]; + const objects = [ + { type: type1, id: `id-${type1}` }, + { type: type2, id: `id-${type2}` }, + ]; const apiCallOptions = Object.freeze({ namespace: 'some-ns' }); await expect(client.bulkGet(objects, apiCallOptions)).resolves.toBe(apiCallReturnValue); diff --git a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts index f25908147bfe5b..4f78828b14dc20 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts @@ -172,7 +172,10 @@ describe('copy to space', () => { it(`requires objects to be unique`, async () => { const payload = { spaces: ['a-space'], - objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], + objects: [ + { type: 'foo', id: 'bar' }, + { type: 'foo', id: 'bar' }, + ], }; const { copyToSpace } = await setup(); @@ -185,7 +188,10 @@ describe('copy to space', () => { it('does not allow namespace agnostic types to be copied (via "supportedTypes" property)', async () => { const payload = { spaces: ['a-space'], - objects: [{ type: 'globalType', id: 'bar' }, { type: 'visualization', id: 'bar' }], + objects: [ + { type: 'globalType', id: 'bar' }, + { type: 'visualization', id: 'bar' }, + ], }; const { copyToSpace, legacyAPI } = await setup(); @@ -307,7 +313,10 @@ describe('copy to space', () => { it(`requires objects to be unique`, async () => { const payload = { retries: {}, - objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], + objects: [ + { type: 'foo', id: 'bar' }, + { type: 'foo', id: 'bar' }, + ], }; const { resolveConflicts } = await setup(); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 7a984acb2c09f5..1252dd1400807f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -90,10 +90,9 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all at space1': expect(response.statusCode).to.eql(200); - const alertTestRecord = (await esTestIndexTool.waitForDocs( - 'alert:test.always-firing', - reference - ))[0]; + const alertTestRecord = ( + await esTestIndexTool.waitForDocs('alert:test.always-firing', reference) + )[0]; expect(alertTestRecord._source).to.eql({ source: 'alert:test.always-firing', reference, @@ -103,10 +102,9 @@ export default function alertTests({ getService }: FtrProviderContext) { reference, }, }); - const actionTestRecord = (await esTestIndexTool.waitForDocs( - 'action:test.index-record', - reference - ))[0]; + const actionTestRecord = ( + await esTestIndexTool.waitForDocs('action:test.index-record', reference) + )[0]; expect(actionTestRecord._source).to.eql({ config: { unencrypted: `This value shouldn't get encrypted`, @@ -265,10 +263,9 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - alertTestRecord = (await esTestIndexTool.waitForDocs( - 'alert:test.authorization', - reference - ))[0]; + alertTestRecord = ( + await esTestIndexTool.waitForDocs('alert:test.authorization', reference) + )[0]; expect(alertTestRecord._source.state).to.eql({ callClusterSuccess: false, savedObjectsClientSuccess: false, @@ -288,10 +285,9 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - alertTestRecord = (await esTestIndexTool.waitForDocs( - 'alert:test.authorization', - reference - ))[0]; + alertTestRecord = ( + await esTestIndexTool.waitForDocs('alert:test.authorization', reference) + )[0]; expect(alertTestRecord._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, @@ -362,10 +358,9 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - actionTestRecord = (await esTestIndexTool.waitForDocs( - 'action:test.authorization', - reference - ))[0]; + actionTestRecord = ( + await esTestIndexTool.waitForDocs('action:test.authorization', reference) + )[0]; expect(actionTestRecord._source.state).to.eql({ callClusterSuccess: false, savedObjectsClientSuccess: false, @@ -385,10 +380,9 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - actionTestRecord = (await esTestIndexTool.waitForDocs( - 'action:test.authorization', - reference - ))[0]; + actionTestRecord = ( + await esTestIndexTool.waitForDocs('action:test.authorization', reference) + )[0]; expect(actionTestRecord._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts index 02e0b3795fcc52..badec079d68285 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts @@ -68,10 +68,9 @@ export default function alertTests({ getService }: FtrProviderContext) { const response = await alertUtils.createAlwaysFiringAction({ reference }); expect(response.statusCode).to.eql(200); - const alertTestRecord = (await esTestIndexTool.waitForDocs( - 'alert:test.always-firing', - reference - ))[0]; + const alertTestRecord = ( + await esTestIndexTool.waitForDocs('alert:test.always-firing', reference) + )[0]; expect(alertTestRecord._source).to.eql({ source: 'alert:test.always-firing', reference, @@ -81,10 +80,9 @@ export default function alertTests({ getService }: FtrProviderContext) { reference, }, }); - const actionTestRecord = (await esTestIndexTool.waitForDocs( - 'action:test.index-record', - reference - ))[0]; + const actionTestRecord = ( + await esTestIndexTool.waitForDocs('action:test.index-record', reference) + )[0]; expect(actionTestRecord._source).to.eql({ config: { unencrypted: `This value shouldn't get encrypted`, @@ -207,10 +205,9 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(200); objectRemover.add(Spaces.space1.id, response.body.id, 'alert'); - const alertTestRecord = (await esTestIndexTool.waitForDocs( - 'alert:test.authorization', - reference - ))[0]; + const alertTestRecord = ( + await esTestIndexTool.waitForDocs('alert:test.authorization', reference) + )[0]; expect(alertTestRecord._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, @@ -263,10 +260,9 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(200); objectRemover.add(Spaces.space1.id, response.body.id, 'alert'); - const actionTestRecord = (await esTestIndexTool.waitForDocs( - 'action:test.authorization', - reference - ))[0]; + const actionTestRecord = ( + await esTestIndexTool.waitForDocs('action:test.authorization', reference) + )[0]; expect(actionTestRecord._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, diff --git a/x-pack/test/functional/services/infra_source_configuration_form.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts index a311f38b67c18a..ab61d5232fa1c7 100644 --- a/x-pack/test/functional/services/infra_source_configuration_form.ts +++ b/x-pack/test/functional/services/infra_source_configuration_form.ts @@ -38,10 +38,12 @@ export function InfraSourceConfigurationFormProvider({ getService }: FtrProvider async addTimestampLogColumn() { await (await this.getAddLogColumnButton()).click(); await retry.try(async () => { - await (await testSubjects.findDescendant( - '~addTimestampLogColumn', - await this.getAddLogColumnPopover() - )).click(); + await ( + await testSubjects.findDescendant( + '~addTimestampLogColumn', + await this.getAddLogColumnPopover() + ) + ).click(); }); }, async addFieldLogColumn(fieldName: string) { @@ -49,10 +51,9 @@ export function InfraSourceConfigurationFormProvider({ getService }: FtrProvider await retry.try(async () => { const popover = await this.getAddLogColumnPopover(); await (await testSubjects.findDescendant('~fieldSearchInput', popover)).type(fieldName); - await (await testSubjects.findDescendant( - `~addFieldLogColumn:${fieldName}`, - popover - )).click(); + await ( + await testSubjects.findDescendant(`~addFieldLogColumn:${fieldName}`, popover) + ).click(); }); }, async getLogColumnPanels(): Promise { @@ -98,10 +99,9 @@ export function InfraSourceConfigurationFormProvider({ getService }: FtrProvider return await testSubjects.find('~sourceConfigurationContent'); }, async saveConfiguration() { - await (await testSubjects.findDescendant( - '~applySettingsButton', - await this.getForm() - )).click(); + await ( + await testSubjects.findDescendant('~applySettingsButton', await this.getForm()) + ).click(); await retry.try(async () => { const element = await testSubjects.findDescendant( diff --git a/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/encrypted_saved_objects_api.ts b/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/encrypted_saved_objects_api.ts index 1c7be6def614d1..98d653d71b5ec3 100644 --- a/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/encrypted_saved_objects_api.ts +++ b/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/encrypted_saved_objects_api.ts @@ -252,7 +252,10 @@ export default function({ getService }: FtrProviderContext) { }); describe('within a default space', () => { - runTests(() => '/api/saved_objects/', id => `${SAVED_OBJECT_WITH_SECRET_TYPE}:${id}`); + runTests( + () => '/api/saved_objects/', + id => `${SAVED_OBJECT_WITH_SECRET_TYPE}:${id}` + ); }); describe('within a custom space', () => { diff --git a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts index 85e877912ab6c0..7383bb3409f1a6 100644 --- a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts @@ -139,19 +139,16 @@ export function copyToSpaceTestSuiteFactory( } const { countByType } = spaceBucket; - const expectedBuckets = Object.entries(expectedCounts).reduce( - (acc, entry) => { - const [type, count] = entry; - return [ - ...acc, - { - key: type, - doc_count: count, - }, - ]; - }, - [] as CountByTypeBucket[] - ); + const expectedBuckets = Object.entries(expectedCounts).reduce((acc, entry) => { + const [type, count] = entry; + return [ + ...acc, + { + key: type, + doc_count: count, + }, + ]; + }, [] as CountByTypeBucket[]); expectedBuckets.sort(bucketSorter); countByType.buckets.sort(bucketSorter); diff --git a/x-pack/test_utils/testbed/mount_component.tsx b/x-pack/test_utils/testbed/mount_component.tsx index b1f82ceae3b424..4984ccca7cef9c 100644 --- a/x-pack/test_utils/testbed/mount_component.tsx +++ b/x-pack/test_utils/testbed/mount_component.tsx @@ -31,9 +31,10 @@ const getCompFromConfig = ({ Component, memoryRouter, store, onRouter }: Config) const { componentRoutePath, initialEntries, initialIndex } = memoryRouter!; // Wrap the componenet with a MemoryRouter and attach it to a react-router - Comp = WithMemoryRouter(initialEntries, initialIndex)( - WithRoute(componentRoutePath, onRouter)(Comp) - ); + Comp = WithMemoryRouter( + initialEntries, + initialIndex + )(WithRoute(componentRoutePath, onRouter)(Comp)); } return Comp; diff --git a/yarn.lock b/yarn.lock index d0ebd30d701369..4990d2bab0a77a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21805,10 +21805,10 @@ prettier@1.16.4: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g== -prettier@^1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" - integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== +prettier@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== pretty-bytes@^4.0.2: version "4.0.2" From bf8f1306b30b3ff20fd9ea98424327f9040e3fed Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Wed, 13 Nov 2019 18:19:25 +0100 Subject: [PATCH 11/59] [SIEM] Events viewer fixes (#50175) * updates KQL_SEARCH_BAR locator * updates HEADER_SUBTITLE locator * waits for the events to be loaded --- .../siem/cypress/integration/lib/events_viewer/helpers.ts | 5 +++++ .../siem/cypress/integration/lib/events_viewer/selectors.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/helpers.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/helpers.ts index e611744754912f..02a80f6c0329cb 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/helpers.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/helpers.ts @@ -6,12 +6,17 @@ import { EVENTS_VIEWER_FIELDS_BUTTON, KQL_SEARCH_BAR } from './selectors'; import { FIELDS_BROWSER_CONTAINER } from '../fields_browser/selectors'; +import { SERVER_SIDE_EVENT_COUNT } from '../timeline/selectors'; import { DEFAULT_TIMEOUT } from '../util/helpers'; /** Opens the eventsViewer Field Browser */ export const openEventsViewerFieldsBrowser = () => { cy.get(EVENTS_VIEWER_FIELDS_BUTTON, { timeout: DEFAULT_TIMEOUT }).click({ force: true }); + cy.get(SERVER_SIDE_EVENT_COUNT, { timeout: DEFAULT_TIMEOUT }) + .invoke('text') + .should('not.equal', '0'); + cy.get(FIELDS_BROWSER_CONTAINER).should('exist'); }; diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/selectors.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/selectors.ts index c6cf4d455fb593..0e3717feef7ad0 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/selectors.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/events_viewer/selectors.ts @@ -11,10 +11,10 @@ export const EVENTS_VIEWER_PANEL = '[data-test-subj="events-viewer-panel"]'; export const EVENTS_VIEWER_FIELDS_BUTTON = `${EVENTS_VIEWER_PANEL} [data-test-subj="show-field-browser-gear"]`; /** The KQL search bar that exists at the top of most pages */ -export const KQL_SEARCH_BAR = '[data-test-subj="kqlInput"]'; +export const KQL_SEARCH_BAR = '[data-test-subj="queryInput"]'; /** The Events Viewer Showing N events header subtitle */ -export const HEADER_SUBTITLE = `${EVENTS_VIEWER_PANEL} [data-test-subj="subtitle"]`; +export const HEADER_SUBTITLE = `${EVENTS_VIEWER_PANEL} [data-test-subj="header-panel-subtitle"]`; /** The inspect query modal */ export const INSPECT_MODAL = '[data-test-subj="modal-inspect-euiModal"]'; From aca8ddb4f00287464b67c7858ebbd8ef1dfaa300 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 13 Nov 2019 12:42:40 -0500 Subject: [PATCH 12/59] [Monitoring] Fix logstash pipelines page in multi-cluster environment (#50166) * Ensure we pass in the clusterUuid * Add test --- .../logstash/pipelines/cluster_pipelines.js | 2 +- .../fixtures/multicluster_pipelines.json | 1 + .../apis/monitoring/logstash/index.js | 1 + .../logstash/multicluster_pipelines.js | 43 + .../data.json.gz | Bin 0 -> 18808 bytes .../mappings.json | 1591 +++++++++++++++++ 6 files changed, 1637 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/api_integration/apis/monitoring/logstash/fixtures/multicluster_pipelines.json create mode 100644 x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js create mode 100644 x-pack/test/functional/es_archives/monitoring/logstash_pipelines_multicluster/data.json.gz create mode 100644 x-pack/test/functional/es_archives/monitoring/logstash_pipelines_multicluster/mappings.json diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js index c55f8c19037d58..6e8243b72e6a0e 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js @@ -67,7 +67,7 @@ export function logstashClusterPipelinesRoute(server) { } const { pageOfPipelines, totalPipelineCount } = - await getPaginatedPipelines(req, lsIndexPattern, {}, metricSet, pagination, sort, queryText); + await getPaginatedPipelines(req, lsIndexPattern, { clusterUuid }, metricSet, pagination, sort, queryText); // Just the IDs for the rest const pipelineIds = pageOfPipelines.map(pipeline => pipeline.id); diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/fixtures/multicluster_pipelines.json b/x-pack/test/api_integration/apis/monitoring/logstash/fixtures/multicluster_pipelines.json new file mode 100644 index 00000000000000..1094e2b1a40043 --- /dev/null +++ b/x-pack/test/api_integration/apis/monitoring/logstash/fixtures/multicluster_pipelines.json @@ -0,0 +1 @@ +{"pipelines":[{"id":"uno","metrics":{"throughput":{"bucket_size":"10 seconds","timeRange":{"min":1573485225266,"max":1573485425399},"metric":{"app":"logstash","field":"logstash_stats.pipelines.events.out","label":"Pipeline Throughput","description":"Number of events emitted per second by the Logstash pipeline at the outputs stage.","units":"e/s","format":"0,0.[00]","hasCalculation":true,"isDerivative":false},"data":[[1573485230000,0]]},"nodesCount":{"bucket_size":"10 seconds","timeRange":{"min":1573485225266,"max":1573485425399},"metric":{"app":"logstash","field":"logstash_stats.logstash.uuid","label":"Pipeline Node Count","description":"Number of nodes on which the Logstash pipeline is running.","units":"","format":"0,0.[00]","hasCalculation":true,"isDerivative":false},"data":[[1573485230000,1]]}},"latestThroughput":0,"latestNodesCount":1}],"clusterStatus":{"node_count":1,"events_in_total":0,"events_out_total":0,"avg_memory":1037959168,"avg_memory_used":203687512,"max_uptime":863288,"pipeline_count":1,"queue_types":{"memory":1,"persisted":0},"versions":["8.0.0"]},"totalPipelineCount":1} diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/index.js b/x-pack/test/api_integration/apis/monitoring/logstash/index.js index d07e8a812ad57b..6406942f029691 100644 --- a/x-pack/test/api_integration/apis/monitoring/logstash/index.js +++ b/x-pack/test/api_integration/apis/monitoring/logstash/index.js @@ -9,6 +9,7 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./overview')); loadTestFile(require.resolve('./nodes')); loadTestFile(require.resolve('./node_detail')); + loadTestFile(require.resolve('./multicluster_pipelines')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js b/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js new file mode 100644 index 00000000000000..bea09562bdb11e --- /dev/null +++ b/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import fixture from './fixtures/multicluster_pipelines'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('pipelines listing multicluster', () => { + const archive = 'monitoring/logstash_pipelines_multicluster'; + const timeRange = { + min: '2019-11-11T15:13:45.266Z', + max: '2019-11-11T15:17:05.399Z' + }; + const pagination = { + size: 10, + index: 0 + }; + + before('load archive', () => { + return esArchiver.load(archive); + }); + + after('unload archive', () => { + return esArchiver.unload(archive); + }); + + it('should get the pipelines', async () => { + const { body } = await supertest + .post('/api/monitoring/v1/clusters/hJS0FZ7wR9GGdYs8RNW8pw/logstash/pipelines') + .set('kbn-xsrf', 'xxx') + .send({ timeRange, pagination }) + .expect(200); + + expect(body).to.eql(fixture); + }); + }); +} diff --git a/x-pack/test/functional/es_archives/monitoring/logstash_pipelines_multicluster/data.json.gz b/x-pack/test/functional/es_archives/monitoring/logstash_pipelines_multicluster/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..42d6d190db0cd39c659b97dd111f02dddfc5a4fc GIT binary patch literal 18808 zcmb5VQ*dY9+pe2*Y<7%}ZQEAIwr$(C?WAK{9ox2T{o-WhegAuX-}-jd-c@TJjafAh zMm-0k=6zq+z>kCk`sew9a_MazyWYG8c>0X+_Xo)eB%2zS(d;HMPa&0=Gdf~6hyNjv zViwC-e<*%OO>?)cD_L(PLEIFTT4%a~W@aEyD6)Az==pM-nwTiyz*HJYMg~IX1Q9!j zPn)e5|9OY-2J=>NU98F{H0&C+-4qM?@d!}Fc)vyOZuhX5{~M079bJafcHE3jy%!|v zlEpqsIF*yat9LYe{(u=Va!Wmy^O+P!x8`$Qw^G`)l_-mcTfTP(=SDnE`{1DL27-eE0~YQ zBsLsvem=(5<9su_bwjR?OLu@xFSNW zj%j}^@oCipfg!7-GlFNCuWlOMPZ}l>VJoi%CxX~KtE4T$hlo(poD+&?7rKjRI~v9n z=63sNL`TXK_3~Rwr?ei7UY6yy1HK-d6+(c3K~i$>B6r*aH)P8#K|^mBNt(v7KzNa1 z)ig9WR8W^;970&^ugJPlo_&uAyF5z0rov2`b52N4IR{|WCU8t>WKE(l#^!-nf1U12 z8LEtlbWXN~4<_9c7dWY?j1NXjl29dAD%C5DN|Nx|C2O@t@V!6z@_3)F;%|3maI@T^ ze# z&E^!Np0~!QfJBlkVB< z9H);7?cExC5~wgK$wIYQsnnn_`J~Q*u0x!yH4_elZffWa*uafJ!{~ag{2gW}M$nCi z2`wNUAR|qWn2#vHu8$BlEd_&90t(seFAU_oR6w0=$ZNTJ33zC<t8+Ju`tl00NNb^4tkLfVbBZ8?89jGM>iWbZH*J{ z2czmYrVEK&nsp#>J1!+u8CFD^{Nc&*(|^E=x)VLppat`AcRu^i|z0wbBL~?k?m%Krz;N zrTtrNl}J-bJE|^zqo{lGDl#~ioGa7!cfp$c)=)P$E>2EXQPFtuu{i7t*Lr{AbQ+?| z^#T2ijl}-?n7~ihRjTZd4@3kYrC8AeCyHgzFZHI&g-!)YbmwDF4SgCRag<%CmLXG` zC=Obcr^)lK6UuG7&|f zde}Xj^b#a%hfHGXV|>%tzP^ zb55{XP=_**guO7?y|XP?pnlK}mgo_OfuPnv(CV&|zk?KxS7b?A&MQSZCG1lAI`gzI z^ri5Xs6f)8LPEmPp>14$-`KH7q^u!QwOzNtR4$74k!dKC?KPIwXOvqkEnr0)D-mhC zZvvGsqEtvtNB2 z<9WN1TSo)qa5`|3;=Lw%RC@0?=A|~2{$k?uqQ60nZ0%P5;pV*S{l1t3vY8HhCh7qb z>THsslF9Oh3}{Py$rduxKs-eQ(ttb6qq1--d6|8DJD%qC(SH8~98D~ZYCbJXk~Ng1 zMHVOLDANVvdKg+Xl+pW{2CB!&x5hH;bZnBVM-&teua2JyG?w*2uIfIH1`%I zy+LbO!BkvVCni9VO^)#vTG5$~A4RVqYR+4f5#VUgi_f_UXzqxJL1S*T&W9!B?=Cv$ zU?Fu~bHH`uDBIsYr=#lFo2ImP5S-KOzY;`J&%hBUgP0o?I6p{;UIR$6Iq14yp9g7f z;^a37*$}-_9`*_&KEuBMmVg$`@e!KCr&az#}F4pn%*`EozT;Dc~UvW9k*p5SI zKWr&PW2PRmH^m0pSx&@6BPAwZUM{Sh`tI#8N!OUP=D0JqDxH&G9C3myf#R4sS>r+? zS%-C{mKkOVT^Ck&K>9faN^v-3O6$!;ER*A8;r33Pl^iYqbnt7j1oh_KjNv}5&f52B z4$x87MWc6@9D$~#S#%k6d1e^&M{tnS*u`n`TpJ;y+N**s%1u@$bo7*4`qLY5#Ye`8 z$$OuesCX1Pe{wMGn(#(1EuJf*3mqqM9J^;x$LcQz3yq2$f-kqlLE(b@k{J$2Z>T#@r|G&SDlXcH z|C!lZxfA9Z<9WCHa3BR^?f{)iIvU+o+?15FWGJEFA=Tw$ngAUi5LI!WXjslI4?1N$ z^@NAZ75QsdAmj(HWR}@4<1pJrFmRaW&euK*Lk9l<+O!+ab0^%@^N%p*D$J|v39r!C62Dv2toCByKxv<-n+9+sn&GzE0 z69EWthWOqq@_j1%&b%f}y?xkot}~R{P2oMLIYb#mM=}Wz&x0N18s~+NBrAAQk_g2pczqLr_B?gKK=#E5J9K)aNo4#g+;+>Gr7WST zPj`jt1Bm|k2;wQ53&yJpRT|c#ZIfOve`sE+IvT`6d-Y`8+8X~%nJ&a`LkF= zolk)HyIRSDb@LH5ZcLhb7ijO_+@8jdJ^``pW+=c`$vyq5S!_WPLb|cTy7t=f6%GLs zCU}EvkCH4I!L66`;&{==o=k>Jv|5V(by=XECL>Y8RxSazBgn|_+I>>6iz6T zb9y3?wgJO05zhOMjiE-xqfpSn-75ks8M<<*u0PIu9a)a5b*x<+E5?MeCJD1P#J9BQ z)<+>sH4zc=NvIi@z{w@`ZVcPWl~jK30?fPxiqwQYmV<-RTslfFia?6WiBi#tTG+UJ8ntcCkZC8zdolP#-{GQ*0@ z0`H6ix0Vp+!Xf1HIBS~9)X-60(M%(7&p_-To4ZLL%kxt)) zR>)1n1mryjQin{|EauR}@s&pPv=N!0!`Hs_YOUtYKrbP>j+UIaSyk6oxXfHtp$R>~pnROgIx1I5f7&`Tv z1(~c@T@-Dkl^fl{j{r#;D|s3qyLStJ@+Lbni+l+xoLU8bud@tsk~|H(^yYNY_B9F5^?3N!w)ATD_*k3`uS1a%4^vp87`0$jJ12;l8L#a8?& zV3o94Ru+Hv_Y8ivB+`>ADApyA%#~hA=Yn zu?6X;DjE@j6SzZ?OXm9B5svOMPRh`}=Y|0a?YR+VG_1dYIBf!{AS@O++v^L!|}|3O`K4K3|3uEi-& z@vM`Ls_{xL4pEbBR@9X6HwiNg-JSI}4IN(#HD>|R%Z{>YtcLt)oGlCCA3R=2!Qlqn zAuJA`et9fuHdMZlcJNv-ry^$wdP*80t#PeRG<)3pHFT40`QLpwKZMJ@cZ~<9#($2D z!%TMQt=!Wec+|_DM2U7&EpWidBUFX?m^RV`NJ&nz>Iuzi0>?G&8hP}`lpysfa;^ii z)~ubLFH40qz6K_vNt1kgq*<;XU|5OoDV_i+SJtBy>*aE9l}o%2T~Du@HePG@Y^6Jg zs{3b&k7vnGs#ZQ8U#nTVn_Y5|VZD|bb#gGyVNh+Jxhm_aQZUWO(;8NqShyPF!efOz zSt0-@<9uU_$?8fQ%uKiX+E_A60=UNqqj0EK_jQe z02+>F-LLnL@g`p1$5WJkz-4Pgc+?{rydNOkzc`p_T=b7)xXQ$zem?csA{LjdBR8>rJ6lA4(v!!oMQb z5TAC=PsnOKNYERXvfIJi*tz{G7-{f@1Xb`Bh$_kM^`@)e}E`Jth>Z8yVqvf#gU!sgVF8w@$g!4 zDmO-_U_r|sPEK7rnmTfIX)K8O+J#^RAj6ymFaSFb-)U*EN}%tp4`L2*{+*QOxivtO;Vdp2`|E2Za?(32haKI}?)ALvW$Tra-oxi3b@nJ%~rS zh<|>>uPH(eU^iW++87PqZCPe5>TKcUpO^yznqjD+XsGNZlmU(y?mimSzS_`eknMkN zxkg8v5>zpd288^D?9hMo#!^u?PiZ9IH9FAVy|W|e>9Ek(bnR_BEv;Z#;@}_6N*l*> ztEr7#a^UxZA?gL>ps)35#p1=OQIRiY1=PCCZCcpej;+%@XO_dA~BtaIGZlDETjN@5#elBIUPh3E9l$f806Q=1s!O5INAuR zl$V!eC9laOmT@Cm*~H~G=2`uvChWsu&+1J~Y4(XL6-_R z>p|5!DmHdFzw}|{&&p0qj4nJ(D$>Oi39m+iWZs+Zv~iyf`cFqw(FzWftR+DKDN70- z8nGl2r!-(d^^`AESk={XGdRNa&5Z;v##6WB-O2$$EhHI9>`gHZhlf5DwDfAVhl}Vc z*hE2lBzm2wF~_4~A&vKg3rrQ!zaqs97%ODlNE+70^1K_2;?9yB;xAv1KUd*8$vec{ zp}U5nm<-~VxU*ykWz*u*0kD7e2p&AHnD&Rq89GUt!x^m-xqF|XSn)u*uw<0li*sno zK?2j_!jZdR^9F7MmQ4JjnJTXlm9Y8upwi|sS&32xN1{y4{!U15Yv=q@iW{-)p!X;E z)2}N1VmD67)mmKBUCE&Pc>%^H>cf&}`C=b#EI90(l@BatCw>A6iwhSO;&zel7sG6Q z5a%CodPvWs8R0yU=0bvD;n{f?iBr+m={s%a9nT zjQvqU_{zHK4R6%r%@rqDtj0`$>jV>l1Wy*CMtz%y?;i><`BI z%S1&rUom!O36JnQhv00pVuC9U&3Plc@Ngg`Mx$l1F39F5t<%1w=r$G}YA5Ng{e+Qw zbA^?TXYj;faJH;jkhJ$%Dg3E39HJI5I-KO;nO-RmZhJFCxIiKI9-SPeM_1(! z?Q!h#*N*bf>W(b!f8UjTmp#|Ee-fH6c8*cJ2spcu6l6T_;niSZh_b=t$gZk1PexV2 zWsLJ86O#8K7HP^tv&gI~E3Us+SkDNc#f##Hj0YfJr(sWV>$WExH8G?3Fukzt3cMg~ zT#;^O`Dm)lF#FopZyHs*NY&onyAlmtUI^@qZC{dFt?7DjVejN{eO}0J`AVXQVdQS| zHhCF@zmPP>;vrU9Z*h2OYTC(miSQ$cU$k`TBN@~l8$Z5mbeN6V@GSjePb#^X-o}v) zPh>XaPclo~zbUST>kl}z3Yim3-4N&Da)sIxAh}h=Y2Hd80g0)}f$WQ36lVY0Q5h62 zVa^DXoptQ+lrrZHRY)?zk)I96?~)}VS6~xTFz(dcdD2V-6mTqP!hevk-1)0}Fs zjX+^-^1!*s`zWioDxNBn%rh-OUXe*bK1t38B?w4qvL}!$z*e!;h@g)&HMdwX#+45@ zrvRsRv}#qQu7;Tx$EbQfrAYc}0RrHR97ma<@zb_Tw8P*2K>H3%AEVTfBD!)AMuA1K zbkVyU&6W%0dGP59eUeaAB$Y|E3VjHIP&FAG1J}pmPg(OV)7yPD55=F*Uj6}Nd9HJ4 z2Y4x|NJ0q4+nyaaeanSG=;Cd-g68?-jzhck0(Xc%e5x|};o@*|(+jcN>mA|yrU-E1 zvO`Mf#^z29PxE+F;8BgvTQIm(rauWV2u!ZxR2(5t1Seuh5#}DIR1mH#0Tq%=rXGyNvje=o-X-B2wOFW}w6~F7b^&E(Tu(OxVsLFvnh3dmaN@ zB@L~I5cc4eS#7ML>%bD$wb@u%sD)JZf_@Ms(W;QF{Cu^u{T(V)4jJ!kin0SAU{I!T zz;9BMw5wWCSJb+YVK#Cu%;`alskwqG%=Ao9r=5nDQ@QLWwjbz=5I%Pb>&7Oy6>u6f zC-%$tmmnH*bhS1PcldGjPAWHrCzJdl<2UvJ8O_8`KRK$s~)SVSL0IgoK-{vU_iYGPtCq4tbLax zx*X1Ec^CVOiop93#9a<8mpb6*un#{;wCZtEmjw7DJcj+d<*$?8X077JOM7ATx(9=& z=3xpz+Y1)<6ueZVHFk1tu9Pec$@ui45Xg_o!bMr;e2E@SVhONX+>#a;|M?S5<}nq9 z+i`ju(*&8P^Ux;>4A%7@!RW2nnMpjMck_Ud9WHTLwC%IB@=v z9A}Gur^e?&AeR)UD){LS=?*!;tI$1s`V0*D%G?$Wv?4T9>T0I7>p*e>_EwDFlgE~n zryB76p@&pYaaL-s2yR%=F#k2hZn%GPkS`>1&WU6n71Y=78>}uq9Y?zxE@n7ffS^g9 zxd6!&SD54F$*wCLUKhLW$4jPU#)|qJXi~{`m26jwXLC=-UcZeIS0r)cus&jtYQaSN zoN>u~N-xkN(Yx&-LQh(ZnNg^r=LLP_U#gr=Y09#}61zeoPB;_|X~W}PjB!w#m&w~c z-l9V{qsJZm-AzzYcY+Upiqllo2ZX@K7%uQeC`HpG>y_yIXjP-!XyYY+C5Nt ziWslea1%Ets}fj8^#L%!a*blW5Qg1xbg~TLdiim_`ef5LpPqz^@KEd0sL*(x8V?r) zLF~NDz*Cuyz#9QQs$NU~WjTE*Jx56qLRsrf2V+I?zj-fJvKPMc9VPal@7MBtYR<>) zWW}f=itjC-yXwAB+11DUYUyr=sV}#zvcn9n(@f)Vm>+LmU@$PEKm69f*X5-0`_V(> z=dQsn_}YAf+iN4;$#321t8vS&XOI6cRJ$U|bM5WSIP2fWgAHMCELfoeA22qt8kydI zvUK7RCE~KxA9QX+u}bm>WTR1jtyvnk2&H0niGju7s-lD(f3NE+pSb^mI$^ z@wa4z!6xIA)p^mS()a0uKMPTuk!+z-u3lzRoN?V?LE9-zE4IU zcKt6*<35v?c;Rk9@@_qPzsR{+8)E0ZB2vYES(u4`S60N$Y=JV!&<`UJ6w!0TKE1i+ zFae`;lPKU;MkPima1ArlP{QByu13>{^L?JI=3!v*&}yx*z%Y_TRMC~p^>ZVVMB75q zTCL$k{UVV)xpQ)uL6;)MbWBuHiB-OTD zl@@z^~(u88}lz z-}7aa9~-mAMr+J z`ilbHg$ejI8u`VV%q{_Gch;$#tLOnkMh26F%QR^V6_B@nEZ6}WYx&`zvEmQEw3*~v zRQv=x6unR0Zu5Q1z9h;Lv?~%4vNo$3SKZgNZ{y8&2EwmtC2}pJlbz4X^=Cd7z zUy?Y2M|q{v16IWG64ADYMj6Q@2z?vHgRG?>=67zB+892gXea+ViKOXGGS-GWC)%o| zeRm9@j+_lWp@r;Z$UYm78}@W~Z%oa`0<_uS=1dbu)sapcnd| zN^iGkeQ(bdJP_@Q*Z8Yr`q}9vizbuZLEcwJKF9Rd8R1SaKvf|QGe23l=ig6WKkiNO zduV-pJsnNX531fQU%;>oX;V}@RJvd#-i14 zD*v>ic|jOdy8;D+=4pv{44n>oJauTrJ= zGP^JHjkJ*4SSPQC{GW(+zLO;PdexYOBk1xGC*7-#(*Q3X3*n>u{UX`(I43#acGuyfTn} zL9efzf9WhEO=Md{$?qp6qY~p&46MhXKVyVFy0S0ICU+iFZz~z*KtW)08Y>4`B?^%| zWpm@;*eNCgn_k2?-C^lBG${7iLTl*_=9fqu_&tjcXljUt)jn3kN5puwi|l zXoDt?D=0PWtdU9^mA#`7mH()fPQ;)!TgySnsCF-6i*l3I^dC6kk$&-dKINih!{)w> zj#AtYnmgScbB%taIvoX5ti$pO$6(JS9_tUlzIZ&#KBlbAeIgVH6e_)u7T03RRQH_- z4v8E~Fs5pa!xndv(d-VK$(8v!WQIzp;zy*hkHE(_ByQ7NQ)EAd9L>=#Pi%3^_VGJ! zh5D_|r|}EoL4{74C$Ux^F?EUbY03{&A>&R(SAk6p@r=V~(8YHFF zWNC2ONJJ6hlS-J=JbUCyR0=~i($dbwQ9KMMw4-(GemYrE z2ZcglM7@#U69%CW^7`+VBQde#FJ&5C(9v;(PX?Gbc!p679Fy?ING=(Nm_5RTHJia* zRNT5vAJw;YM@eQYlORy84z8YK;?CFeIE_ZpCgx6H38x>u3RR_jydLX#utL+oa!Q>7 zKohPXWR;I^Nqwaum)u@oxdbfQOwT->WCpvVhG)FBO(HqUV})o6N2= zvj$shAM%L%2(@BEcnfL{8G|!KEh-W%q>xxzo1|~Ot|p`fv&GfuZ|CsApYrPA)djPBf;1TR)KHeit8PbSVY-04m3 zT%1*i56)rR4hwcoWbG2?qypuBF>^pTrRdzJpdVu7V?*I(7trj}C({BpB9-v}oGnuGRA(b5L@jM!{^B??OI;X&q0p>WQu;*bg@ zGEt!upuah$v+l8*kuS9l=xX^^23Xe$$q$80(l=aE0c~7j;=&=ll_(THc|1;ZA9`mz z#Z0SD=o_eR`QSYGI0m&Y?FXotJ&hAkk7u&5Ny4tn#YzDI?en9HYAB{wW zBSwzmFepWcCCLo;H1}a7(VBvkKFOLRn4H)^L?Nxiw1}4G_G1hrPl`AzPR03!7^ntnj~7OU3*^q%Iv5g8^q7geHYN{R{>D1l0QREWLX1mZ)a7)* zmECt|d-GtsE8f$!A=H(ZOVpLCNA}9*lN`aUt8kUc8kIdEF|qoloEwVS`<*?iq(cEO z6}hPK=eca4dP@FF^Rb-adRvxwY!6joDilzCU37VP*_`+%@r$O)UV>|VysB*9#li_% zTp{_8XYdWAa&j8Cr~ku4Mmvmz0spC;IRBgii>gi<4unqW(U7KJP=hvlDdRM{#20#; zt%okL<}Zr(QQ4kOJLfjk4=w1!brr^|3J^JH)0l;)Wvdjb%eOkh(_ywxEM*1mjUhVC>nV7-* zK+CYh>#H1lu`;3hiA|bEH*#jF-ZtbM^KGEF%=nh{7zrW~G2UNyKO%vB8DyAuwpafC z1_3okg!G`F%)I&=M&+C34Mp&K7BNlzXcDmTyeKa}zTaLH_9Talo{uf4AgDDZY%?E{ zcx2~*naK)+(iUE;rOV#H1bs3HXTrpVI<`NUx-C2H8okY~_&ii`~dM5Bu*$5!{?VL^bT|Nr18LonDU6hlM zInXYa-XRaYhIxRjh8_ebkW>8EPOWi|`6J?|h>P~ARn&EukEL}j&8qA_zUY~;3zm_m zPv}&Wky5>Pm&^*c%W8~0+wA96Y(r0yma4njDMoLr4Y?SM$LIP1G(LpVI_TQiV6d@gkA&G@T!@~~QakPU@ z5vPD5rwLWtquLWZN403Or41!1h3&ZP&$rLh(^K1;trkb6mofyA?iPRHVX{NdzdDjj zRO&sd>f8S71)kH^l2`ZvL|w9|T!P!`X@@06Z3#!NQ!0H~nfrsj#ce_ntEdguxvM(f zo9YTZ*sF)Ecm=d1=i>_vsaYzMn_ns=5ra+xX@ofI?zidRpjj02U(ihOCZ3$Kbuo+& zlaU&Mwv9u#(MYo3hQus~KKnr3ayP^r(f4|O(Fm8Y*RSc2lBUu!Zg$^amP1gQR|(zf zr`VQ~SFsWZa)Cl=WkY=GxV0Afj>s8f`anS4MjKwB$3+OMM9G^04A=d$j9TT)C3@y* zZBk2TjR*ZYlNQ+k#8tC2_=Pt8uvoAm|F_pte6*%f_oNpNDSk&2jymxtBIxa=i^I0F zr^}*ES6FMicE@9t%jyvqBLZo4SZ6&eVgh)Y{?2H`M^(ER>VIKqkB9$(p*4aFR64pi zm0KRlQs8wUCQ68((-Cx>WokI;2)4(xXR@6UgJMj%qFC;p z)nexK+Vh_o21bI!&lS3=_VgpM1|!f3ZICtJIxmQzU;73BUL0F!no5wZI=n643Erda z1Gr&9VmMC!q0ma~Fai?XCDJ`ieQ1LPDV*v3Au#~~zE{xchXj#|{O&Pg1zOEVjNH zb$J|q{LIYV@?||%b-kKF4%CZe(hr8O>V+kToCRiY1iBc_2V1{4S*F7@m5zP`|wh)JS~~h*9sWavm)4- zEnXxb(Dv2{3!9y84qrCji3haf}>E$<`#M-d$+~ z#qI6Cvti&b5rrJi5WHSmOK^RAoZjxyI=@%VJ^3dH-<8L8BXamN%33|{$pW)zteK-B zcWOFaDOzEeyJLUs>tW&R=4^O1?elii{r2%_?Ctr&kmtCIsm9qPR|PKH8~JS`eEPnf z(T{!|(#~I#s{A=00{!Z6@?w8^+6i!+yLA0v{a*4;xcXd)`KX61uQ3{_<%&ko&Kx8H z)bKzi168>jGVjhG%;OBcnID?G|M~~rsECG9A?pCbB?2%rHqbEF0>n;d_W zV240>Xl*y{!|hX`Tg={)CdJzyRQj35q>ib?eJ0^MEk<($K`X8N{PUX`{k7E4{|`6v za_L<64vK_`Eg;%hwLT=LR_MIjeWxR)2yWHF;aB#zynFq-QKD0R-RD%)hWff|D*b!^ zND;XvUXC3n2{WC@Y&C{_q4CGlSq}3&vLlBUp$I=R4?b`>pyd6KHiG$Y_Mwxi8dQpr z^0X{GeX>#`>J;BJ|H}H#zb;poEj`mun^Q&}AoUA6O~0to{{3Wuq-zOQZt~bMs2Wjo ztSfCwg{P^*i3amN6ZsfI|Hjn4-O83U8&lW( zzc4j|qC~%`kAs6G5#UcE-?qe6PZ1NHbeqWyfy0Jh4mSdk$zmksdyQ=w&E?lGEN00j zTZJE)vj>z>v_{fNtYF_^&Q{h&+|oC*sdVm5V$L~~@CvSeAPF^o(tntQTkUv_C6z5U zu~s(wRK{ctaf*@(JjG5%Lb;w%tcpj)hJM%^6qB^R7Cg-D!sF=7pXSS70qbfcQ0AiP zPWOL<>Wl+sYe|s*0@b55V8Hb*160WWfa+lF`sQBt?+h36Z-xuctKUJE|HrL84E;ac z+9115(705=JMNc}8JBKLYm-K#30p~U$0JHo!J1><2JcQ|73~9h z7YL|JJX?*EwKwKeby@Fed;tNtL_Js=P4BG(jQRVVQ!{=Au-^hLfimpez6Qz zhY@~(M~6Q-RfAoKM}WyTkb4G{N-w?$MiA35>kn4bBTzPq-HY;$*7FF?$ke&sBiX+0 zLFpLPM-8z}q|tl)Lc*F_kcF@}2+MfQ@@ zqAzUqPEqKv@>L}_*=FW))qxUf^iC#JB!}F6p}?#03A(+k6Wto71HRR)AGnB26*Pnx z&keo}0NHiW7~4$PKnlZCUa0l)+|W@`m>7lC-iea`;?)bJ>)*UOa7#|s|G#;4$jEA^ z3*PzsPPdQUH+F^Q|YUI8!tOAkGytGP-)5MT)k6EUqma_xEv;erbyuo z5^PzFih>)=`pChNFDIgImm6&p<_SFyJg5x__qV0p7(~>NVLiyAc+td`Vd#ZvCB(Fy z9?r5vYtZLK48VIr!{A7{sS@$4I+#Jt_HDrvPxKsGgu52%^wg+3A7rWWhF|(Uf zHHjUWd}9bY*JglDm}nyV*mjLHh1DFMoOGdiZHic_@VXU?tJ0Hm#)JXDySWw9zC^^H zk|^E2vXLRSGKykx{JX?mOJ!E>wGmMjZGl+kJFSyK`ACyCoo2ZMBk=Q zd}|SlFy>c!Ez%^n;SIZ^m$_u-n&R}E%+Vewgt6Ei7q-)*hxPh^k{8d!OH#)s&4B3K z9&7>|Qv@u&R~xq8+)4D&Y+FCitLFwT_b&<=9Q`ntw}rcKlB3iaUJw4p6yZ-JLV6xR z57_a7Cg_9TfX_NM8UeVcj!N$ICP`PLZ%%56w0zT)WcTQq14VN+DqVdOacxbg;uY~E zCL+oD0lODRU+~ExBGav4wx6hk7R?21q^9k7GDr6wVQXDIHH)zOfe;=9kH5upooR>xJQxeH9qgBe;@=cj&FaSyk}4BQIqELO_DlcZ1e ziUX73RXEj7cS7?5VQOyLVyku>9zGUY8NRyhw|n?akH`f00oe}_ZJ{J412aOaPg}H| z^n9Fd!091iEW|S8m6$XytApXnV9zYpe)A0MTI>e!hkEm01DtD}`jE45Qu#1XNZP+8)hP6f zgOZU|B%giAca`Tyo6~ zD`K6Q-Q!AJn?3Aw8%$j{B?XFYexvV0U;x=}ECrh*f>1*4`GB*N|3?P+hk$$4Bs=cP z>zs+cw=mVo>TXMK$>jDF!>31~GTZCsg|pel(AWJiZ=D$43r2ga5gy+J&E`Ks!t47h z`ZlbzG_6yKUu76o8iJ<*qfs#nRL@H9CyoyiW*ahR@?{p%{U|QifAC6T<%Js9mNvuM z4?#Euw4QJn$egG-8577u0E$Kc9p4%o7NjsDNkA1`iCV8P@+3!qK2>;&mh0pFMe_b| zN5j!TJK?Ik&HZ&JpO5$i7W@swfRSgI^R^Iw)kRlEhQOObSgxC8=riNDsF_^@qDz4P zAnglia7cSQH#%bI_d__}{BTXtv3QiE8{C;fkxnl&cH*(`4YFLIVsUEioLa(B1o~SY zqZL+t$uW+qpKS*1)|#4+_+QS1B*(Vpq1JQEay-gc-QR7w9xtDxZk{iC5~h9?kzZGE zkPLidzaf>r4HDD*%pGLqY7Y4M&~d*CEZ%o@KTfAr8Q4Fwb#p%#@RQmK*)q6ZyJNJR zi~urX!CBL_FW(n4)Q_5{wWOutk0!vdIG3KhjttBvh7{BWyax!A1XZBbDU6Eak_Eec zq1)`R`z!dq(mJ2`e7V2gpRT8MzmMQzUU>n;Cvac(B1$B6AvfS31SivkgNR0=QZJBT z%qbET%GoSuPX_{RmFtG_Vf#1U_<)Y@` zphhUUIXoXufIZcmdep?K7Q)TSpPOM&UbPfbv`DoeyMqNnEA|b!f2Py-*az()`t75Y zFJt1KI8{#-wf?l;=(WaKYTE~8EwA_p*=O!G3pFxYS~+bDnF#$&+~XVcg)ng(60_8% zoGf9tl*@Vq{Dn>yS%9N67ajP5G${R4?OQsZrO%-j;s-s5{qT#JQc++nxR9y8PX;E6 z@rA>?6-ucn3ZO_`{&olo{(KhgAR4%@)qZOPvX}pA1Q0diF{l4(1pQ?QzJdq;k?<3i zK-Oc2E(CX&U(urLm8IY76-oYwNAR3j>8vU^zav+6B;%?#0%mTsPPG?G8n10q>%y`? zdGrSThKJl~|7N_a8a6&5WeP30TW9`%B@z_c{g+4(#r2O!0I&Kj61Z?6rHkVCZvCw0 zK_sXFo>Lq-2c;y~rafrG7}!U-6NYjpIlvE#3;laRbm%!yh~t+hH!lU{#{=r^5jw@YA4MjR_xA-cYI6R_f7Jzm{yKTJ>R8>)gVR{DLVv;rljuvcZab)&i|ipK&F)k&fvz@a#g_qwv5Ao3tV2pPHJJ$oNz}M{9kRF z|34FmAIIGpEyh_h&2HS7@^wY1RiqfhoNzdbla`}|%|_8TUq{;JM8%9Y3u7+dZlS`W zMj_wA46*Z_(TNns=hNdpkIzqczr7yM$LsZezy5$%YrA<$j@NIbf`BQG(5L|BBqwB!tEbOkWEB&fM>Bk$+~qGD!QFAIZHbnAHRrnxenS6a3Io-t zRrgL@Uhcj)(G9rAcPhhOIB4sUzQFGDfdx)w2sqdP8}iIbTrSaboBm1zUzBG*^iEV_ zO|kCQxeJD?;Rp(8Li6g^O=_>6`ZkjNn@t;s-ReS+^6PqrA)^~f_o_fmpp!kMG@BRF5I4| zN*a=(iT&twKQ>Qk3w2#1-eAnxVmxL%tbmrADa|dJg(>ubUkdv`yN(TBO+nu|mTSHP z&*X(%($Za2*S$vTvY~679%8MmABjJkul)Pi67yFk43%yZI(5{ev=EP61NO0tk5lIv zV(L6~asKhCQ41uHsf!hcOqFNOi*3>a`6Fu&Ig`glA0)Vxo%k(d(9Rdtpg>zFT9Dr& zejlq?5C%kH#j#0QCkEB_PvO)PUs4LPE-p-3I1$*-m`c1>8sLt7D+;CP)nSf)zP0pN zzMT)7C^vARMn*mtY=i zb7}-$8QpMR7vp9ejkgDk##O-dQ1V4&DTPVUm_I3g0R#Dd`$Z+&vyl4sX6bDPLBOI`dI)lz4dEkbjc; zt{zfJ|D|*ZFE{uZ)1u%0?32(E;Ma5a5xTG_1AnljZ1Y9t1&5E*l~y&BQLiA>yuz=K z4E6HO`H@*zMQQ!Rq@Y_WK{s^G_IC!IdD#4Rugmw~;wz(tj$1eW(h97RN5^PBI7?YR zG#cM!eTkvyIy-`#9ZN53MTIUh+K=u^yMphwmar2cmi`SD%}q-1VS1CT4Lnhz19qu* zjy%IRkC9NTx2vHKsUN=X$1uO|`vDY>*5sTBOHDP^TQ}_&=YMH#Y{(dA-R!js zFdIF2Ene&N!*wUqON+yJjkmRxZMS`8NMLE@QguI)^>m(}MD*5RsI+*V!k7SYN>UyY z0Zrll1G2U>Q&!nM73jA2&&!K*3L0;1JTpn Date: Wed, 13 Nov 2019 12:21:30 -0700 Subject: [PATCH 13/59] [Newsfeed/Lint] fix chained fn lint (#50515) --- src/plugins/newsfeed/public/lib/api.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/newsfeed/public/lib/api.test.ts b/src/plugins/newsfeed/public/lib/api.test.ts index b9707ff91b9365..4383b9e0f7dabe 100644 --- a/src/plugins/newsfeed/public/lib/api.test.ts +++ b/src/plugins/newsfeed/public/lib/api.test.ts @@ -631,10 +631,7 @@ describe('getApi', () => { .mockImplementationOnce(getHttpMockWithItems(successItems)); getApi(httpMock, configMock.newsfeed, '6.8.2') - .pipe( - take(4), - toArray() - ) + .pipe(take(4), toArray()) .subscribe(result => { expect(result).toMatchInlineSnapshot(` Array [ From 013f3ebe876a83f676e20850ac63ac53c594943a Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 13 Nov 2019 13:18:04 -0700 Subject: [PATCH 14/59] [Search service] Add support for ES request preference (#49424) * Add support for ES preference * Fix name of test --- .../search/es_search/es_search_strategy.ts | 13 ++++-- .../es_search/get_es_preference.test.ts | 46 +++++++++++++++++++ .../search/es_search/get_es_preference.ts | 29 ++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/plugins/data/public/search/es_search/get_es_preference.test.ts create mode 100644 src/plugins/data/public/search/es_search/get_es_preference.ts diff --git a/src/plugins/data/public/search/es_search/es_search_strategy.ts b/src/plugins/data/public/search/es_search/es_search_strategy.ts index 643ded120799e0..d29f3b6882b26b 100644 --- a/src/plugins/data/public/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/public/search/es_search/es_search_strategy.ts @@ -20,6 +20,7 @@ import { Observable } from 'rxjs'; import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../../common/search'; import { SYNC_SEARCH_STRATEGY } from '../sync_search_strategy'; +import { getEsPreference } from './get_es_preference'; import { TSearchStrategyProvider, ISearchStrategy, ISearchGeneric, ISearchContext } from '..'; export const esSearchStrategyProvider: TSearchStrategyProvider = ( @@ -27,11 +28,17 @@ export const esSearchStrategyProvider: TSearchStrategyProvider => { return { - search: (request, options) => - search( + search: (request, options) => { + if (typeof request.params.preference === 'undefined') { + const setPreference = context.core.uiSettings.get('courier:setRequestPreference'); + const customPreference = context.core.uiSettings.get('courier:customRequestPreference'); + request.params.preference = getEsPreference(setPreference, customPreference); + } + return search( { ...request, serverStrategy: ES_SEARCH_STRATEGY }, options, SYNC_SEARCH_STRATEGY - ) as Observable, + ) as Observable; + }, }; }; diff --git a/src/plugins/data/public/search/es_search/get_es_preference.test.ts b/src/plugins/data/public/search/es_search/get_es_preference.test.ts new file mode 100644 index 00000000000000..27e6f9b48bbdd5 --- /dev/null +++ b/src/plugins/data/public/search/es_search/get_es_preference.test.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getEsPreference } from './get_es_preference'; + +jest.useFakeTimers(); + +describe('Get ES preference', () => { + test('returns the session ID if set to sessionId', () => { + const setPreference = 'sessionId'; + const customPreference = 'foobar'; + const sessionId = 'my_session_id'; + const preference = getEsPreference(setPreference, customPreference, sessionId); + expect(preference).toBe(sessionId); + }); + + test('returns the custom preference if set to custom', () => { + const setPreference = 'custom'; + const customPreference = 'foobar'; + const preference = getEsPreference(setPreference, customPreference); + expect(preference).toBe(customPreference); + }); + + test('returns undefined if set to none', () => { + const setPreference = 'none'; + const customPreference = 'foobar'; + const preference = getEsPreference(setPreference, customPreference); + expect(preference).toBe(undefined); + }); +}); diff --git a/src/plugins/data/public/search/es_search/get_es_preference.ts b/src/plugins/data/public/search/es_search/get_es_preference.ts new file mode 100644 index 00000000000000..200e5bacb7f182 --- /dev/null +++ b/src/plugins/data/public/search/es_search/get_es_preference.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const defaultSessionId = `${Date.now()}`; + +export function getEsPreference( + setRequestPreference: string, + customRequestPreference?: string, + sessionId: string = defaultSessionId +) { + if (setRequestPreference === 'sessionId') return `${sessionId}`; + return setRequestPreference === 'custom' ? customRequestPreference : undefined; +} From 1010f285b3686feab6e593cf8d4ca3d8165d989c Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 13 Nov 2019 15:26:11 -0500 Subject: [PATCH 15/59] [Metrics UI] Convert layouts to use React components (#49134) * Convert layouts to use React compontents - This PR closes #48808 - Move all files under pages/metrics * Renaming layout files; Fixing some types; Removing unused types * Fixing naming issue * Fixing path * Fixing i18n stuff * [Metrics UI] Move toolbars under inventory models * Fixing imports; wrapping code in useMemo to optimize * removing unused imports * Removing prototype page --- .../inventory_models/container/index.ts | 10 +- .../container/{layout.ts => layout.tsx} | 194 ++++++----- .../container/metrics/index.ts | 1 + .../container/toolbar_items.tsx} | 13 +- .../common/inventory_models/host/index.ts | 20 +- .../host/{layout.ts => layout.tsx} | 300 +++++++++--------- .../inventory_models/host/metrics/index.ts | 1 + .../inventory_models/host/toolbar_items.tsx} | 13 +- .../infra/common/inventory_models/index.ts | 2 +- .../infra/common/inventory_models/layouts.ts | 44 +++ .../common/inventory_models/pod/index.ts | 11 +- .../pod/{layout.ts => layout.tsx} | 139 ++++---- .../inventory_models/pod/metrics/index.ts | 1 + .../inventory_models/pod/toolbar_items.tsx} | 13 +- .../shared/layouts/{aws.ts => aws.tsx} | 181 ++++++----- .../inventory_models/shared/layouts/nginx.ts | 102 ------ .../inventory_models/shared/layouts/nginx.tsx | 103 ++++++ .../inventory_models/shared/metrics/index.ts | 5 + .../shared/metrics/required_metrics.ts | 23 ++ .../infra/common/inventory_models/toolbars.ts | 36 +++ .../infra/common/inventory_models/types.ts | 112 +++---- .../components/inventory/toolbars/toolbar.tsx | 22 +- .../infra/public/components/metrics/index.tsx | 128 -------- .../public/components/metrics/section.tsx | 42 --- .../metrics/sections/gauges_section.tsx | 104 ------ .../components/metrics/sections/index.ts | 13 - .../public/components/metrics/side_nav.tsx | 81 ----- .../waffle/waffle_inventory_switcher.tsx | 6 +- .../metadata/lib/get_filtered_layouts.ts | 38 --- .../metadata/lib/get_filtered_metrics.ts | 25 ++ .../containers/metadata/use_metadata.ts | 9 +- .../redirect_to_host_detail_via_ip.tsx | 2 +- .../pages/link_to/redirect_to_node_detail.tsx | 2 +- .../metrics/components/chart_section_vis.tsx} | 51 ++- .../metrics/components}/error_message.tsx | 0 .../metrics/components/gauges_section_vis.tsx | 101 ++++++ .../metrics/components/helpers.ts} | 50 ++- .../metrics/components}/invalid_node.tsx | 6 +- .../metrics/components}/node_details.tsx | 4 +- .../pages/metrics/components/page_body.tsx | 72 +++++ .../pages/metrics/components/page_error.tsx | 45 +++ .../pages/metrics/components/section.tsx | 78 +++++ .../metrics/components}/series_chart.tsx | 0 .../pages/metrics/components/side_nav.tsx | 52 +++ .../pages/metrics/components/sub_section.tsx | 59 ++++ .../components}/time_controls.test.tsx | 2 +- .../metrics/components}/time_controls.tsx | 4 +- .../metrics/containers}/metrics.gql_query.ts | 0 .../metrics/containers}/metrics_time.test.tsx | 0 .../metrics/containers}/with_metrics.tsx | 18 +- .../metrics/containers}/with_metrics_time.tsx | 4 +- .../infra/public/pages/metrics/index.tsx | 122 +++---- .../pages/metrics/lib/side_nav_context.ts | 24 ++ .../public/pages/metrics/page_providers.tsx | 2 +- .../infra/public/pages/metrics/types.ts | 62 ++++ .../infra/public/utils/formatters/index.ts | 17 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../api_integration/apis/infra/metrics.ts | 2 +- 59 files changed, 1389 insertions(+), 1184 deletions(-) rename x-pack/legacy/plugins/infra/common/inventory_models/container/{layout.ts => layout.tsx} (64%) rename x-pack/legacy/plugins/infra/{public/components/inventory/toolbars/container_toolbar_items.tsx => common/inventory_models/container/toolbar_items.tsx} (76%) rename x-pack/legacy/plugins/infra/common/inventory_models/host/{layout.ts => layout.tsx} (68%) rename x-pack/legacy/plugins/infra/{public/components/inventory/toolbars/host_toolbar_items.tsx => common/inventory_models/host/toolbar_items.tsx} (77%) create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts rename x-pack/legacy/plugins/infra/common/inventory_models/pod/{layout.ts => layout.tsx} (59%) rename x-pack/legacy/plugins/infra/{public/components/inventory/toolbars/pod_toolbar_items.tsx => common/inventory_models/pod/toolbar_items.tsx} (75%) rename x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/{aws.ts => aws.tsx} (69%) delete mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/required_metrics.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts delete mode 100644 x-pack/legacy/plugins/infra/public/components/metrics/index.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/metrics/section.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/metrics/sections/gauges_section.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/metrics/sections/index.ts delete mode 100644 x-pack/legacy/plugins/infra/public/components/metrics/side_nav.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_layouts.ts create mode 100644 x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts rename x-pack/legacy/plugins/infra/public/{components/metrics/sections/chart_section.tsx => pages/metrics/components/chart_section_vis.tsx} (72%) rename x-pack/legacy/plugins/infra/public/{components/metrics/sections => pages/metrics/components}/error_message.tsx (100%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/gauges_section_vis.tsx rename x-pack/legacy/plugins/infra/public/{components/metrics/sections/helpers/index.ts => pages/metrics/components/helpers.ts} (57%) rename x-pack/legacy/plugins/infra/public/{components/metrics => pages/metrics/components}/invalid_node.tsx (92%) rename x-pack/legacy/plugins/infra/public/{components/metrics => pages/metrics/components}/node_details.tsx (97%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/page_body.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/page_error.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx rename x-pack/legacy/plugins/infra/public/{components/metrics/sections => pages/metrics/components}/series_chart.tsx (100%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/side_nav.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx rename x-pack/legacy/plugins/infra/public/{components/metrics => pages/metrics/components}/time_controls.test.tsx (95%) rename x-pack/legacy/plugins/infra/public/{components/metrics => pages/metrics/components}/time_controls.tsx (92%) rename x-pack/legacy/plugins/infra/public/{containers/metrics => pages/metrics/containers}/metrics.gql_query.ts (100%) rename x-pack/legacy/plugins/infra/public/{containers/metrics => pages/metrics/containers}/metrics_time.test.tsx (100%) rename x-pack/legacy/plugins/infra/public/{containers/metrics => pages/metrics/containers}/with_metrics.tsx (83%) rename x-pack/legacy/plugins/infra/public/{containers/metrics => pages/metrics/containers}/with_metrics_time.tsx (98%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/lib/side_nav_context.ts create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/types.ts diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts index 254ed7b7593009..54fe938528d199 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts @@ -4,13 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { layout } from './layout'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; export const container: InventoryModel = { id: 'container', requiredModules: ['docker'], - layout, metrics, + requiredMetrics: [ + 'containerOverview', + 'containerCpuUsage', + 'containerMemory', + 'containerNetworkTraffic', + 'containerDiskIOBytes', + 'containerDiskIOOps', + ], }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.ts b/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx similarity index 64% rename from x-pack/legacy/plugins/infra/common/inventory_models/container/layout.ts rename to x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx index 821e180cda0166..00da70f1d96a5b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx @@ -3,30 +3,32 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { InventoryDetailLayoutCreator } from '../types'; -import { nginxLayoutCreator } from '../shared/layouts/nginx'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; -export const layout: InventoryDetailLayoutCreator = theme => [ - { - id: 'containerOverview', - label: i18n.translate('xpack.infra.metricDetailPage.containerMetricsLayout.layoutLabel', { - defaultMessage: 'Container', - }), - sections: [ - { - id: 'containerOverview', - label: i18n.translate( - 'xpack.infra.metricDetailPage.containerMetricsLayout.overviewSection.sectionLabel', - { - defaultMessage: 'Overview', - } - ), - requires: ['docker.cpu', 'docker.memory', 'docker.network'], - type: 'gauges', - visConfig: { - seriesOverrides: { +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +

+ + [ formatter: 'bits', formatterTemplate: '{{value}}/s', }, - }, - }, - }, - { - id: 'containerCpuUsage', - label: i18n.translate( + }} + /> + + + + + + + + + [ } ), }, - }, - }, - }, - { - id: 'containerDiskIOOps', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'containerDiskIOBytes', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - ], - }, - ...nginxLayoutCreator(theme), -]; + }} + /> + +
+ +)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts index 9cbbb2dca7ffa5..9e0153c5d6ea6b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts @@ -29,4 +29,5 @@ export const metrics: InventoryMetrics = { containerMemory, }, snapshot: { cpu, memory, rx, tx }, + defaultSnapshot: 'cpu', }; diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/container_toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx similarity index 76% rename from x-pack/legacy/plugins/infra/public/components/inventory/toolbars/container_toolbar_items.tsx rename to x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx index 2c24c7aa1a8305..ddb3c0491f164e 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/container_toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx @@ -6,11 +6,14 @@ import React, { useMemo } from 'react'; import { EuiFlexItem } from '@elastic/eui'; -import { ToolbarProps } from './toolbar'; -import { WaffleMetricControls } from '../../waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../graphql/types'; -import { toMetricOpt, toGroupByOpt } from './toolbar_wrapper'; +import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; +import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; +import { InfraSnapshotMetricType } from '../../../public/graphql/types'; +import { + toMetricOpt, + toGroupByOpt, +} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; export const ContainerToolbarItems = (props: ToolbarProps) => { const options = useMemo( diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts index e29f5878bfcb3f..08056e650a32e3 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts @@ -4,13 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { layout } from './layout'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; +import { + aws as awsRequiredMetrics, + nginx as nginxRequireMetrics, +} from '../shared/metrics/required_metrics'; export const host: InventoryModel = { id: 'host', requiredModules: ['system'], - layout, metrics, + requiredMetrics: [ + 'hostSystemOverview', + 'hostCpuUsage', + 'hostLoad', + 'hostMemoryUsage', + 'hostNetworkTraffic', + 'hostK8sOverview', + 'hostK8sCpuCap', + 'hostK8sMemoryCap', + 'hostK8sDiskCap', + 'hostK8sPodCap', + ...awsRequiredMetrics, + ...nginxRequireMetrics, + ], }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.ts b/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx similarity index 68% rename from x-pack/legacy/plugins/infra/common/inventory_models/host/layout.ts rename to x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx index 2ac12387e26a4b..fee79d8364c422 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx @@ -3,33 +3,34 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { InventoryDetailLayoutCreator } from '../types'; - -import { nginxLayoutCreator } from '../shared/layouts/nginx'; -import { awsLayoutCreator } from '../shared/layouts/aws'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; +import * as Aws from '../shared/layouts/aws'; +import * as Ngnix from '../shared/layouts/nginx'; -export const layout: InventoryDetailLayoutCreator = theme => [ - { - id: 'hostOverview', - label: i18n.translate('xpack.infra.metricDetailPage.hostMetricsLayout.layoutLabel', { - defaultMessage: 'Host', - }), - sections: [ - { - id: 'hostSystemOverview', - linkToId: 'hostOverview', - label: i18n.translate( - 'xpack.infra.metricDetailPage.hostMetricsLayout.overviewSection.sectionLabel', - { - defaultMessage: 'Overview', - } - ), - requires: ['system.cpu', 'system.load', 'system.memory', 'system.network'], - type: 'gauges', - visConfig: { - seriesOverrides: { +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + [ formatter: 'bits', formatterTemplate: '{{value}}/s', }, - }, - }, - }, - { - id: 'hostCpuUsage', - label: i18n.translate( + }} + /> + + + [ softirq: { color: theme.eui.euiColorVis6 }, iowait: { color: theme.eui.euiColorVis7 }, nice: { color: theme.eui.euiColorVis5 }, - }, - }, - }, - { - id: 'hostLoad', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'hostMemoryUsage', - label: i18n.translate( + }} + /> + + + + + + [ } ), }, - }, - }, - }, - ], - }, - { - id: 'k8sOverview', - label: 'Kubernetes', - sections: [ - { - id: 'hostK8sOverview', - linkToId: 'k8sOverview', - label: i18n.translate( - 'xpack.infra.metricDetailPage.kubernetesMetricsLayout.overviewSection.sectionLabel', - { - defaultMessage: 'Overview', - } - ), - requires: ['kubernetes.node'], - type: 'gauges', - visConfig: { - seriesOverrides: { + }} + /> + +
+
+ + [ formatter: 'percent', gaugeMax: 1, }, - }, - }, - }, - { - id: 'hostK8sCpuCap', - label: i18n.translate( + }} + /> + + + + + + + + + + + + + +
+ + +
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts index d1fd3a307ae366..f4c0150309dd8c 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts @@ -51,4 +51,5 @@ export const metrics: InventoryMetrics = { hostDockerTop5ByCpu, }, snapshot: { count, cpu, load, logRate, memory, rx, tx }, + defaultSnapshot: 'cpu', }; diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/host_toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx similarity index 77% rename from x-pack/legacy/plugins/infra/public/components/inventory/toolbars/host_toolbar_items.tsx rename to x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx index 81dadcc7f6c8b7..8e1bb0dfb48163 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/host_toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx @@ -6,11 +6,14 @@ import React, { useMemo } from 'react'; import { EuiFlexItem } from '@elastic/eui'; -import { ToolbarProps } from './toolbar'; -import { WaffleMetricControls } from '../../waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../graphql/types'; -import { toGroupByOpt, toMetricOpt } from './toolbar_wrapper'; +import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; +import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; +import { InfraSnapshotMetricType } from '../../../public/graphql/types'; +import { + toGroupByOpt, + toMetricOpt, +} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; export const HostToolbarItems = (props: ToolbarProps) => { const metricOptions = useMemo( diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/index.ts index ec518cb9cb9509..79aad7b2ccf6fe 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/index.ts @@ -11,7 +11,7 @@ import { container } from './container'; import { InventoryItemType } from './types'; export { metrics } from './metrics'; -export const inventoryModels = [host, pod, container]; +const inventoryModels = [host, pod, container]; export const findInventoryModel = (type: InventoryItemType) => { const model = inventoryModels.find(m => m.id === type); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts b/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts new file mode 100644 index 00000000000000..9fce720f5b14b6 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/** + * WHY ARE THE LAYOUTS A SEPERATE FILE? + * + * Files with React can not be included on the server without + * crashing due to the requirement of the `window` object. + */ + +import { idx } from '@kbn/elastic-idx'; +import { i18n } from '@kbn/i18n'; + +import { ReactNode, FunctionComponent } from 'react'; +import { Layout as HostLayout } from './host/layout'; +import { Layout as PodLayout } from './pod/layout'; +import { Layout as ContainerLayout } from './container/layout'; +import { InventoryItemType } from './types'; +import { LayoutProps } from '../../public/pages/metrics/types'; + +interface Layouts { + [type: string]: ReactNode; +} + +const layouts: Layouts = { + host: HostLayout, + pod: PodLayout, + container: ContainerLayout, +}; + +export const findLayout = (type: InventoryItemType) => { + const Layout = idx(layouts, _ => _[type]); + if (!Layout) { + throw new Error( + i18n.translate('xpack.infra.inventoryModels.findLayout.error', { + defaultMessage: "The layout you've attempted to find does not exist", + }) + ); + } + return Layout as FunctionComponent; +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts index 1cf839b7876570..66ace03abac00b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts @@ -4,12 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { layout } from './layout'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; +import { nginx as nginxRequiredMetrics } from '../shared/metrics/required_metrics'; + export const pod: InventoryModel = { id: 'pod', requiredModules: ['kubernetes'], - layout, metrics, + requiredMetrics: [ + 'podOverview', + 'podCpuUsage', + 'podMemoryUsage', + 'podNetworkTraffic', + ...nginxRequiredMetrics, + ], }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.ts b/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx similarity index 59% rename from x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.ts rename to x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx index ffb78894d63f63..401e25c4defb86 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx @@ -3,30 +3,33 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { InventoryDetailLayoutCreator } from '../types'; -import { nginxLayoutCreator } from '../shared/layouts/nginx'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; +import * as Nginx from '../shared/layouts/nginx'; -export const layout: InventoryDetailLayoutCreator = theme => [ - { - id: 'podOverview', - label: i18n.translate('xpack.infra.metricDetailPage.podMetricsLayout.layoutLabel', { - defaultMessage: 'Pod', - }), - sections: [ - { - id: 'podOverview', - label: i18n.translate( - 'xpack.infra.metricDetailPage.podMetricsLayout.overviewSection.sectionLabel', - { - defaultMessage: 'Overview', - } - ), - requires: ['kubernetes.pod'], - type: 'gauges', - visConfig: { - seriesOverrides: { +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + [ formatter: 'bits', formatterTemplate: '{{value}}/s', }, - }, - }, - }, - { - id: 'podCpuUsage', - label: i18n.translate( + }} + /> + + + + + + + + + [ } ), }, - }, - }, - }, - ], - }, - ...nginxLayoutCreator(theme), -]; + }} + /> + +
+ +
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts index 03aa6d4e039b11..2aa7ac6b496afa 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts @@ -25,4 +25,5 @@ export const metrics: InventoryMetrics = { podMemoryUsage, }, snapshot: { cpu, memory, rx, tx }, + defaultSnapshot: 'cpu', }; diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/pod_toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx similarity index 75% rename from x-pack/legacy/plugins/infra/public/components/inventory/toolbars/pod_toolbar_items.tsx rename to x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx index b3eec84dcfcd6b..cc0676fc60ae43 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/pod_toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx @@ -6,11 +6,14 @@ import React, { useMemo } from 'react'; import { EuiFlexItem } from '@elastic/eui'; -import { ToolbarProps } from './toolbar'; -import { WaffleMetricControls } from '../../waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../graphql/types'; -import { toGroupByOpt, toMetricOpt } from './toolbar_wrapper'; +import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; +import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; +import { InfraSnapshotMetricType } from '../../../public/graphql/types'; +import { + toGroupByOpt, + toMetricOpt, +} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; export const PodToolbarItems = (props: ToolbarProps) => { const options = useMemo( diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.ts b/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.tsx similarity index 69% rename from x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.ts rename to x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.tsx index 7c7c009df6f278..2cabbe4c33ff30 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/aws.tsx @@ -3,28 +3,30 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { InventoryDetailLayoutCreator } from '../../types'; +import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/types'; +import { Section } from '../../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../../public/pages/metrics/components/sub_section'; +import { GaugesSectionVis } from '../../../../public/pages/metrics/components/gauges_section_vis'; +import { ChartSectionVis } from '../../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../../common/eui_styled_components'; -export const awsLayoutCreator: InventoryDetailLayoutCreator = theme => [ - { - id: 'awsOverview', - label: 'AWS', - sections: [ - { - id: 'awsOverview', - linkToId: 'awsOverview', - label: i18n.translate( - 'xpack.infra.metricDetailPage.awsMetricsLayout.overviewSection.sectionLabel', - { - defaultMessage: 'Overview', - } - ), - requires: ['aws.ec2'], - type: 'gauges', - visConfig: { - seriesOverrides: { +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + [ color: theme.eui.euiColorFullShade, formatter: 'number', }, - }, - }, - }, - { - id: 'awsCpuUtilization', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'awsNetworkBytes', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'awsNetworkPackets', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'awsDiskioOps', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - { - id: 'awsDiskioBytes', - label: i18n.translate( + }} + /> + + + [ } ), }, - }, - }, - }, - ], - }, -]; + }} + /> + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.ts b/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.ts deleted file mode 100644 index 2d895c3b83a0bf..00000000000000 --- a/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.ts +++ /dev/null @@ -1,102 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { InventoryDetailLayoutCreator } from '../../types'; - -export const nginxLayoutCreator: InventoryDetailLayoutCreator = theme => [ - { - id: 'nginxOverview', - label: 'Nginx', - sections: [ - { - id: 'nginxHits', - label: i18n.translate( - 'xpack.infra.metricDetailPage.nginxMetricsLayout.hitsSection.sectionLabel', - { - defaultMessage: 'Hits', - } - ), - requires: ['nginx.access'], - type: 'chart', - visConfig: { - formatter: 'abbreviatedNumber', - stacked: true, - seriesOverrides: { - '200s': { color: theme.eui.euiColorVis1, type: 'bar' }, - '300s': { color: theme.eui.euiColorVis5, type: 'bar' }, - '400s': { color: theme.eui.euiColorVis2, type: 'bar' }, - '500s': { color: theme.eui.euiColorVis9, type: 'bar' }, - }, - }, - }, - { - id: 'nginxRequestRate', - label: i18n.translate( - 'xpack.infra.metricDetailPage.nginxMetricsLayout.requestRateSection.sectionLabel', - { - defaultMessage: 'Request Rate', - } - ), - requires: ['nginx.stubstatus'], - type: 'chart', - visConfig: { - formatter: 'abbreviatedNumber', - formatterTemplate: '{{value}}/s', - seriesOverrides: { - rate: { color: theme.eui.euiColorVis1, type: 'area' }, - }, - }, - }, - { - id: 'nginxActiveConnections', - label: i18n.translate( - 'xpack.infra.metricDetailPage.nginxMetricsLayout.activeConnectionsSection.sectionLabel', - { - defaultMessage: 'Active Connections', - } - ), - requires: ['nginx.stubstatus'], - type: 'chart', - visConfig: { - formatter: 'abbreviatedNumber', - seriesOverrides: { - connections: { - color: theme.eui.euiColorVis1, - type: 'bar', - }, - }, - }, - }, - { - id: 'nginxRequestsPerConnection', - label: i18n.translate( - 'xpack.infra.metricDetailPage.nginxMetricsLayout.requestsPerConnectionsSection.sectionLabel', - { - defaultMessage: 'Requests per Connections', - } - ), - requires: ['nginx.stubstatus'], - type: 'chart', - visConfig: { - formatter: 'abbreviatedNumber', - seriesOverrides: { - reqPerConns: { - color: theme.eui.euiColorVis1, - type: 'bar', - name: i18n.translate( - 'xpack.infra.metricDetailPage.nginxMetricsLayout.requestsPerConnectionsSection.reqsPerConnSeriesLabel', - { - defaultMessage: 'reqs per conn', - } - ), - }, - }, - }, - }, - ], - }, -]; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx new file mode 100644 index 00000000000000..9d31ffa775d213 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/types'; +import { Section } from '../../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../../public/pages/metrics/components/sub_section'; +import { ChartSectionVis } from '../../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../../common/eui_styled_components'; + +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + + + + + + + + + + + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts index a17ca0e2b09e58..6416aa08e85851 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts @@ -16,6 +16,7 @@ import { awsNetworkBytes } from './tsvb/aws_network_bytes'; import { awsNetworkPackets } from './tsvb/aws_network_packets'; import { awsOverview } from './tsvb/aws_overview'; import { InventoryMetrics } from '../../types'; +import { count } from './snapshot/count'; export const metrics: InventoryMetrics = { tsvb: { @@ -30,4 +31,8 @@ export const metrics: InventoryMetrics = { awsNetworkPackets, awsOverview, }, + snapshot: { + count, + }, + defaultSnapshot: 'count', }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/required_metrics.ts b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/required_metrics.ts new file mode 100644 index 00000000000000..0b2623c448646b --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/required_metrics.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { InventoryMetric } from '../../types'; + +export const nginx: InventoryMetric[] = [ + 'nginxHits', + 'nginxRequestRate', + 'nginxActiveConnections', + 'nginxRequestsPerConnection', +]; + +export const aws: InventoryMetric[] = [ + 'awsOverview', + 'awsCpuUtilization', + 'awsNetworkBytes', + 'awsNetworkPackets', + 'awsDiskioOps', + 'awsDiskioBytes', +]; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts b/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts new file mode 100644 index 00000000000000..661b9c7a8841e4 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { idx } from '@kbn/elastic-idx/target'; +import { ReactNode, FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { InventoryItemType } from './types'; +import { HostToolbarItems } from './host/toolbar_items'; +import { ContainerToolbarItems } from './container/toolbar_items'; +import { PodToolbarItems } from './pod/toolbar_items'; +import { ToolbarProps } from '../../public/components/inventory/toolbars/toolbar'; + +interface Toolbars { + [type: string]: ReactNode; +} + +const toolbars: Toolbars = { + host: HostToolbarItems, + container: ContainerToolbarItems, + pod: PodToolbarItems, +}; + +export const findToolbar = (type: InventoryItemType) => { + const Toolbar = idx(toolbars, _ => _[type]); + if (!Toolbar) { + throw new Error( + i18n.translate('xpack.infra.inventoryModels.findToolbar.error', { + defaultMessage: "The toolbar you've attempted to find does not exist.", + }) + ); + } + return Toolbar as FunctionComponent; +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/types.ts b/x-pack/legacy/plugins/infra/common/inventory_models/types.ts index 9c9f11048ee63c..93eaf214ad23e9 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/types.ts @@ -5,7 +5,6 @@ */ import * as rt from 'io-ts'; -import { EuiTheme } from '../../../../common/eui_styled_components'; export const ItemTypeRT = rt.keyof({ host: null, @@ -32,62 +31,50 @@ export const InventoryFormatterTypeRT = rt.keyof({ number: null, percent: null, }); +export type InventoryFormatterType = rt.TypeOf; export type InventoryItemType = rt.TypeOf; -export const InventoryMetricRT = rt.string; -export type InventoryMetric = rt.TypeOf; - -export const SeriesOverridesRT = rt.intersection([ - rt.type({ - color: rt.string, - }), - rt.partial({ - type: InventoryVisTypeRT, - name: rt.string, - formatter: InventoryFormatterTypeRT, - formatterTemplate: rt.string, - gaugeMax: rt.number, - }), -]); - -export const VisConfigRT = rt.partial({ - stacked: rt.boolean, - type: InventoryVisTypeRT, - formatter: InventoryFormatterTypeRT, - formatterTemplate: rt.string, - seriesOverrides: rt.record(rt.string, rt.union([rt.undefined, SeriesOverridesRT])), +export const InventoryMetricRT = rt.keyof({ + hostSystemOverview: null, + hostCpuUsage: null, + hostFilesystem: null, + hostK8sOverview: null, + hostK8sCpuCap: null, + hostK8sDiskCap: null, + hostK8sMemoryCap: null, + hostK8sPodCap: null, + hostLoad: null, + hostMemoryUsage: null, + hostNetworkTraffic: null, + hostDockerOverview: null, + hostDockerInfo: null, + hostDockerTop5ByCpu: null, + hostDockerTop5ByMemory: null, + podOverview: null, + podCpuUsage: null, + podMemoryUsage: null, + podLogUsage: null, + podNetworkTraffic: null, + containerOverview: null, + containerCpuKernel: null, + containerCpuUsage: null, + containerDiskIOOps: null, + containerDiskIOBytes: null, + containerMemory: null, + containerNetworkTraffic: null, + nginxHits: null, + nginxRequestRate: null, + nginxActiveConnections: null, + nginxRequestsPerConnection: null, + awsOverview: null, + awsCpuUtilization: null, + awsNetworkBytes: null, + awsNetworkPackets: null, + awsDiskioBytes: null, + awsDiskioOps: null, + custom: null, }); - -export const InventorySectionTypeRT = rt.keyof({ - chart: null, - gauges: null, -}); - -export type InventorySectionType = rt.TypeOf; - -export const SectionRT = rt.intersection([ - rt.type({ - id: InventoryMetricRT, - label: rt.string, - requires: rt.array(rt.string), - visConfig: VisConfigRT, - type: InventorySectionTypeRT, - }), - rt.partial({ - linkToId: rt.string, - }), -]); - -export const InventoryDetailLayoutRT = rt.type({ - id: rt.string, - label: rt.string, - sections: rt.array(SectionRT), -}); - -export type InventoryDetailSection = rt.TypeOf; -export type InventoryDetailLayout = rt.TypeOf; - -export type InventoryDetailLayoutCreator = (theme: EuiTheme) => InventoryDetailLayout[]; +export type InventoryMetric = rt.TypeOf; export const TSVBMetricTypeRT = rt.keyof({ avg: null, @@ -272,14 +259,27 @@ export const SnapshotModelRT = rt.record( ); export type SnapshotModel = rt.TypeOf; +export const SnapshotMetricTypeRT = rt.keyof({ + count: null, + cpu: null, + load: null, + memory: null, + tx: null, + rx: null, + logRate: null, +}); + +export type SnapshotMetricType = rt.TypeOf; + export interface InventoryMetrics { tsvb: { [name: string]: TSVBMetricModelCreator }; - snapshot?: { [name: string]: SnapshotModel }; + snapshot: { [name: string]: SnapshotModel }; + defaultSnapshot: SnapshotMetricType; } export interface InventoryModel { id: string; requiredModules: string[]; - layout: InventoryDetailLayoutCreator; metrics: InventoryMetrics; + requiredMetrics: InventoryMetric[]; } diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar.tsx b/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar.tsx index f68944b012ccaa..167a328135bf72 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar.tsx @@ -4,18 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { FunctionComponent } from 'react'; import { StaticIndexPattern } from 'ui/index_patterns'; import { Action } from 'typescript-fsa'; import { EuiFlexItem } from '@elastic/eui'; +import { findToolbar } from '../../../../common/inventory_models/toolbars'; import { InfraNodeType, InfraSnapshotMetricInput, InfraSnapshotGroupbyInput, } from '../../../graphql/types'; -import { HostToolbarItems } from './host_toolbar_items'; -import { PodToolbarItems } from './pod_toolbar_items'; -import { ContainerToolbarItems } from './container_toolbar_items'; import { ToolbarWrapper } from './toolbar_wrapper'; import { waffleOptionsSelectors } from '../../../store'; @@ -35,7 +33,7 @@ export interface ToolbarProps { nodeType: ReturnType; } -const wrapToolbarItems = (ToolbarItems: (props: ToolbarProps) => JSX.Element) => { +const wrapToolbarItems = (ToolbarItems: FunctionComponent) => { return ( {props => ( @@ -60,15 +58,7 @@ const wrapToolbarItems = (ToolbarItems: (props: ToolbarProps) => JSX.Element) => ); }; -export const Toolbar = (props: { nodeType: InfraNodeType }) => { - switch (props.nodeType) { - case InfraNodeType.host: - return wrapToolbarItems(HostToolbarItems); - case InfraNodeType.pod: - return wrapToolbarItems(PodToolbarItems); - case InfraNodeType.container: - return wrapToolbarItems(ContainerToolbarItems); - default: - return null; - } +export const Toolbar = ({ nodeType }: { nodeType: InfraNodeType }) => { + const ToolbarItems = findToolbar(nodeType); + return wrapToolbarItems(ToolbarItems); }; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/index.tsx b/x-pack/legacy/plugins/infra/public/components/metrics/index.tsx deleted file mode 100644 index a80525e3a9cacb..00000000000000 --- a/x-pack/legacy/plugins/infra/public/components/metrics/index.tsx +++ /dev/null @@ -1,128 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { EuiPageContentBody, EuiTitle } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; - -import { InfraMetricData } from '../../graphql/types'; -import { NoData } from '../empty_states'; -import { InfraLoadingPanel } from '../loading'; -import { Section } from './section'; -import { MetricsTimeInput } from '../../containers/metrics/with_metrics_time'; -import { - InventoryDetailLayout, - InventoryDetailSection, -} from '../../../common/inventory_models/types'; - -interface Props { - metrics: InfraMetricData[]; - layouts: InventoryDetailLayout[]; - loading: boolean; - refetch: () => void; - nodeId: string; - label: string; - onChangeRangeTime?: (time: MetricsTimeInput) => void; - isLiveStreaming?: boolean; - stopLiveStreaming?: () => void; -} - -interface State { - crosshairValue: number | null; -} - -export const Metrics = class extends React.PureComponent { - public static displayName = 'Metrics'; - public readonly state = { - crosshairValue: null, - }; - - public render() { - if (this.props.loading) { - return ( - - ); - } else if (!this.props.loading && this.props.metrics && this.props.metrics.length === 0) { - return ( - - ); - } - - return {this.props.layouts.map(this.renderLayout)}; - } - - private handleRefetch = () => { - this.props.refetch(); - }; - - private renderLayout = (layout: InventoryDetailLayout) => { - return ( - - - -

- -

-
-
- {layout.sections.map(this.renderSection(layout))} -
- ); - }; - - private renderSection = (layout: InventoryDetailLayout) => (section: InventoryDetailSection) => { - let sectionProps = {}; - if (section.type === 'chart') { - const { onChangeRangeTime, isLiveStreaming, stopLiveStreaming } = this.props; - sectionProps = { - onChangeRangeTime, - isLiveStreaming, - stopLiveStreaming, - crosshairValue: this.state.crosshairValue, - onCrosshairUpdate: this.onCrosshairUpdate, - }; - } - return ( -
- ); - }; - - private onCrosshairUpdate = (crosshairValue: number) => { - this.setState({ - crosshairValue, - }); - }; -}; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/section.tsx b/x-pack/legacy/plugins/infra/public/components/metrics/section.tsx deleted file mode 100644 index ff416bf4541b21..00000000000000 --- a/x-pack/legacy/plugins/infra/public/components/metrics/section.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { InfraMetricData } from '../../graphql/types'; -import { sections } from './sections'; -import { MetricsTimeInput } from '../../containers/metrics/with_metrics_time'; -import { InventoryDetailSection } from '../../../common/inventory_models/types'; - -interface Props { - section: InventoryDetailSection; - metrics: InfraMetricData[]; - onChangeRangeTime?: (time: MetricsTimeInput) => void; - crosshairValue?: number; - onCrosshairUpdate?: (crosshairValue: number) => void; - isLiveStreaming?: boolean; - stopLiveStreaming?: () => void; -} - -export class Section extends React.PureComponent { - public render() { - const metric = this.props.metrics.find(m => m.id === this.props.section.id); - if (!metric) { - return null; - } - let sectionProps = {}; - if (this.props.section.type === 'chart') { - sectionProps = { - onChangeRangeTime: this.props.onChangeRangeTime, - crosshairValue: this.props.crosshairValue, - onCrosshairUpdate: this.props.onCrosshairUpdate, - isLiveStreaming: this.props.isLiveStreaming, - stopLiveStreaming: this.props.stopLiveStreaming, - }; - } - const Component = sections[this.props.section.type]; - return ; - } -} diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/gauges_section.tsx b/x-pack/legacy/plugins/infra/public/components/metrics/sections/gauges_section.tsx deleted file mode 100644 index 6b73ac62872c9b..00000000000000 --- a/x-pack/legacy/plugins/infra/public/components/metrics/sections/gauges_section.tsx +++ /dev/null @@ -1,104 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - EuiFlexItem, - EuiPageContentBody, - EuiPanel, - EuiProgress, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { get, last, max } from 'lodash'; -import React, { ReactText } from 'react'; - -import euiStyled from '../../../../../../common/eui_styled_components'; -import { InfraMetricData } from '../../../graphql/types'; -import { InfraFormatterType } from '../../../lib/lib'; -import { createFormatter } from '../../../utils/formatters'; -import { InventoryDetailSection } from '../../../../common/inventory_models/types'; - -interface Props { - section: InventoryDetailSection; - metric: InfraMetricData; -} - -const getFormatter = (section: InventoryDetailSection, seriesId: string) => (val: ReactText) => { - if (val == null) { - return ''; - } - const defaultFormatter = get(section, ['visConfig', 'formatter'], InfraFormatterType.number); - const defaultFormatterTemplate = get(section, ['visConfig', 'formatterTemplate'], '{{value}}'); - const formatter = get( - section, - ['visConfig', 'seriesOverrides', seriesId, 'formatter'], - defaultFormatter - ); - const formatterTemplate = get( - section, - ['visConfig', 'seriesOverrides', seriesId, 'formatterTemplate'], - defaultFormatterTemplate - ); - return createFormatter(formatter, formatterTemplate)(val); -}; - -export class GaugesSection extends React.PureComponent { - public render() { - const { metric, section } = this.props; - return ( - - - - {metric.series.map(series => { - const lastDataPoint = last(series.data); - if (!lastDataPoint) { - return null; - } - const formatter = getFormatter(section, series.id); - const value = formatter(lastDataPoint.value || 0); - const name = get( - section, - ['visConfig', 'seriesOverrides', series.id, 'name'], - series.id - ); - const dataMax = max(series.data.map(d => d.value || 0)); - const gaugeMax = get( - section, - ['visConfig', 'seriesOverrides', series.id, 'gaugeMax'], - dataMax - ); - return ( - - - - {name} - - -

{value}

-
- -
-
- ); - })} -
- -
- ); - } -} - -const GroupBox = euiStyled.div` - display: flex; - flex-flow: row wrap; - justify-content: space-evenly; -`; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/index.ts b/x-pack/legacy/plugins/infra/public/components/metrics/sections/index.ts deleted file mode 100644 index 39844868ecbea9..00000000000000 --- a/x-pack/legacy/plugins/infra/public/components/metrics/sections/index.ts +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { GaugesSection } from './gauges_section'; -import { ChartSection } from './chart_section'; - -export const sections = { - chart: ChartSection, - gauges: GaugesSection, -}; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/side_nav.tsx b/x-pack/legacy/plugins/infra/public/components/metrics/side_nav.tsx deleted file mode 100644 index f20adadce6042d..00000000000000 --- a/x-pack/legacy/plugins/infra/public/components/metrics/side_nav.tsx +++ /dev/null @@ -1,81 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { EuiHideFor, EuiPageSideBar, EuiShowFor, EuiSideNav } from '@elastic/eui'; - -import React from 'react'; - -import euiStyled from '../../../../../common/eui_styled_components'; -import { - InventoryDetailLayout, - InventoryDetailSection, -} from '../../../common/inventory_models/types'; - -interface Props { - layouts: InventoryDetailLayout[]; - loading: boolean; - nodeName: string; - handleClick: (section: InventoryDetailSection) => () => void; -} - -export const MetricsSideNav = class extends React.PureComponent { - public static displayName = 'MetricsSideNav'; - - public readonly state = { - isOpenOnMobile: false, - }; - - public render() { - let content; - let mobileContent; - if (!this.props.loading) { - const entries = this.props.layouts.map(item => { - return { - name: item.label, - id: item.id, - items: item.sections.map(section => ({ - id: section.id, - name: section.label, - onClick: this.props.handleClick(section), - })), - }; - }); - content = ; - mobileContent = ( - - ); - } - return ( - - - {content} - - {mobileContent} - - ); - } - - private toggleOpenOnMobile = () => { - this.setState({ - isOpenOnMobile: !this.state.isOpenOnMobile, - }); - }; -}; - -const SideNavContainer = euiStyled.div` - position: fixed; - z-index: 1; - height: 88vh; - padding-left: 16px; - margin-left: -16px; - overflow-y: auto; - overflow-x: hidden; -`; diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx index ddb89811ac0235..38e87038b7c4f7 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx @@ -15,6 +15,7 @@ import { InfraNodeType, InfraSnapshotGroupbyInput, } from '../../graphql/types'; +import { findInventoryModel } from '../../../common/inventory_models'; interface Props { nodeType: InfraNodeType; @@ -32,7 +33,10 @@ export const WaffleInventorySwitcher = (props: Props) => { closePopover(); props.changeNodeType(nodeType); props.changeGroupBy([]); - props.changeMetric({ type: InfraSnapshotMetricType.cpu }); + const inventoryModel = findInventoryModel(nodeType); + props.changeMetric({ + type: inventoryModel.metrics.defaultSnapshot as InfraSnapshotMetricType, + }); }, [props.changeGroupBy, props.changeNodeType, props.changeMetric] ); diff --git a/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_layouts.ts b/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_layouts.ts deleted file mode 100644 index 6c7a9d6dcad38c..00000000000000 --- a/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_layouts.ts +++ /dev/null @@ -1,38 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { InfraMetadataFeature } from '../../../../common/http_api/metadata_api'; -import { InventoryDetailLayout } from '../../../../common/inventory_models/types'; - -export const getFilteredLayouts = ( - layouts: InventoryDetailLayout[], - metadata: Array | undefined -): InventoryDetailLayout[] => { - if (!metadata) { - return layouts; - } - - const metricMetadata: Array = metadata - .filter(data => data && data.source === 'metrics') - .map(data => data && data.name); - - // After filtering out sections that can't be displayed, a layout may end up empty and can be removed. - const filteredLayouts = layouts - .map(layout => getFilteredLayout(layout, metricMetadata)) - .filter(layout => layout.sections.length > 0); - return filteredLayouts; -}; - -export const getFilteredLayout = ( - layout: InventoryDetailLayout, - metricMetadata: Array -): InventoryDetailLayout => { - // A section is only displayed if at least one of its requirements is met - // All others are filtered out. - const filteredSections = layout.sections.filter( - section => _.intersection(section.requires, metricMetadata).length > 0 - ); - return { ...layout, sections: filteredSections }; -}; diff --git a/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts b/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts new file mode 100644 index 00000000000000..b485c90700145a --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { InfraMetadataFeature } from '../../../../common/http_api/metadata_api'; +import { InventoryMetric } from '../../../../common/inventory_models/types'; +import { metrics } from '../../../../common/inventory_models/metrics'; + +export const getFilteredMetrics = ( + requiredMetrics: InventoryMetric[], + metadata: Array +) => { + const metricMetadata = metadata + .filter(data => data && data.source === 'metrics') + .map(data => data && data.name); + return requiredMetrics.filter(metric => { + const metricModelCreator = metrics.tsvb[metric]; + // We just need to get a dummy version of the model so we can filter + // using the `requires` attribute. + const metricModel = metricModelCreator('@timestamp', 'test', '>=1m'); + return metricMetadata.some(m => m && metricModel.requires.includes(m)); + }); +}; diff --git a/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts b/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts index 718178ecb4fa20..e04aafee56fd27 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts +++ b/x-pack/legacy/plugins/infra/public/containers/metadata/use_metadata.ts @@ -10,15 +10,15 @@ import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { InfraNodeType } from '../../graphql/types'; import { InfraMetadata, InfraMetadataRT } from '../../../common/http_api/metadata_api'; -import { getFilteredLayouts } from './lib/get_filtered_layouts'; import { useHTTPRequest } from '../../hooks/use_http_request'; import { throwErrors, createPlainError } from '../../../common/runtime_types'; -import { InventoryDetailLayout } from '../../../common/inventory_models/types'; +import { InventoryMetric } from '../../../common/inventory_models/types'; +import { getFilteredMetrics } from './lib/get_filtered_metrics'; export function useMetadata( nodeId: string, nodeType: InfraNodeType, - layouts: InventoryDetailLayout[], + requiredMetrics: InventoryMetric[], sourceId: string ) { const decodeResponse = (response: any) => { @@ -44,7 +44,8 @@ export function useMetadata( return { name: (response && response.name) || '', - filteredLayouts: (response && getFilteredLayouts(layouts, response.features)) || [], + filteredRequiredMetrics: + (response && getFilteredMetrics(requiredMetrics, response.features)) || [], error: (error && error.message) || null, loading, metadata: response, diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx index d06abb2aa1060f..c1b0814f550a36 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { replaceMetricTimeInQueryString } from '../../containers/metrics/with_metrics_time'; +import { replaceMetricTimeInQueryString } from '../metrics/containers/with_metrics_time'; import { useHostIpToName } from './use_host_ip_to_name'; import { getFromFromLocation, getToFromLocation } from './query_params'; import { LoadingPage } from '../../components/loading_page'; diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx index ad513076417807..a2cebbb96a4f0d 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; -import { replaceMetricTimeInQueryString } from '../../containers/metrics/with_metrics_time'; +import { replaceMetricTimeInQueryString } from '../metrics/containers/with_metrics_time'; import { InfraNodeType } from '../../graphql/types'; import { getFromFromLocation, getToFromLocation } from './query_params'; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/chart_section.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx similarity index 72% rename from x-pack/legacy/plugins/infra/public/components/metrics/sections/chart_section.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx index 6d8503b333c0bf..425b5a43f793f7 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/sections/chart_section.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx @@ -6,8 +6,6 @@ import React, { useCallback } from 'react'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; - -import { get } from 'lodash'; import { Axis, Chart, @@ -17,10 +15,8 @@ import { Settings, TooltipValue, } from '@elastic/charts'; -import { EuiPageContentBody, EuiTitle } from '@elastic/eui'; -import { InfraMetricData } from '../../../graphql/types'; -import { getChartTheme } from '../../metrics_explorer/helpers/get_chart_theme'; -import { InfraFormatterType } from '../../../lib/lib'; +import { EuiPageContentBody } from '@elastic/eui'; +import { getChartTheme } from '../../../components/metrics_explorer/helpers/get_chart_theme'; import { SeriesChart } from './series_chart'; import { getFormatter, @@ -32,28 +28,24 @@ import { } from './helpers'; import { ErrorMessage } from './error_message'; import { useKibanaUiSetting } from '../../../utils/use_kibana_ui_setting'; -import { MetricsTimeInput } from '../../../containers/metrics/with_metrics_time'; -import { InventoryDetailSection } from '../../../../common/inventory_models/types'; - -interface Props { - section: InventoryDetailSection; - metric: InfraMetricData; - onChangeRangeTime?: (time: MetricsTimeInput) => void; - isLiveStreaming?: boolean; - stopLiveStreaming?: () => void; -} +import { VisSectionProps } from '../types'; -export const ChartSection = ({ +export const ChartSectionVis = ({ + id, onChangeRangeTime, - section, metric, stopLiveStreaming, isLiveStreaming, -}: Props) => { - const { visConfig } = section; + formatter, + formatterTemplate, + stacked, + seriesOverrides, + type, +}: VisSectionProps) => { + if (!metric || !id) { + return null; + } const [dateFormat] = useKibanaUiSetting('dateFormat'); - const formatter = get(visConfig, 'formatter', InfraFormatterType.number); - const formatterTemplate = get(visConfig, 'formatterTemplate', '{{value}}'); const valueFormatter = useCallback(getFormatter(formatter, formatterTemplate), [ formatter, formatterTemplate, @@ -109,9 +101,6 @@ export const ChartSection = ({ return ( - -

{section.label}

-
( ))} (val: ReactText) => { + if (val == null) { + return ''; + } + const formatter = get(seriesOverrides, [seriesId, 'formatter'], defaultFormatter); + const formatterTemplate = get( + seriesOverrides, + [seriesId, 'formatterTemplate'], + defaultFormatterTemplate + ); + return createFormatter(formatter, formatterTemplate)(val); +}; + +export const GaugesSectionVis = ({ + id, + metric, + seriesOverrides, + formatter, + formatterTemplate, +}: VisSectionProps) => { + if (!metric || !id) { + return null; + } + return ( + + + + {metric.series.map(series => { + const lastDataPoint = last(series.data); + if (!lastDataPoint) { + return null; + } + const formatterFn = getFormatter( + formatter, + formatterTemplate, + seriesOverrides, + series.id + ); + const value = formatterFn(lastDataPoint.value || 0); + const name = getChartName(seriesOverrides, series.id, series.id); + const dataMax = max(series.data.map(d => d.value || 0)); + const gaugeMax = get(seriesOverrides, [series.id, 'gaugeMax'], dataMax); + return ( + + + + {name} + + +

{value}

+
+ +
+
+ ); + })} +
+ +
+ ); +}; + +const GroupBox = euiStyled.div` + display: flex; + flex-flow: row wrap; + justify-content: space-evenly; +`; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts b/x-pack/legacy/plugins/infra/public/pages/metrics/components/helpers.ts similarity index 57% rename from x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/helpers.ts index 2e8d6b056caef4..68c459983bd72f 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/sections/helpers/index.ts +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/helpers.ts @@ -7,19 +7,22 @@ import { ReactText } from 'react'; import Color from 'color'; import { get, first, last, min, max } from 'lodash'; -import { InfraFormatterType } from '../../../../lib/lib'; -import { createFormatter } from '../../../../utils/formatters'; -import { InfraDataSeries, InfraMetricData } from '../../../../graphql/types'; +import { createFormatter } from '../../../utils/formatters'; +import { InfraDataSeries, InfraMetricData } from '../../../graphql/types'; import { - InventoryDetailSection, InventoryVisTypeRT, -} from '../../../../../common/inventory_models/types'; + InventoryFormatterType, + InventoryVisType, +} from '../../../../common/inventory_models/types'; +import { SeriesOverrides } from '../types'; /** * Returns a formatter */ -export const getFormatter = (formatter: InfraFormatterType, template: string) => (val: ReactText) => - val != null ? createFormatter(formatter, template)(val) : ''; +export const getFormatter = ( + formatter: InventoryFormatterType = 'number', + template: string = '{{value}}' +) => (val: ReactText) => (val != null ? createFormatter(formatter, template)(val) : ''); /** * Does a series have more then two points? @@ -47,16 +50,25 @@ export const getMaxMinTimestamp = (metric: InfraMetricData): [number, number] => * Returns the chart name from the visConfig based on the series id, otherwise it * just returns the seriesId */ -export const getChartName = (section: InventoryDetailSection, seriesId: string, label: string) => { - return get(section, ['visConfig', 'seriesOverrides', seriesId, 'name'], label); +export const getChartName = ( + seriesOverrides: SeriesOverrides | undefined, + seriesId: string, + label: string +) => { + if (!seriesOverrides) { + return label; + } + return get(seriesOverrides, [seriesId, 'name'], label); }; /** * Returns the chart color from the visConfig based on the series id, otherwise it * just returns null if the color doesn't exists in the overrides. */ -export const getChartColor = (section: InventoryDetailSection, seriesId: string) => { - const rawColor: string | null = get(section, ['visConfig', 'seriesOverrides', seriesId, 'color']); +export const getChartColor = (seriesOverrides: SeriesOverrides | undefined, seriesId: string) => { + const rawColor: string | null = seriesOverrides + ? get(seriesOverrides, [seriesId, 'color']) + : null; if (!rawColor) { return null; } @@ -67,14 +79,20 @@ export const getChartColor = (section: InventoryDetailSection, seriesId: string) /** * Gets the chart type based on the section and seriesId */ -export const getChartType = (section: InventoryDetailSection, seriesId: string) => { - const value = get(section, ['visConfig', 'type']); - const overrideValue = get(section, ['visConfig', 'seriesOverrides', seriesId, 'type']); +export const getChartType = ( + seriesOverrides: SeriesOverrides | undefined, + type: InventoryVisType | undefined, + seriesId: string +) => { + if (!seriesOverrides || !type) { + return 'line'; + } + const overrideValue = get(seriesOverrides, [seriesId, 'type']); if (InventoryVisTypeRT.is(overrideValue)) { return overrideValue; } - if (InventoryVisTypeRT.is(value)) { - return value; + if (InventoryVisTypeRT.is(type)) { + return type; } return 'line'; }; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/invalid_node.tsx similarity index 92% rename from x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/invalid_node.tsx index 673bca91904c7e..f9e56791746f5c 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/invalid_node.tsx @@ -8,12 +8,12 @@ import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/e import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import euiStyled from '../../../../../common/eui_styled_components'; -import { WithKibanaChrome } from '../../containers/with_kibana_chrome'; +import euiStyled from '../../../../../../common/eui_styled_components'; +import { WithKibanaChrome } from '../../../containers/with_kibana_chrome'; import { ViewSourceConfigurationButton, ViewSourceConfigurationButtonHrefBase, -} from '../../components/source_configuration'; +} from '../../../components/source_configuration'; interface InvalidNodeErrorProps { nodeName: string; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/node_details.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx similarity index 97% rename from x-pack/legacy/plugins/infra/public/components/metrics/node_details.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx index 41331ed73afce1..5329ea992c493d 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/node_details.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx @@ -8,8 +8,8 @@ import React, { useState, useCallback, useMemo } from 'react'; import { EuiButtonIcon, EuiFlexGrid, EuiFlexItem, EuiTitle, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { InfraMetadata } from '../../../common/http_api'; -import euiStyled from '../../../../../common/eui_styled_components'; +import { InfraMetadata } from '../../../../common/http_api'; +import euiStyled from '../../../../../../common/eui_styled_components'; interface Props { metadata?: InfraMetadata | null; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_body.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_body.tsx new file mode 100644 index 00000000000000..81c96c0ffe68d7 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_body.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { findLayout } from '../../../../common/inventory_models/layouts'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; +import { InfraMetricData } from '../../../graphql/types'; +import { MetricsTimeInput } from '../containers/with_metrics_time'; +import { InfraLoadingPanel } from '../../../components/loading'; +import { NoData } from '../../../components/empty_states'; + +interface Props { + loading: boolean; + refetch: () => void; + type: InventoryItemType; + metrics: InfraMetricData[]; + onChangeRangeTime?: (time: MetricsTimeInput) => void; + isLiveStreaming?: boolean; + stopLiveStreaming?: () => void; +} + +export const PageBody = ({ + loading, + refetch, + type, + metrics, + onChangeRangeTime, + isLiveStreaming, + stopLiveStreaming, +}: Props) => { + if (loading) { + return ( + + ); + } else if (!loading && metrics && metrics.length === 0) { + return ( + + ); + } + + const Layout = findLayout(type); + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_error.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_error.tsx new file mode 100644 index 00000000000000..69ba80b85e3b2f --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/page_error.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GraphQLFormattedError } from 'graphql'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { ApolloError } from 'apollo-client'; +import { InvalidNodeError } from './invalid_node'; +import { InfraMetricsErrorCodes } from '../../../../common/errors'; +import { DocumentTitle } from '../../../components/document_title'; +import { ErrorPageBody } from '../../error'; + +interface Props { + name: string; + error: ApolloError; +} + +export const PageError = ({ error, name }: Props) => { + const invalidNodeError = error.graphQLErrors.some( + (err: GraphQLFormattedError) => err.code === InfraMetricsErrorCodes.invalid_node + ); + + return ( + <> + + i18n.translate('xpack.infra.metricDetailPage.documentTitleError', { + defaultMessage: '{previousTitle} | Uh oh', + values: { + previousTitle, + }, + }) + } + /> + {invalidNodeError ? ( + + ) : ( + + )} + + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx new file mode 100644 index 00000000000000..32d2e2eff8ab97 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { + useContext, + Children, + isValidElement, + cloneElement, + FunctionComponent, + useMemo, +} from 'react'; +import { EuiTitle } from '@elastic/eui'; +import { SideNavContext, SubNavItem } from '../lib/side_nav_context'; +import { LayoutProps } from '../types'; + +type SectionProps = LayoutProps & { + navLabel: string; + sectionLabel: string; +}; + +export const Section: FunctionComponent = ({ + children, + metrics, + navLabel, + sectionLabel, + onChangeRangeTime, + isLiveStreaming, + stopLiveStreaming, +}) => { + const { addNavItem } = useContext(SideNavContext); + const subNavItems: SubNavItem[] = []; + + const childrenWithProps = useMemo( + () => + Children.map(children, child => { + if (isValidElement(child)) { + const metric = (metrics && metrics.find(m => m.id === child.props.id)) || null; + if (metric) { + subNavItems.push({ + id: child.props.id, + name: child.props.label, + onClick: () => { + const el = document.getElementById(child.props.id); + if (el) { + el.scrollIntoView(); + } + }, + }); + } + return cloneElement(child, { + metrics, + onChangeRangeTime, + isLiveStreaming, + stopLiveStreaming, + }); + } + return null; + }), + [children, metrics, onChangeRangeTime, isLiveStreaming, stopLiveStreaming] + ); + + if (metrics && subNavItems.length) { + addNavItem({ id: navLabel, name: navLabel, items: subNavItems }); + return ( +
+ +

{sectionLabel}

+
+ {childrenWithProps} +
+ ); + } + + return null; +}; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/sections/series_chart.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/series_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/infra/public/components/metrics/sections/series_chart.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/series_chart.tsx diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/side_nav.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/side_nav.tsx new file mode 100644 index 00000000000000..8e922818222b4f --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/side_nav.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiHideFor, EuiPageSideBar, EuiShowFor, EuiSideNav } from '@elastic/eui'; +import React, { useState, useCallback } from 'react'; +import euiStyled from '../../../../../../common/eui_styled_components'; +import { NavItem } from '../lib/side_nav_context'; + +interface Props { + loading: boolean; + name: string; + items: NavItem[]; +} + +export const MetricsSideNav = ({ loading, name, items }: Props) => { + const [isOpenOnMobile, setMobileState] = useState(false); + + const toggle = useCallback(() => { + setMobileState(!isOpenOnMobile); + }, [isOpenOnMobile]); + + const content = loading ? null : ; + const mobileContent = loading ? null : ( + + ); + return ( + + + {content} + + {mobileContent} + + ); +}; + +const SideNavContainer = euiStyled.div` + position: fixed; + z-index: 1; + height: 88vh; + padding-left: 16px; + margin-left: -16px; + overflow-y: auto; + overflow-x: hidden; +`; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx new file mode 100644 index 00000000000000..f3db3b16701996 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { isValidElement, cloneElement, FunctionComponent, Children, useMemo } from 'react'; +import { EuiTitle } from '@elastic/eui'; +import { InventoryMetric } from '../../../../common/inventory_models/types'; +import { LayoutProps } from '../types'; + +type SubSectionProps = LayoutProps & { + id: InventoryMetric; + label?: string; +}; + +export const SubSection: FunctionComponent = ({ + id, + label, + children, + metrics, + onChangeRangeTime, + isLiveStreaming, + stopLiveStreaming, +}) => { + if (!children || !metrics) { + return null; + } + const metric = metrics.find(m => m.id === id); + if (!metric) { + return null; + } + const childrenWithProps = useMemo( + () => + Children.map(children, child => { + if (isValidElement(child)) { + return cloneElement(child, { + metric, + id, + onChangeRangeTime, + isLiveStreaming, + stopLiveStreaming, + }); + } + return null; + }), + [children, metric, id, onChangeRangeTime, isLiveStreaming, stopLiveStreaming] + ); + return ( +
+ {label ? ( + +

{label}

+
+ ) : null} + {childrenWithProps} +
+ ); +}; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/time_controls.test.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.test.tsx similarity index 95% rename from x-pack/legacy/plugins/infra/public/components/metrics/time_controls.test.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.test.tsx index 61872f52615a02..624a2bb4a6f0f7 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/time_controls.test.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { MetricsTimeControls } from './time_controls'; import { mount } from 'enzyme'; -import { MetricsTimeInput } from '../../containers/metrics/with_metrics_time'; +import { MetricsTimeInput } from '../containers/with_metrics_time'; describe('MetricsTimeControls', () => { it('should set a valid from and to value for Today', () => { diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/time_controls.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.tsx similarity index 92% rename from x-pack/legacy/plugins/infra/public/components/metrics/time_controls.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.tsx index 7d236cf0a3ea78..d181aa37f59aa6 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/time_controls.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/time_controls.tsx @@ -6,8 +6,8 @@ import { EuiSuperDatePicker, OnRefreshChangeProps, OnTimeChangeProps } from '@elastic/eui'; import React from 'react'; -import euiStyled from '../../../../../common/eui_styled_components'; -import { MetricsTimeInput } from '../../containers/metrics/with_metrics_time'; +import euiStyled from '../../../../../../common/eui_styled_components'; +import { MetricsTimeInput } from '../containers/with_metrics_time'; interface MetricsTimeControlsProps { currentTimeRange: MetricsTimeInput; diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics/metrics.gql_query.ts b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/metrics.gql_query.ts similarity index 100% rename from x-pack/legacy/plugins/infra/public/containers/metrics/metrics.gql_query.ts rename to x-pack/legacy/plugins/infra/public/pages/metrics/containers/metrics.gql_query.ts diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics/metrics_time.test.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/metrics_time.test.tsx similarity index 100% rename from x-pack/legacy/plugins/infra/public/containers/metrics/metrics_time.test.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/containers/metrics_time.test.tsx diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics.tsx similarity index 83% rename from x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics.tsx index 67356236ef8f1e..6f7e411628d27b 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics.tsx @@ -13,9 +13,9 @@ import { InfraNodeType, MetricsQuery, InfraTimerangeInput, -} from '../../graphql/types'; +} from '../../../graphql/types'; import { metricsQuery } from './metrics.gql_query'; -import { InventoryDetailLayout, InventoryMetric } from '../../../common/inventory_models/types'; +import { InventoryMetric, InventoryMetricRT } from '../../../../common/inventory_models/types'; interface WithMetricsArgs { metrics: InfraMetricData[]; @@ -26,7 +26,7 @@ interface WithMetricsArgs { interface WithMetricsProps { children: (args: WithMetricsArgs) => React.ReactNode; - layouts: InventoryDetailLayout[]; + requiredMetrics: InventoryMetric[]; nodeType: InfraNodeType; nodeId: string; cloudId: string; @@ -35,23 +35,19 @@ interface WithMetricsProps { } const isInfraMetrics = (subject: any[]): subject is InfraMetric[] => { - return subject.every(s => !!InfraMetric[s]); + return subject.every(s => InventoryMetricRT.is(s)); }; export const WithMetrics = ({ children, - layouts, + requiredMetrics, sourceId, timerange, nodeType, nodeId, cloudId, }: WithMetricsProps) => { - const metrics = layouts.reduce((acc, item) => { - return acc.concat(item.sections.map(s => s.id)); - }, [] as InventoryMetric[]); - - if (!isInfraMetrics(metrics)) { + if (!isInfraMetrics(requiredMetrics)) { throw new Error( i18n.translate('xpack.infra.invalidInventoryMetricsError', { defaultMessage: 'One of the InfraMetric is invalid', @@ -66,7 +62,7 @@ export const WithMetrics = ({ notifyOnNetworkStatusChange variables={{ sourceId, - metrics, + metrics: requiredMetrics, nodeType, nodeId, cloudId, diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics_time.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx similarity index 98% rename from x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics_time.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx index 1afc3a04acd654..6a89e756794680 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics/with_metrics_time.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx @@ -11,8 +11,8 @@ import moment from 'moment'; import dateMath from '@elastic/datemath'; import * as rt from 'io-ts'; import { isRight } from 'fp-ts/lib/Either'; -import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state'; -import { InfraTimerangeInput } from '../../graphql/types'; +import { replaceStateKeyInQueryString, UrlStateContainer } from '../../../utils/url_state'; +import { InfraTimerangeInput } from '../../../graphql/types'; export interface MetricsTimeInput { from: string; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx index 1996d51b4f26b4..643d943273a818 100644 --- a/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx @@ -14,34 +14,28 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { GraphQLFormattedError } from 'graphql'; -import React, { useCallback, useContext } from 'react'; +import React, { useContext, useState } from 'react'; import { UICapabilities } from 'ui/capabilities'; import { injectUICapabilities } from 'ui/capabilities/react'; import euiStyled, { EuiTheme, withTheme } from '../../../../../common/eui_styled_components'; -import { InfraMetricsErrorCodes } from '../../../common/errors'; import { AutoSizer } from '../../components/auto_sizer'; import { DocumentTitle } from '../../components/document_title'; import { Header } from '../../components/header'; -import { Metrics } from '../../components/metrics'; -import { InvalidNodeError } from '../../components/metrics/invalid_node'; -import { MetricsSideNav } from '../../components/metrics/side_nav'; -import { MetricsTimeControls } from '../../components/metrics/time_controls'; +import { MetricsSideNav } from './components/side_nav'; +import { MetricsTimeControls } from './components/time_controls'; import { ColumnarPage, PageContent } from '../../components/page'; -import { WithMetrics } from '../../containers/metrics/with_metrics'; -import { - WithMetricsTime, - WithMetricsTimeUrlState, -} from '../../containers/metrics/with_metrics_time'; +import { WithMetrics } from './containers/with_metrics'; +import { WithMetricsTime, WithMetricsTimeUrlState } from './containers/with_metrics_time'; import { InfraNodeType } from '../../graphql/types'; -import { ErrorPageBody } from '../error'; import { withMetricPageProviders } from './page_providers'; import { useMetadata } from '../../containers/metadata/use_metadata'; import { Source } from '../../containers/source'; import { InfraLoadingPanel } from '../../components/loading'; -import { NodeDetails } from '../../components/metrics/node_details'; +import { NodeDetails } from './components/node_details'; import { findInventoryModel } from '../../../common/inventory_models'; -import { InventoryDetailSection } from '../../../common/inventory_models/types'; +import { PageError } from './components/page_error'; +import { NavItem, SideNavContext } from './lib/side_nav_context'; +import { PageBody } from './components/page_body'; const DetailPageContent = euiStyled(PageContent)` overflow: auto; @@ -69,15 +63,26 @@ export const MetricDetail = withMetricPageProviders( const nodeId = match.params.node; const nodeType = match.params.type as InfraNodeType; const inventoryModel = findInventoryModel(nodeType); - const layoutCreator = inventoryModel.layout; const { sourceId } = useContext(Source.Context); - const layouts = layoutCreator(theme); - const { name, filteredLayouts, loading: metadataLoading, cloudId, metadata } = useMetadata( - nodeId, - nodeType, - layouts, - sourceId + const { + name, + filteredRequiredMetrics, + loading: metadataLoading, + cloudId, + metadata, + } = useMetadata(nodeId, nodeType, inventoryModel.requiredMetrics, sourceId); + + const [sideNav, setSideNav] = useState([]); + + const addNavItem = React.useCallback( + (item: NavItem) => { + if (!sideNav.some(n => n.id === item.id)) { + setSideNav([item, ...sideNav]); + } + }, + [sideNav] ); + const breadcrumbs = [ { href: '#/', @@ -88,18 +93,7 @@ export const MetricDetail = withMetricPageProviders( { text: name }, ]; - const handleClick = useCallback( - (section: InventoryDetailSection) => () => { - const id = section.linkToId || section.id; - const el = document.getElementById(id); - if (el) { - el.scrollIntoView(); - } - }, - [] - ); - - if (metadataLoading && !filteredLayouts.length) { + if (metadataLoading && !filteredRequiredMetrics.length) { return ( {({ metrics, error, loading, refetch }) => { if (error) { - const invalidNodeError = error.graphQLErrors.some( - (err: GraphQLFormattedError) => - err.code === InfraMetricsErrorCodes.invalid_node - ); - - return ( - <> - - i18n.translate('xpack.infra.metricDetailPage.documentTitleError', { - defaultMessage: '{previousTitle} | Uh oh', - values: { - previousTitle, - }, - }) - } - /> - {invalidNodeError ? ( - - ) : ( - - )} - - ); + return ; } return ( - + {({ measureRef, bounds: { width = 0 } }) => { const w = width ? `${width}px` : `100%`; @@ -209,19 +175,19 @@ export const MetricDetail = withMetricPageProviders( - 0 && isAutoReloading ? false : loading - } - refetch={refetch} - onChangeRangeTime={setTimeRange} - isLiveStreaming={isAutoReloading} - stopLiveStreaming={() => setAutoReload(false)} - /> + + 0 && isAutoReloading ? false : loading + } + refetch={refetch} + type={nodeType} + metrics={metrics} + onChangeRangeTime={setTimeRange} + isLiveStreaming={isAutoReloading} + stopLiveStreaming={() => setAutoReload(false)} + /> + diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/lib/side_nav_context.ts b/x-pack/legacy/plugins/infra/public/pages/metrics/lib/side_nav_context.ts new file mode 100644 index 00000000000000..3afd91ef59e934 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/lib/side_nav_context.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +export interface SubNavItem { + id: string; + name: string; + onClick: () => void; +} + +export interface NavItem { + id: string | number; + name: string; + items: SubNavItem[]; +} + +export const SideNavContext = React.createContext({ + items: [] as NavItem[], + addNavItem: (item: NavItem) => {}, +}); diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/page_providers.tsx index 5e43e79ab7c891..0abbd597dd65cd 100644 --- a/x-pack/legacy/plugins/infra/public/pages/metrics/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/page_providers.tsx @@ -6,7 +6,7 @@ import React from 'react'; -import { MetricsTimeContainer } from '../../containers/metrics/with_metrics_time'; +import { MetricsTimeContainer } from './containers/with_metrics_time'; import { Source } from '../../containers/source'; export const withMetricPageProviders = (Component: React.ComponentType) => ( diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/types.ts b/x-pack/legacy/plugins/infra/public/pages/metrics/types.ts new file mode 100644 index 00000000000000..e752164796150f --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/types.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import rt from 'io-ts'; +import { EuiTheme } from '../../../../../common/eui_styled_components'; +import { InfraMetricData } from '../../graphql/types'; +import { InventoryFormatterTypeRT } from '../../../common/inventory_models/types'; +import { MetricsTimeInput } from './containers/with_metrics_time'; + +export interface LayoutProps { + metrics?: InfraMetricData[]; + onChangeRangeTime?: (time: MetricsTimeInput) => void; + isLiveStreaming?: boolean; + stopLiveStreaming?: () => void; +} + +export type LayoutPropsWithTheme = LayoutProps & { theme: EuiTheme }; + +const ChartTypesRT = rt.keyof({ + area: null, + bar: null, + line: null, +}); + +export const SeriesOverridesObjectRT = rt.intersection([ + rt.type({ + color: rt.string, + }), + rt.partial({ + name: rt.string, + formatter: InventoryFormatterTypeRT, + formatterTemplate: rt.string, + gaugeMax: rt.number, + type: ChartTypesRT, + }), +]); + +export const SeriesOverridesRT = rt.record( + rt.string, + rt.union([rt.undefined, SeriesOverridesObjectRT]) +); + +export type SeriesOverrides = rt.TypeOf; + +export const VisSectionPropsRT = rt.partial({ + type: ChartTypesRT, + stacked: rt.boolean, + formatter: InventoryFormatterTypeRT, + formatterTemplate: rt.string, + seriesOverrides: SeriesOverridesRT, +}); + +export type VisSectionProps = rt.TypeOf & { + id?: string; + metric?: InfraMetricData; + onChangeRangeTime?: (time: MetricsTimeInput) => void; + isLiveStreaming?: boolean; + stopLiveStreaming?: () => void; +}; diff --git a/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts b/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts index 4006e672d8b742..efb20e71a9ce45 100644 --- a/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts +++ b/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts @@ -5,26 +5,25 @@ */ import Mustache from 'mustache'; -import { InfraFormatterType, InfraWaffleMapDataFormat } from '../../lib/lib'; +import { InfraWaffleMapDataFormat } from '../../lib/lib'; import { createBytesFormatter } from './bytes'; import { formatNumber } from './number'; import { formatPercent } from './percent'; +import { InventoryFormatterType } from '../../../common/inventory_models/types'; export const FORMATTERS = { - [InfraFormatterType.number]: formatNumber, + number: formatNumber, // Because the implimentation for formatting large numbers is the same as formatting // bytes we are re-using the same code, we just format the number using the abbreviated number format. - [InfraFormatterType.abbreviatedNumber]: createBytesFormatter( - InfraWaffleMapDataFormat.abbreviatedNumber - ), + abbreviatedNumber: createBytesFormatter(InfraWaffleMapDataFormat.abbreviatedNumber), // bytes in bytes formatted string out - [InfraFormatterType.bytes]: createBytesFormatter(InfraWaffleMapDataFormat.bytesDecimal), + bytes: createBytesFormatter(InfraWaffleMapDataFormat.bytesDecimal), // bytes in bits formatted string out - [InfraFormatterType.bits]: createBytesFormatter(InfraWaffleMapDataFormat.bitsDecimal), - [InfraFormatterType.percent]: formatPercent, + bits: createBytesFormatter(InfraWaffleMapDataFormat.bitsDecimal), + percent: formatPercent, }; -export const createFormatter = (format: InfraFormatterType, template: string = '{{value}}') => ( +export const createFormatter = (format: InventoryFormatterType, template: string = '{{value}}') => ( val: string | number ) => { if (val == null) { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 1a66ab3e26fc29..6557875f8b8f80 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4929,7 +4929,6 @@ "xpack.infra.metrics.emptyViewTitle": "表示するデータがありません。", "xpack.infra.metrics.invalidNodeErrorDescription": "構成をよく確認してください", "xpack.infra.metrics.invalidNodeErrorTitle": "{nodeName} がメトリックデータを収集していないようです", - "xpack.infra.metrics.layoutLabelOverviewTitle": "{layoutLabel} 概要", "xpack.infra.metrics.loadingNodeDataText": "データを読み込み中", "xpack.infra.metrics.refetchButtonLabel": "新規データを確認", "xpack.infra.metricsExplorer.actionsLabel.aria": "{grouping} のアクション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 38df1b1f02b8f3..bf1e43b04f9649 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4930,7 +4930,6 @@ "xpack.infra.metrics.emptyViewTitle": "没有可显示的数据。", "xpack.infra.metrics.invalidNodeErrorDescription": "反复检查您的配置", "xpack.infra.metrics.invalidNodeErrorTitle": "似乎 {nodeName} 未在收集任何指标数据", - "xpack.infra.metrics.layoutLabelOverviewTitle": "{layoutLabel} 概览", "xpack.infra.metrics.loadingNodeDataText": "正在加载数据", "xpack.infra.metrics.refetchButtonLabel": "检查新数据", "xpack.infra.metricsExplorer.actionsLabel.aria": "适用于 {grouping} 的操作", diff --git a/x-pack/test/api_integration/apis/infra/metrics.ts b/x-pack/test/api_integration/apis/infra/metrics.ts index d40359edc5ff23..00c57bcc45e327 100644 --- a/x-pack/test/api_integration/apis/infra/metrics.ts +++ b/x-pack/test/api_integration/apis/infra/metrics.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { first, last } from 'lodash'; -import { metricsQuery } from '../../../../legacy/plugins/infra/public/containers/metrics/metrics.gql_query'; +import { metricsQuery } from '../../../../legacy/plugins/infra/public/pages/metrics/containers/metrics.gql_query'; import { MetricsQuery } from '../../../../legacy/plugins/infra/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; From 998b0e6fd68e33326cfb430f1dbc9806c563be4c Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 13 Nov 2019 14:54:21 -0600 Subject: [PATCH 16/59] Upgrade EUI to v14.9.0 (#49678) * eui to 14.9.0 * euiswitch updtates * misc snapshot * x-pack functional fixes * more euiswitch functional test fixes * label-less switches for spaces management * more euiswitch fixes * telemetry form a11y * snapshot update * label updates * more switch updates * lint --- package.json | 2 +- .../filter/filter_bar/filter_editor/index.tsx | 3 +- .../editor/list_control_editor.test.js | 6 +- .../components/editor/options_tab.test.js | 12 +- .../discover_field_search.test.tsx | 2 +- .../field_chooser/discover_field_search.tsx | 3 +- .../__snapshots__/telemetry_form.test.js.snap | 1 + .../public/components/telemetry_form.js | 2 + .../default/controls/auto_precision.tsx | 2 +- .../vis/editors/default/controls/switch.tsx | 2 +- .../default/controls/use_geocentroid.tsx | 2 +- .../tests/customize_panel_modal.test.tsx | 2 +- .../forms/components/fields/toggle_field.tsx | 12 +- .../saved_objects/saved_object_save_modal.tsx | 3 +- .../input_control_options.js | 4 +- .../functional/page_objects/dashboard_page.js | 8 +- .../functional/page_objects/visualize_page.js | 24 +- .../saved_query_management_component.ts | 8 +- .../plugins/kbn_tp_run_pipeline/package.json | 2 +- .../kbn_tp_custom_visualizations/package.json | 2 +- .../kbn_tp_embeddable_explorer/package.json | 2 +- .../kbn_tp_sample_panel_action/package.json | 2 +- .../simple_template.examples.storyshot | 62 ++--- .../arguments/axis_config/simple_template.tsx | 2 + .../components/__tests__/app.test.tsx | 4 +- .../autoplay_settings.examples.storyshot | 213 +++++++++--------- .../toolbar_settings.examples.storyshot | 210 ++++++++--------- .../__snapshots__/settings.test.tsx.snap | 91 ++++---- .../__tests__/autoplay_settings.test.tsx | 10 +- .../settings/__tests__/settings.test.tsx | 4 +- .../__tests__/toolbar_settings.test.tsx | 10 +- .../shareable_runtime/test/selectors.ts | 4 +- .../helpers/follower_index_add.helpers.js | 2 +- .../helpers/follower_index_edit.helpers.js | 2 +- .../__jest__/components/edit_policy.test.js | 14 +- .../__jest__/components/index_table.test.js | 4 +- .../components/waffle/legend_controls.tsx | 5 +- .../definitions/date_histogram.test.tsx | 4 +- .../operations/definitions/date_histogram.tsx | 3 +- .../create_analytics_form.test.tsx | 2 +- .../dedicated_index_switch.tsx | 8 + .../model_plot/model_plot_switch.tsx | 8 + .../sparse_data/sparse_data_switch.tsx | 5 + .../components/job_settings_form.tsx | 4 + .../remote_clusters_add.test.js | 4 +- .../remote_clusters_edit.test.js | 2 +- .../remote_cluster_form.test.js.snap | 124 +++++----- .../__snapshots__/job_switch.test.tsx.snap | 2 + .../ml_popover/jobs_table/job_switch.test.tsx | 4 +- .../ml_popover/jobs_table/job_switch.tsx | 2 + .../ml_popover/jobs_table/jobs_table.test.tsx | 4 +- .../is_ptr_included.test.tsx | 4 +- .../pages/detection_engine/rules/index.tsx | 8 +- .../enabled_features/feature_table.tsx | 5 +- .../edit_space/manage_space_page.test.tsx | 4 +- .../overview/deprecation_logging_toggle.tsx | 2 +- x-pack/package.json | 2 +- .../test/functional/page_objects/gis_page.js | 9 +- .../page_objects/upgrade_assistant.js | 2 +- .../machine_learning/job_wizard_common.ts | 6 +- x-pack/test_utils/testbed/testbed.ts | 8 +- yarn.lock | 8 +- 62 files changed, 542 insertions(+), 435 deletions(-) diff --git a/package.json b/package.json index 757e868d4e02b5..8fa9bf1847eb81 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@elastic/charts": "^14.0.0", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "1.0.5", - "@elastic/eui": "14.8.0", + "@elastic/eui": "14.9.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", "@elastic/numeral": "2.3.3", diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index 5dd5c056477896..74b9a753502299 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -30,6 +30,7 @@ import { EuiPopoverTitle, EuiSpacer, EuiSwitch, + EuiSwitchEvent, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; @@ -431,7 +432,7 @@ class FilterEditorUI extends Component { this.setState({ selectedOperator, params }); }; - private onCustomLabelSwitchChange = (event: React.ChangeEvent) => { + private onCustomLabelSwitchChange = (event: EuiSwitchEvent) => { const useCustomLabel = event.target.checked; const customLabel = event.target.checked ? '' : null; this.setState({ useCustomLabel, customLabel }); diff --git a/src/legacy/core_plugins/input_control_vis/public/components/editor/list_control_editor.test.js b/src/legacy/core_plugins/input_control_vis/public/components/editor/list_control_editor.test.js index 96c0802d3772a2..ea029af9e48908 100644 --- a/src/legacy/core_plugins/input_control_vis/public/components/editor/list_control_editor.test.js +++ b/src/legacy/core_plugins/input_control_vis/public/components/editor/list_control_editor.test.js @@ -236,7 +236,7 @@ test('handleCheckboxOptionChange - multiselect', async () => { component.update(); const checkbox = findTestSubject(component, 'listControlMultiselectInput'); - checkbox.simulate('change', { target: { checked: true } }); + checkbox.simulate('click'); sinon.assert.notCalled(handleFieldNameChange); sinon.assert.notCalled(handleIndexPatternChange); sinon.assert.notCalled(handleNumberOptionChange); @@ -247,7 +247,9 @@ test('handleCheckboxOptionChange - multiselect', async () => { expectedControlIndex, expectedOptionName, sinon.match((evt) => { - if (evt.target.checked === true) { + // Synthetic `evt.target.checked` does not get altered by EuiSwitch, + // but its aria attribute is correctly updated + if (evt.target.getAttribute('aria-checked') === 'true') { return true; } return false; diff --git a/src/legacy/core_plugins/input_control_vis/public/components/editor/options_tab.test.js b/src/legacy/core_plugins/input_control_vis/public/components/editor/options_tab.test.js index 39f5f6a50a5a63..8784f0e79ca8d2 100644 --- a/src/legacy/core_plugins/input_control_vis/public/components/editor/options_tab.test.js +++ b/src/legacy/core_plugins/input_control_vis/public/components/editor/options_tab.test.js @@ -47,8 +47,8 @@ describe('OptionsTab', () => { it('should update updateFiltersOnChange', () => { const component = mountWithIntl(); - const checkbox = component.find('[data-test-subj="inputControlEditorUpdateFiltersOnChangeCheckbox"] input[type="checkbox"]'); - checkbox.simulate('change', { target: { checked: true } }); + const checkbox = component.find('[data-test-subj="inputControlEditorUpdateFiltersOnChangeCheckbox"] button'); + checkbox.simulate('click'); expect(props.setValue).toHaveBeenCalledTimes(1); expect(props.setValue).toHaveBeenCalledWith('updateFiltersOnChange', true); @@ -56,8 +56,8 @@ describe('OptionsTab', () => { it('should update useTimeFilter', () => { const component = mountWithIntl(); - const checkbox = component.find('[data-test-subj="inputControlEditorUseTimeFilterCheckbox"] input[type="checkbox"]'); - checkbox.simulate('change', { target: { checked: true } }); + const checkbox = component.find('[data-test-subj="inputControlEditorUseTimeFilterCheckbox"] button'); + checkbox.simulate('click'); expect(props.setValue).toHaveBeenCalledTimes(1); expect(props.setValue).toHaveBeenCalledWith('useTimeFilter', true); @@ -65,8 +65,8 @@ describe('OptionsTab', () => { it('should update pinFilters', () => { const component = mountWithIntl(); - const checkbox = component.find('[data-test-subj="inputControlEditorPinFiltersCheckbox"] input[type="checkbox"]'); - checkbox.simulate('change', { target: { checked: true } }); + const checkbox = component.find('[data-test-subj="inputControlEditorPinFiltersCheckbox"] button'); + checkbox.simulate('click'); expect(props.setValue).toHaveBeenCalledTimes(1); expect(props.setValue).toHaveBeenCalledWith('pinFilters', true); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx index badfbb4b14a4c1..5054f7b4bdad16 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx @@ -121,7 +121,7 @@ describe('DiscoverFieldSearch', () => { // @ts-ignore (aggregtableButtonGroup.props() as EuiButtonGroupProps).onChange('aggregatable-true', null); }); - missingSwitch.simulate('change', { target: { value: false } }); + missingSwitch.simulate('click'); expect(onChange).toBeCalledTimes(2); }); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx index 3d93487d9e6ccd..d5f6b63d121992 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx @@ -29,6 +29,7 @@ import { EuiPopoverTitle, EuiSelect, EuiSwitch, + EuiSwitchEvent, EuiForm, EuiFormRow, EuiButtonGroup, @@ -154,7 +155,7 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) { setActiveFiltersCount(activeFiltersCount + diff); }; - const handleMissingChange = (e: React.ChangeEvent) => { + const handleMissingChange = (e: EuiSwitchEvent) => { const missingValue = e.target.checked; handleValueChange('missing', missingValue); }; diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap index b96313fd700ac5..3340197fda5132 100644 --- a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap +++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap @@ -34,6 +34,7 @@ exports[`TelemetryForm renders as expected when allows to change optIn status 1` save={[Function]} setting={ Object { + "ariaName": "Provide usage statistics", "defVal": false, "description":

diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index 80eb2da59c47e8..aff830334d577e 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -33,6 +33,7 @@ import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../common/cons import { OptInExampleFlyout } from './opt_in_details_component'; import { Field } from 'ui/management'; import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; const SEARCH_TERMS = ['telemetry', 'usage', 'data', 'usage data']; @@ -117,6 +118,7 @@ export class TelemetryForm extends Component { value: telemetryOptInProvider.getOptIn() || false, description: this.renderDescription(), defVal: false, + ariaName: i18n.translate('telemetry.provideUsageStatisticsLabel', { defaultMessage: 'Provide usage statistics' }) }} save={this.toggleOptIn} clear={this.toggleOptIn} diff --git a/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx b/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx index 3b6aebe8c2b0c5..53f74465e90a5e 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx @@ -23,7 +23,7 @@ import { EuiSwitch, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AggParamEditorProps } from '..'; -function AutoPrecisionParamEditor({ value, setValue }: AggParamEditorProps) { +function AutoPrecisionParamEditor({ value = false, setValue }: AggParamEditorProps) { const label = i18n.translate('common.ui.aggTypes.changePrecisionLabel', { defaultMessage: 'Change precision on map zoom', }); diff --git a/src/legacy/ui/public/vis/editors/default/controls/switch.tsx b/src/legacy/ui/public/vis/editors/default/controls/switch.tsx index a5fc9682bd9543..de675386d91003 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/switch.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/switch.tsx @@ -30,7 +30,7 @@ interface SwitchParamEditorProps extends AggParamEditorProps { } function SwitchParamEditor({ - value, + value = false, setValue, dataTestSubj, displayToolTip, diff --git a/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx b/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx index 6da32690912e7e..932a4d19b495c0 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx @@ -23,7 +23,7 @@ import { EuiSwitch, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AggParamEditorProps } from '..'; -function UseGeocentroidParamEditor({ value, setValue }: AggParamEditorProps) { +function UseGeocentroidParamEditor({ value = false, setValue }: AggParamEditorProps) { const label = i18n.translate('common.ui.aggTypes.placeMarkersOffGridLabel', { defaultMessage: 'Place markers off grid (use geocentroid)', }); diff --git a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx index b11bd167e15f2e..70d7c99d3fb9d0 100644 --- a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx +++ b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx @@ -173,7 +173,7 @@ test('Can set title to an empty string', async () => { ); const inputField = findTestSubject(component, 'customizePanelHideTitle'); - inputField.simulate('change'); + inputField.simulate('click'); findTestSubject(component, 'saveNewTitleButton').simulate('click'); expect(inputField.props().value).toBeUndefined(); diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/toggle_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/toggle_field.tsx index 417f3436a2c63c..0c075c497a4d07 100644 --- a/src/plugins/es_ui_shared/static/forms/components/fields/toggle_field.tsx +++ b/src/plugins/es_ui_shared/static/forms/components/fields/toggle_field.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; -import { EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; import { FieldHook } from '../../hook_form_lib'; import { getFieldValidityAndErrorMessage } from '../helpers'; @@ -33,6 +33,14 @@ interface Props { export const ToggleField = ({ field, euiFieldProps = {}, ...rest }: Props) => { const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); + // Shim for sufficient overlap between EuiSwitchEvent and FieldHook[onChange] event + const onChange = (e: EuiSwitchEvent) => { + const event = ({ ...e, value: `${e.target.checked}` } as unknown) as React.ChangeEvent<{ + value: string; + }>; + field.onChange(event); + }; + return ( { diff --git a/src/plugins/kibana_react/public/saved_objects/saved_object_save_modal.tsx b/src/plugins/kibana_react/public/saved_objects/saved_object_save_modal.tsx index e1e7f1c536342d..bab710cdca5958 100644 --- a/src/plugins/kibana_react/public/saved_objects/saved_object_save_modal.tsx +++ b/src/plugins/kibana_react/public/saved_objects/saved_object_save_modal.tsx @@ -32,6 +32,7 @@ import { EuiOverlayMask, EuiSpacer, EuiSwitch, + EuiSwitchEvent, EuiTextArea, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -227,7 +228,7 @@ export class SavedObjectSaveModal extends React.Component { }); }; - private onCopyOnSaveChange = (event: React.ChangeEvent) => { + private onCopyOnSaveChange = (event: EuiSwitchEvent) => { this.setState({ copyOnSave: event.target.checked, }); diff --git a/test/functional/apps/visualize/input_control_vis/input_control_options.js b/test/functional/apps/visualize/input_control_vis/input_control_options.js index b659d29b158b7d..4088ab6193a59f 100644 --- a/test/functional/apps/visualize/input_control_vis/input_control_options.js +++ b/test/functional/apps/visualize/input_control_vis/input_control_options.js @@ -133,13 +133,13 @@ export default function ({ getService, getPageObjects }) { describe('updateFiltersOnChange is true', () => { before(async () => { await PageObjects.visualize.clickVisEditorTab('options'); - await PageObjects.visualize.checkCheckbox('inputControlEditorUpdateFiltersOnChangeCheckbox'); + await PageObjects.visualize.checkSwitch('inputControlEditorUpdateFiltersOnChangeCheckbox'); await PageObjects.visualize.clickGo(); }); after(async () => { await PageObjects.visualize.clickVisEditorTab('options'); - await PageObjects.visualize.uncheckCheckbox('inputControlEditorUpdateFiltersOnChangeCheckbox'); + await PageObjects.visualize.uncheckSwitch('inputControlEditorUpdateFiltersOnChangeCheckbox'); await PageObjects.visualize.clickGo(); }); diff --git a/test/functional/page_objects/dashboard_page.js b/test/functional/page_objects/dashboard_page.js index ca141114f976dc..af3a15e9b30153 100644 --- a/test/functional/page_objects/dashboard_page.js +++ b/test/functional/page_objects/dashboard_page.js @@ -347,7 +347,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) { async clickSave() { log.debug('DashboardPage.clickSave'); - await testSubjects.clickWhenNotDisabled('confirmSaveSavedObjectButton'); + await testSubjects.click('confirmSaveSavedObjectButton'); } async pressEnterKey() { @@ -543,9 +543,10 @@ export function DashboardPageProvider({ getService, getPageObjects }) { async setSaveAsNewCheckBox(checked) { log.debug('saveAsNewCheckbox: ' + checked); const saveAsNewCheckbox = await testSubjects.find('saveAsNewCheckbox'); - const isAlreadyChecked = (await saveAsNewCheckbox.getAttribute('checked') === 'true'); + const isAlreadyChecked = (await saveAsNewCheckbox.getAttribute('aria-checked') === 'true'); if (isAlreadyChecked !== checked) { log.debug('Flipping save as new checkbox'); + const saveAsNewCheckbox = await testSubjects.find('saveAsNewCheckbox'); await retry.try(() => saveAsNewCheckbox.click()); } } @@ -553,9 +554,10 @@ export function DashboardPageProvider({ getService, getPageObjects }) { async setStoreTimeWithDashboard(checked) { log.debug('Storing time with dashboard: ' + checked); const storeTimeCheckbox = await testSubjects.find('storeTimeWithDashboard'); - const isAlreadyChecked = (await storeTimeCheckbox.getAttribute('checked') === 'true'); + const isAlreadyChecked = (await storeTimeCheckbox.getAttribute('aria-checked') === 'true'); if (isAlreadyChecked !== checked) { log.debug('Flipping store time checkbox'); + const storeTimeCheckbox = await testSubjects.find('storeTimeWithDashboard'); await retry.try(() => storeTimeCheckbox.click()); } } diff --git a/test/functional/page_objects/visualize_page.js b/test/functional/page_objects/visualize_page.js index f3a90f20b6686c..81d26a4b69478e 100644 --- a/test/functional/page_objects/visualize_page.js +++ b/test/functional/page_objects/visualize_page.js @@ -372,6 +372,28 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli } } + async isSwitchChecked(selector) { + const checkbox = await testSubjects.find(selector); + const isChecked = await checkbox.getAttribute('aria-checked'); + return isChecked === 'true'; + } + + async checkSwitch(selector) { + const isChecked = await this.isSwitchChecked(selector); + if (!isChecked) { + log.debug(`checking switch ${selector}`); + await testSubjects.click(selector); + } + } + + async uncheckSwitch(selector) { + const isChecked = await this.isSwitchChecked(selector); + if (isChecked) { + log.debug(`unchecking switch ${selector}`); + await testSubjects.click(selector); + } + } + async setSelectByOptionText(selectId, optionText) { const selectField = await find.byCssSelector(`#${selectId}`); const options = await find.allByCssSelector(`#${selectId} > option`); @@ -1009,7 +1031,7 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli async setIsFilteredByCollarCheckbox(value = true) { await retry.try(async () => { - const isChecked = await this.isChecked('isFilteredByCollarCheckbox'); + const isChecked = await this.isSwitchChecked('isFilteredByCollarCheckbox'); if (isChecked !== value) { await testSubjects.click('isFilteredByCollarCheckbox'); throw new Error('isFilteredByCollar not set correctly'); diff --git a/test/functional/services/saved_query_management_component.ts b/test/functional/services/saved_query_management_component.ts index f134fde028e09d..d6de0be0c172e6 100644 --- a/test/functional/services/saved_query_management_component.ts +++ b/test/functional/services/saved_query_management_component.ts @@ -118,15 +118,17 @@ export function SavedQueryManagementComponentProvider({ getService }: FtrProvide await testSubjects.setValue('saveQueryFormDescription', description); const currentIncludeFiltersValue = - (await testSubjects.getAttribute('saveQueryFormIncludeFiltersOption', 'checked')) === + (await testSubjects.getAttribute('saveQueryFormIncludeFiltersOption', 'aria-checked')) === 'true'; if (currentIncludeFiltersValue !== includeFilters) { await testSubjects.click('saveQueryFormIncludeFiltersOption'); } const currentIncludeTimeFilterValue = - (await testSubjects.getAttribute('saveQueryFormIncludeTimeFilterOption', 'checked')) === - 'true'; + (await testSubjects.getAttribute( + 'saveQueryFormIncludeTimeFilterOption', + 'aria-checked' + )) === 'true'; if (currentIncludeTimeFilterValue !== includeTimeFilter) { await testSubjects.click('saveQueryFormIncludeTimeFilterOption'); } diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json index 766e6168002c29..da1bb597f57308 100644 --- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json +++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json @@ -7,7 +7,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "14.8.0", + "@elastic/eui": "14.9.0", "react": "^16.8.0", "react-dom": "^16.8.0" } diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json index 7c5b6f6be58af2..4d0444265825a2 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json @@ -7,7 +7,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "14.8.0", + "@elastic/eui": "14.9.0", "react": "^16.8.0" } } diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json index ef472b4026957e..196e64af399850 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json @@ -8,7 +8,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "14.8.0", + "@elastic/eui": "14.9.0", "react": "^16.8.0" }, "scripts": { diff --git a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json index 277bb09ac745c5..33e60128d08065 100644 --- a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json +++ b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json @@ -8,7 +8,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "14.8.0", + "@elastic/eui": "14.9.0", "react": "^16.8.0" }, "scripts": { diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/__examples__/__snapshots__/simple_template.examples.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/__examples__/__snapshots__/simple_template.examples.storyshot index bf68d217f18abb..0b9358714e71c6 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/__examples__/__snapshots__/simple_template.examples.storyshot +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/__examples__/__snapshots__/simple_template.examples.storyshot @@ -13,23 +13,26 @@ exports[`Storyshots arguments/AxisConfig simple 1`] = `

- - - - + className="euiSwitch__body" + > + + + +
`; @@ -47,23 +50,26 @@ exports[`Storyshots arguments/AxisConfig/components simple template 1`] = `
- - - - + className="euiSwitch__body" + > + + + +
`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/simple_template.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/simple_template.tsx index eb32881bc1f6d0..068854866dc1bd 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/simple_template.tsx +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/uis/arguments/axis_config/simple_template.tsx @@ -19,6 +19,8 @@ export const SimpleTemplate: FunctionComponent = ({ onValueChange, argVal compressed checked={Boolean(argValue)} onChange={() => onValueChange(!Boolean(argValue))} + showLabel={false} + label="" /> ); }; diff --git a/x-pack/legacy/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx b/x-pack/legacy/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx index db0aac34336eab..9cf2ddc3a22e3e 100644 --- a/x-pack/legacy/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx +++ b/x-pack/legacy/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx @@ -111,7 +111,7 @@ describe('', () => { wrapper.update(); expect(footer(wrapper).prop('isHidden')).toEqual(false); expect(footer(wrapper).prop('isAutohide')).toEqual(false); - toolbarCheck(wrapper).simulate('change'); + toolbarCheck(wrapper).simulate('click'); expect(footer(wrapper).prop('isAutohide')).toEqual(true); canvas(wrapper).simulate('mouseEnter'); expect(footer(wrapper).prop('isHidden')).toEqual(false); @@ -132,7 +132,7 @@ describe('', () => { .simulate('click'); await tick(20); wrapper.update(); - toolbarCheck(wrapper).simulate('change'); + toolbarCheck(wrapper).simulate('click'); await tick(20); // Simulate the mouse leaving the container diff --git a/x-pack/legacy/plugins/canvas/shareable_runtime/components/footer/settings/__examples__/__snapshots__/autoplay_settings.examples.storyshot b/x-pack/legacy/plugins/canvas/shareable_runtime/components/footer/settings/__examples__/__snapshots__/autoplay_settings.examples.storyshot index b159e6499ed9fd..1e66e19b3c0e18 100644 --- a/x-pack/legacy/plugins/canvas/shareable_runtime/components/footer/settings/__examples__/__snapshots__/autoplay_settings.examples.storyshot +++ b/x-pack/legacy/plugins/canvas/shareable_runtime/components/footer/settings/__examples__/__snapshots__/autoplay_settings.examples.storyshot @@ -25,49 +25,52 @@ exports[`Storyshots shareables/Footer/Settings/AutoplaySettings component: off,
- - - - - + + + + - -

- - - - - + + + + - -