diff --git a/.i18nrc.json b/.i18nrc.json index 01065201b9d64..51727ce014f58 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/development/core/server/kibana-plugin-server.basepath.get.md b/docs/development/core/server/kibana-plugin-server.basepath.get.md index 04feca7ccc5a8..2b3b6c899e8de 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 da833c71bf93b..478e29696966c 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 cec70ee853bfa..1272a134ef5c4 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/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index e47326a1d2068..8cbbcdcbca3ef 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-*`. + diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 6e7f939a1d2ab..0f17ffcf26930 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/package.json b/package.json index cf9158c3a59b8..757e868d4e02b 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-analytics/package.json b/packages/kbn-analytics/package.json index e2f3a59e95a47..b0ac86b465a62 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 63fd115fa7594..6514347b0b127 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 13b9e5dc59e4e..ceaf53cbc9753 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 7615fd20645e2..dc8cdcd3e4a1e 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 0000000000000..32282dc54bde6 --- /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 6187455fa60a5..333bc05d28f9b 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 37d23aa443090..98e29c1e4329e 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/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts b/packages/kbn-dev-utils/src/proc_runner/observe_readable.ts index 8feab74d36321..1a292aff303af 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 259bfd782d3fb..21f02325cac66 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 34a56615ed43a..ac46dd02757cf 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 b6d9a540ac940..b36246d97c1ad 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 2e5f897894a90..a6b3e8f96f7db 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/scripts/functional_tests.js b/scripts/functional_tests.js index 472545b203a9b..9f4e678c6adf5 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/core/public/chrome/nav_links/nav_links_service.ts b/src/core/public/chrome/nav_links/nav_links_service.ts index affc639faf0b8..a636ff878dd41 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 cca16ddcd2a81..3c9713a93144a 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 d78504a899a34..1ee41fe64418e 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 ef35fd2aa78ac..1110097c1c92b 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 13d81989417f1..2b16682c13aad 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 cfac4c3648053..0d8887774e900 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 048ae2ccbae7f..1170c42cea704 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 8a481fe1704dd..c58ba14d0da3e 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 dcf599f6d1e10..6eaa140e5afad 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 0b24190741b10..58865d13c1afa 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/index.ts b/src/core/server/index.ts index 35e83da4ef30c..2a5631ad1c380 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 0000000000000..1330c5aee64fd --- /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 b7c55a8af7c18..99963ad9ce3e8 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 2964e34c370b1..38fe519567a63 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/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index 9f7d8e4f35172..34acb66d4e931 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 3bac17bc46686..61e4d752445c4 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 54b9938decb0a..51d4a8ad50ad6 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.api.md b/src/core/server/server.api.md index 73626775381d7..97a04a4a4efab 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.test.ts b/src/core/server/server.test.ts index aee6461580654..f912a31901ad8 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/server.ts b/src/core/server/server.ts index 46974e204c7a4..6c38de03f0f2d 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/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts index 423ff2a1dfd90..1a0f29f6ae6d9 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 022c3e4330032..775c890675410 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 0d9b2a6129de0..315ae3328c47f 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 aead3f35ba841..8e5d9f4860d95 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 77854f9af680b..08288343d9077 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/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker index 0926ef365c894..6609b905b81ec 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/dev/license_checker/valid.ts b/src/dev/license_checker/valid.ts index 8fe09db0a5874..9142955185a1a 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/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 dbff5096f2287..7ee3e375c0967 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 60828b4a2a202..c3892fa581fc4 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/index_patterns.ts b/src/legacy/core_plugins/data/public/index_patterns/index_patterns/index_patterns.ts index 4767b6d3a3ca7..2c58af9deaf49 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/data/public/index_patterns/index_patterns_service.ts b/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts index bdeeb787c983d..9ce1b5f2e4a20 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 62f5ddbe9e2b0..1c877f4f14251 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/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 c7ada18f9e1f2..2ca4ed1e2343d 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 a6ed2e36839f4..4ecc3583e76ce 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/newsfeed/constants.ts b/src/legacy/core_plugins/newsfeed/constants.ts new file mode 100644 index 0000000000000..55a0c51c2ac65 --- /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 0000000000000..cf8852be09a1e --- /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 0000000000000..d4d753f32b0f9 --- /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 0000000000000..a77132379041c --- /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 0000000000000..e25dbd25daaf5 --- /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 0000000000000..c3c3e4144fca8 --- /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/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 9749c7fa8e2f9..8306b3274a914 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/common/constants.ts b/src/legacy/core_plugins/telemetry/common/constants.ts index d7f34d1f8f8eb..7b0c62276f290 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 50a25423b5eb8..149fa99938563 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 1245ef88f5892..95c6ebfc7dc79 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 364871380a529..1930d65d5c09b 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 31091e1952053..4f0f2983477e0 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 4d27bad352cd4..f7b09b1befafa 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 fef0a9b0f9f40..19bc735b9a965 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 0bc1d50fab1be..f963ecec0477c 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 0000000000000..e96c47741f79c --- /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 0000000000000..e092ceb5e8593 --- /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/collectors/usage/ensure_deep_object.ts b/src/legacy/core_plugins/telemetry/server/collectors/usage/ensure_deep_object.ts index 6594c7f8e7a6f..3b7a9355da746 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/core_plugins/telemetry/server/fetcher.ts b/src/legacy/core_plugins/telemetry/server/fetcher.ts new file mode 100644 index 0000000000000..43883395eac99 --- /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 aa13fab9a5f81..02752ca773488 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 813aa0df09e8c..a5f0f1234799a 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 549b3ef6068ec..93654f6470555 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 3a7194890b570..440f83277340a 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 8a91d24b34ed2..e87c041a263a5 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 d0de9cc365a71..261012e594b1c 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 67fc721306c21..6125dadc3646f 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 024272e0f805c..b739b20545678 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 f33727d82f44c..f54aaf0ce1bc0 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 0000000000000..9fa4fbc5e0227 --- /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 67ad3aaae427d..efc4a020e0ff0 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 c8bd4a4b6dfbd..057a8b0c47958 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 0000000000000..f2f99104433a3 --- /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 0000000000000..98f2d6b0c7bbf --- /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 0000000000000..25b588b99a3b8 --- /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 0000000000000..c9b4f4ebcd650 --- /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 0000000000000..7cc177878de4d --- /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 0000000000000..91965ef201ecb --- /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 0000000000000..f3629abc1620c --- /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 0000000000000..b66e01faaa6bc --- /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 6c957f23b5c40..964e3497accba 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 7aafc82cfe4c6..983434f09922b 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 b1e78b56d05d0..5c327234b1e7c 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 7310ee5b5f172..ee928b8a1d9ee 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 8a7950c46fa31..e2de23ea806e4 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/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index 675d37d05c33c..7c0245f30a1fd 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 5c599f16e09c2..effa49f0ade6b 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 f7cae60cce773..1b423e64c48ae 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 348fccdab3fe3..230675ab487ad 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 45f350ea6adc8..e6b5f3831e65d 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 66bc205cead13..c1f5528825bcc 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 f3882ca57161f..7461b5cf07ee7 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 1503f43b22dc3..c9f4bcc3862a0 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 ae09b5cd78977..3125026a52185 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/index_patterns/__mocks__/index.ts b/src/legacy/ui/public/index_patterns/__mocks__/index.ts index 85c07cb3b1df1..2dd3f370c6d6a 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 67c370cad82a5..3b4952ac81519 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/legacy/ui/public/vis/editors/default/components/agg.test.tsx b/src/legacy/ui/public/vis/editors/default/components/agg.test.tsx index 7806b1c0f78fb..661ece5944fa3 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 8e8926f027cad..980889743c20d 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 5fb241714b2e8..eb6bef4887642 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 3928c0a62eeaa..c6772cc108762 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 efc424488ec41..4f82298aaca41 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 056f3e8cfc586..70e0c1f1382fa 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 eadf70a36416a..dbb5a06da9cd9 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 => ( { 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 15c5c9d4ad2e6..35110c924fe61 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 e4606695c0f6a..e207a3ff5961b 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 839e4f6359257..5a580db0c57b8 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 901dc724aa4e4..d2374162b195f 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 9008dc2a67294..017bb8e9cb7c5 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 d7931f191e52b..c2513a9dc0c5e 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 2814735061999..a242df4811c05 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 9eda75d8abd0b..ec8d8b006317f 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -21,3 +21,10 @@ 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; +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 1f2d8f914dde3..d838e54e9ead4 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/index_patterns/field.stub.ts b/src/plugins/data/public/index_patterns/field.stub.ts new file mode 100644 index 0000000000000..315894cd212c4 --- /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 0000000000000..444e65cd0cd4b --- /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/query/filter_manager/lib/mappers/map_geo_polygon.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_geo_polygon.test.ts index 3afa3891a24bb..1847296016c73 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_geo_polygon.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_geo_polygon.test.ts @@ -30,7 +30,10 @@ describe('filter manager utilities', () => { }, 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/query/persisted_log/persisted_log.test.ts b/src/plugins/data/public/query/persisted_log/persisted_log.test.ts index e0bc8f2c3525f..87c1ec29c1aee 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/search/create_app_mount_context_search.test.ts b/src/plugins/data/public/search/create_app_mount_context_search.test.ts index deab9af4e3a01..fa7cdbcda3082 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/data/public/stubs.ts b/src/plugins/data/public/stubs.ts new file mode 100644 index 0000000000000..40a5e7d18f8d9 --- /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/types.ts b/src/plugins/data/public/suggestions_provider/types.ts index eac380dde6a62..988b5fcd43fa8 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 13ccbbd9f3dde..7dc8ff0fe133d 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -19,9 +19,8 @@ // TODO: remove when index patterns are moved here. 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 +36,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 +53,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 +62,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 +71,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 +80,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 +90,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 +101,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 +118,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], ''); diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts index 03eaa5d9594d2..c769f64025b0e 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, 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 e288f61de8681..0bb89cc1af593 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 360182368ae63..3902b0615a33d 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 66c3e8d983f98..62867a0c07a6b 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 cb84370ad69c5..15d6b1c025f54 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 cbae5c4638ca2..cbf2ad07b463e 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/src/plugins/newsfeed/constants.ts b/src/plugins/newsfeed/constants.ts new file mode 100644 index 0000000000000..ddcbbb6cb1dbe --- /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 0000000000000..9d49b42424a06 --- /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 0000000000000..8764b7664d449 --- /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 0000000000000..2e88b0053535e --- /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 0000000000000..33702df00a583 --- /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 0000000000000..cec18e0bdec43 --- /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 0000000000000..8a99abe18a75f --- /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 0000000000000..ca449b8ee879e --- /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 0000000000000..fcbc7970377d4 --- /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 0000000000000..da042f0fce7b6 --- /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 0000000000000..1217de60d9638 --- /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 0000000000000..b9707ff91b936 --- /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 0000000000000..6920dd9b2bccc --- /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 0000000000000..5ea5e5b324717 --- /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 0000000000000..78485c6ee4f59 --- /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 31656df2cb644..f5a1e63617dfa 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/api_integration/apis/ui_metric/ui_metric.js b/test/api_integration/apis/ui_metric/ui_metric.js index efa6be47b50c9..f0c86f2904638 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 44e4bef99bf62..58161e545bd06 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,9 +58,12 @@ 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 0000000000000..beee9bb5c6069 --- /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 0000000000000..2a7ea3793324d --- /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 0000000000000..5291b1031b0a9 --- /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 0000000000000..35d7ac8adefa5 --- /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 17c93680088cb..f3f564fbd2919 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 1e8c454f42cfe..84562990191d1 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 0000000000000..24ff21f0b47de --- /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/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index 570511bee4bc5..4b65de57f12d8 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/global_nav.ts b/test/functional/services/global_nav.ts index 164ea999fa279..df3aac67f22a1 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/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index b6b68cc0d3cf9..71e2711906fce 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 377163251010c..298eaaaf420e0 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 acb75b15196d6..d3f2360add6c0 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/test/ui_capabilities/newsfeed_err/config.ts b/test/ui_capabilities/newsfeed_err/config.ts new file mode 100644 index 0000000000000..1f5f770e8447c --- /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 0000000000000..2aa81f34028a0 --- /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); + }); + }); +} diff --git a/x-pack/legacy/common/eui_draggable/index.d.ts b/x-pack/legacy/common/eui_draggable/index.d.ts index a85da7a69534c..322966b3c982e 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 3e71725713070..a5bf42bc2cc01 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 9a8f11c6493c5..522f6d39ac71a 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/index.ts b/x-pack/legacy/plugins/apm/index.ts index 556bce9d37bb5..4655e5e6f92ea 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({ @@ -90,7 +87,7 @@ export const apm: LegacyPluginInitializer = kibana => { catalogue: ['apm'], privileges: { all: { - api: ['apm'], + api: ['apm', 'apm_write'], catalogue: ['apm'], savedObject: { all: [], @@ -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/public/components/app/ServiceMetrics/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx index 276d309cbb3e3..8005fc17f2a20 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 b69076b3a1f70..a118871a5e268 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 d03e70fc99cc6..b696af040223b 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 db0ddb56e7088..fc86f4bb78afb 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 d81b7417570a5..f016052df56a2 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 7c0b6f24f87a7..9918f162a01f4 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 bdf895f423913..4398c129aa7b8 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 ca14be237d22b..b7963b5c75a92 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 52afdffcb0839..d765a57a56a18 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 7b9586634c7d0..50c94fe88e6ad 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 80a1b96efb3d6..2b0263f69db8f 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/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx index a18882120fe75..a224df9e59e58 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/apm_telemetry/make_apm_usage_collector.ts b/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/make_apm_usage_collector.ts index 8a91bd8781fe7..886c3890f1a9a 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/errors/distribution/__tests__/get_buckets.test.ts b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts index b7081c43465bf..5bbd6be14a708 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 ee41599454dd6..f38184fe460b1 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 57de438be7f2a..6ebf7a896591f 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 3ec519d5e71b5..850de4939d599 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_agent_config_index.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts index 861732ee03923..18f6aea610a68 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/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 25a4f5141498f..23faa4b74cf8f 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 896363c054ba7..ed20a58b271e1 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 d5aa389cea335..52efc2b50305b 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 283f30b51441d..dd4d019ef7263 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 e5349edb67f30..b7b9c21172140 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 400bd0207771a..dcf7329b229d8 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 35d76d745cf4f..969bbc542f8a6 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 99553690359cf..ca10183bb259e 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 67816d67a29a2..2648851789c66 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/breakdown/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts index a21c4f38ac30c..3d425415de832 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/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 cddc66e52cf70..3b9e80c901fe9 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 5056a100de3ce..0345b0815679f 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/lib/ui_filters/local_ui_filters/config.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 5d10a4ae27060..a0149bec728c5 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/new-platform/plugin.ts b/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts index 0458c8e4fedf0..351afe618901e 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 b0461f5cb3b68..18fe547a34cf0 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,19 @@ describe('createApi', () => { }, handler: async () => null })) - .init(coreMock); + .add(() => ({ + path: '/baz', + method: 'PUT', + options: { + tags: ['access:apm', 'access:apm_write'] + }, + handler: async () => null + })) + .init(coreMock, legacySetupMock); - expect(coreMock.http.server.route).toHaveBeenCalledTimes(2); + expect(legacySetupMock.server.route).toHaveBeenCalledTimes(3); - 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 +61,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', @@ -61,11 +71,23 @@ 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', () => { const initApi = (params: Params) => { const core = getCoreMock(); + const legacySetupMock = getLegacyMock(); const handler = jest.fn(); createApi() .add(() => ({ @@ -73,9 +95,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 f969e4d6024ca..66f28a9bf6d44 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,15 +30,14 @@ 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< - 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; @@ -54,9 +54,7 @@ export function createApi() { server.route( merge( { - options: { - tags: ['access:apm'] - }, + options, method: 'GET' }, route, @@ -70,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/index_pattern.ts b/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts index 100df4dc238fe..92e1284f3ed74 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 85d53925db86e..26fdf2ab65d1a 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/agent_configuration.ts b/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts index d25ad949d6dde..2867cef28d952 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/settings/apm_indices.ts b/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts index 3c82a35ec7903..40c29f3050455 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 a0ddffe044c15..77d96d3677494 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; @@ -33,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, @@ -45,7 +49,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 +83,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 @@ -88,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 9d36946d29cf6..36508e53acce7 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 9f17b0197a5b2..b694e9526e2b8 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 56cd0ff23a3fb..eff39838bd957 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 92137bdf5cc6e..8972084018d98 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 0d5c67d09da8a..bc77abc9815be 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 479be32ce1e12..3ac2ff72c0116 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 8736663dd08af..f15e08c2ca230 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 a93000a3e80f0..6f03f884563e1 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 4a7f768bd4740..b2e11461007fd 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 31c55b9272193..190c9e265463d 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 8274764e759ab..92cfcc935ad9b 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 4718abc1b7153..83129384a77df 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 cfcc2c4eda397..df9c65034115b 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 bb0376ab87d29..156304443431d 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 c80c37bb1ed56..e592c6d22ef73 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 bfc3212fa234c..a5b65e6bdc62b 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 f44d37abe166f..74c13be3abd7b 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 c180b6186ee92..718f2d8b11e1a 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 5889864df3c1d..5d5c3c1a735a0 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 9229def146f8b..042cbe83fb10f 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 6a7a89231f250..4bb68973e80ea 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 16ca644160c0a..d40c5f787e44f 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 8ecde2cc721e3..f26b3510c7682 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 8789577c92f63..f0a5325baf3c0 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 b3aa9c393096b..65b811fe68134 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 69c4463e7d210..6c05eec0c3c09 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 2c7820df26ca9..7fb73b1672eb1 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 e85ce8c10da64..89c0b5b21c581 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 26a0d92655362..dabf06a24aeb6 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 20d19d2fcbd82..8faaf278a07de 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 8a040c0c90c83..612406c30f88e 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 6ae4ef984264f..4bcdb547186d1 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 32e9cbbd1d91d..774214cf68cec 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 a0692584d4986..a51e6b4b5d987 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 06507e4eb9a71..ef5de3feb575c 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 51d856b0fc7a6..430d6a5343662 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 825ea8a4f2494..9de5f81b440ba 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 f60aad1fa3e72..ac282962afb54 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 723b30aac37fa..fca663f8532d8 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 2b966e7bd6bb8..c6dddab3b5dd1 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 b13740f177a23..aa3bbdce97863 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 dc4c4461c5921..316a49c85c09d 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 cf2e80cee03bf..fc0bd4c74ba24 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 6d3c9a0640ba2..d2fece567a8ad 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 718fec9f59f77..53c053811a273 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 406d6b54729b9..b22a9d35aa793 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 34c3d446c5ca7..731656dd4e095 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 56ea35a6887ec..4ee3a65172a2e 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, @@ -146,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 }) => ({ @@ -197,8 +208,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 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 893caba1465b8..46a97f7c15d74 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 4b99a5ef298d8..d3da1b5553958 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 1005cc60e50ba..7b7e87b027af5 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 87b33cbe35f82..d7df3513dba8d 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 62bb62c1f6125..865de323332c4 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 1d1148f8716a1..93fc9b729ca74 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 54147c24ceec0..255e5b75c1390 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 0f70c40059c93..a99b265fc3ea9 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 f2adc507e7b99..8e55caae738e7 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 dd368ef4d8f92..62db9d517c9d2 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 bfc1385c0431a..2e8d6b056caef 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 2f6097a1514fa..fd18adea3aad0 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 708fd34f23257..90361a5c2b541 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 927ce4c3e1f58..1f4c924ea3da5 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 bbcec36e17f9d..075f3904d994c 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 540e32a27b319..718178ecb4fa2 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 95f130878fc52..67356236ef8f1 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 2d809521dc9e8..d2fa49e8d5d9f 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 41be5dd9eee9f..e4163eed9f61c 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/hooks/use_track_metric.tsx b/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx index 4d9ca3704873c..379b3af3f1063 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/infra/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/public/lib/adapters/framework/kibana_framework_adapter.ts index 5f763b3199a91..d70a42473b710 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 d9c1c825f1a25..986d6b17a2424 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 ec9c0a1584f13..0b6d01bdf5288 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 7520803f93ac7..0306efc334a51 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 f79ce792cac3d..6af6bce315599 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 9735b1e1cb839..0cbc94516617b 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 3a27051755446..4642f7fd26f21 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 179bfef6f1bd8..a6881a05f6f93 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 d46ebbb26fbb8..98d1e2cd89b01 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 4f51677a04449..95d5381d44ab2 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 31d622c7089a8..157537ad574c1 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 f03b64295641b..6b15bc5c2ef30 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 9ad6864b64853..79cea1fb58cc6 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 03ba2e5b84d93..c74b729e4fb7e 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 0555787ec840d..c44d63b01c1b3 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 d83777b758da6..40d9d25869c7a 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 6456250157148..9ad3fb679471e 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 61823fd09c967..9147483247c2e 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 f4fa9b3862733..96006ae6b6ed1 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 f82def178261b..ba1ac461161b1 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 31f1870ee54b4..9b6dcfa8d0f56 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 c52b99c350e38..bed7ba8bc7736 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 5086b29a85725..586e503632eb9 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/file_based/file_datavisualizer_directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js index fa4e0c2654e97..8b76e57029bd1 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/datavisualizer/index_based/page.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/page.tsx index 9123858eef4e5..0e72bf41f177b 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/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 8bd3d9228b857..2b01a84894564 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 e7e99830372d8..b09162b0e84cf 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 17562aba8e45a..c4684f356fdaf 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 05f9ec9d943f9..71e16188db948 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 3267c78deecc1..4b6f3f485d49d 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 358bbf67bee48..82b1684b7b72f 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 224d9ebf55823..b1bd352db387b 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 3a3bd0c5a13a4..54fb19d868cdc 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 da6a19434135c..ea03d16fcccca 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 1927fc430abcb..5e1bf9f1ec889 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 dc0311e552bda..ebe113a1f8bef 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 964dc1eee5140..09f14c971418d 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 0000000000000..ab6dcf8a5b5f6 --- /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 b9777e34737ae..0000000000000 --- 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 4f042c638471d..38a71d994c601 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 0000000000000..2b6fb50538020 --- /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 e3c4bc8a4a28c..95d670eda8a4f 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; } 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 59a33db1da2e9..eb2f50b8e9250 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 69a0472800bf6..812a135f6cf08 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/monitoring/server/telemetry_collection/__tests__/get_all_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js index 0d147b747f2d0..c1425de20d146 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 b1e8db1b96005..ce33068725d9c 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 fdf46122f13b7..f784457b46bc3 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/reporting/export_types/csv/server/create_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/create_job.ts index b1713e1753eea..f9542279f52d9 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 4176a1351d654..f1008a4866fd7 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 72bd3c47ead35..e22d3662a33b4 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 d7990b1204b21..642b2b741abf0 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 1025a340b2d86..37ee43c5473b0 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 619ccc7e408fc..c7bbdbfccf082 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 8770048b5b0e8..408743d261797 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 7674fd09739f5..4050b4f9d70a8 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 0fc7bc6afc216..e069c1a8b8be7 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 b9e32ee897910..35d54414944f4 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 998b90d11a4d8..3628330fbd459 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 5681588cb44b7..68ad6c4e79623 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 2c8092a3295ad..3958cd463d56e 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 d96d161fc0e80..aae8f67997156 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 ba5275ed79aef..4b5ceb25befa4 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 7f835e0e937e6..56bd86310acad 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 b2b21129f188c..5907d16e68f57 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 81b7914b81742..c53407a9f2f03 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 0c44b8d44c317..23cd855cc028a 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 b9b132b4f50a4..c0d11deec94ed 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 cdc84c513737d..502fa0583536a 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 2f2d84306e25e..00eec3fe3a754 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 a5e0977ab9eef..b5e07809f2e12 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 ac5470ee4f236..cc7a895623303 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 71807280ebcb4..e5ad39b814caa 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 107863e6067df..15c48ddf32cd6 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 a41b59b3c6528..b37a3dce808bd 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 6adb335839982..7dd9ca0273c5b 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 ce1376d753f70..8da41fca8f384 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 5b60b62521293..f5a99c631131f 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 cfd7cd840dac8..acf91067c4291 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 59f55f33842fe..2e1a3f1a7f3a1 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 2cba2a4b39f1b..d16e446a879a6 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 531e61dd7dc60..e5656455623b5 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 e5f50c332a7c2..e97a8c0860d36 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 78a9488b2fdbb..e4afef9a351e8 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 7e549a08f9511..8a78d04c88311 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 0ebceccfa90c5..ec491fe50407a 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 b58b60587c863..8164348620b50 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 f548fe9ee8d48..39c540b3bd355 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 f1eeb4e6fbec4..d7fece5731972 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 78e03a36f40cb..665148b7ad650 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 bf8726d5ed377..e9f4c95a80b74 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 2cb193fb47c6b..453f26240a87f 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 1dc21c9d0284f..f616abbac5745 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 b1751cca0b3d0..d160e4f57be6b 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 6b4c54737eb10..b919985fecb04 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 9037583d278a7..16f02fd85cbc2 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 7d00569f9a0ea..8ebeae4bba392 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 7c33c0f787694..cb2d357b74007 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 cf57c0d07c43e..a33684472b279 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 8d4a93ca97eb3..6957db5578af5 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 50cfd89fd057a..3b10314f72531 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 14f51a601fa7f..c248387e6b3fd 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 007d8b9325a86..7a69c11ecf2e5 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 456a79efe874a..1045826bf488f 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 2bae05dbe3b93..83eecc459cd6e 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 208681d002b5b..90839f5ac01c4 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 574ec2d03bcf9..979262c7faff3 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 004ec8b9c0517..797e7480454a3 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 01fc904906bf1..62038f9963836 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 d7ac8d227fc4c..c4927475d586b 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 24cb50a59adc8..f5856aa6fac33 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 c52b99c350e38..bed7ba8bc7736 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 df2ce6b56a5af..eec93d4e08996 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 8bf7ea66d28b1..91e5be5331203 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 ea81b33afbd23..bfde8f171874e 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 a7e4e49440089..c6bae80e6de96 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 cb796230bf942..527f2b6486d7f 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 e04acfd5bf51e..0921b5e7e5cfa 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 13d267cc5c31e..d43a86d2b0e06 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 6fe4d72db3f16..41a4552b722de 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 3228b15297974..219f92ce36e63 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 23ead8271f6ff..b739575a1dd4a 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 099bbe2fc7185..874fb2e37e902 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 cad8b412f3e58..6c71d91794003 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 f281408c9d439..aa7cca6774548 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 ee89d9bfc176a..910d4f1e0b15c 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 f3ebee479b664..25daf190dc1b1 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/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 f19695ca06525..6915da5263624 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/plugins/encrypted_saved_objects/server/crypto/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts index b1795b9439808..54a4203b89191 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 8574293e3e6a6..d101b55d6ad37 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 0b3bdfb599343..22c9379686b34 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 a0cb1ea1a2b67..02574d0851ba0 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 355aeef7f20c7..a85e1fb0e8f8f 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 60f032652221b..6f339a6fc9c95 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 3fca1007413d4..dfddf2036f1b8 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 2caba6ee20f61..0e31dd3d51aba 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 ac8f6cc61edfa..824189fa77a26 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 788395feae442..fa3e1959ba7de 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 b21a23718f861..a8683796293af 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 8e91faa95b459..2906f28912d5b 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 99a4d11fb13b7..0180554a47ccc 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 3a101324ec196..0c5b37883bfb1 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 c590c24923a8c..609b7d2f35c4b 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 f802c011f207e..3c04508e3a74a 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 f25908147bfe5..4f78828b14dc2 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 7a984acb2c09f..1252dd1400807 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 02e0b3795fcc5..badec079d6828 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/apps/advanced_settings/feature_controls/advanced_settings_security.ts b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts index 0834ff11ced58..d60b286e3337a 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/x-pack/test/functional/services/infra_source_configuration_form.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts index a311f38b67c18..ab61d5232fa1c 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 1c7be6def614d..98d653d71b5ec 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 85e877912ab6c..7383bb3409f1a 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 b1f82ceae3b42..4984ccca7cef9 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 71f032cf720dc..4990d2bab0a77 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" @@ -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==