diff --git a/.ci/end2end.groovy b/.ci/end2end.groovy index 5cf6efe324ac3..38fed4aca19dc 100644 --- a/.ci/end2end.groovy +++ b/.ci/end2end.groovy @@ -25,7 +25,7 @@ pipeline { durabilityHint('PERFORMANCE_OPTIMIZED') } triggers { - issueCommentTrigger('(?i).*jenkins\\W+run\\W+(?:the\\W+)?e2e(?:\\W+please)?.*') + issueCommentTrigger('(?i)(retest|.*jenkins\\W+run\\W+(?:the\\W+)?e2e?.*)') } parameters { booleanParam(name: 'FORCE', defaultValue: false, description: 'Whether to force the run.') @@ -60,8 +60,14 @@ pipeline { } } steps { + notifyStatus('Starting services', 'PENDING') dir("${APM_ITS}"){ - sh './scripts/compose.py start master --no-kibana --no-xpack-secure' + sh './scripts/compose.py start master --no-kibana' + } + } + post { + unsuccessful { + notifyStatus('Environmental issue', 'FAILURE') } } } @@ -77,10 +83,16 @@ pipeline { JENKINS_NODE_COOKIE = 'dontKillMe' } steps { + notifyStatus('Preparing kibana', 'PENDING') dir("${BASE_DIR}"){ sh script: "${CYPRESS_DIR}/ci/prepare-kibana.sh" } } + post { + unsuccessful { + notifyStatus('Kibana warm up failed', 'FAILURE') + } + } } stage('Smoke Tests'){ options { skipDefaultCheckout() } @@ -91,6 +103,7 @@ pipeline { } } steps{ + notifyStatus('Running smoke tests', 'PENDING') dir("${BASE_DIR}"){ sh ''' jobs -l @@ -112,6 +125,12 @@ pipeline { archiveArtifacts(allowEmptyArchive: false, artifacts: 'apm-its.log') } } + unsuccessful { + notifyStatus('Test failures', 'FAILURE') + } + success { + notifyStatus('Tests passed', 'SUCCESS') + } } } } @@ -123,3 +142,7 @@ pipeline { } } } + +def notifyStatus(String description, String status) { + withGithubNotify.notify('end2end-for-apm-ui', description, status, getBlueoceanDisplayURL()) +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bf1e341c796fa..e54b7b56707e8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -170,7 +170,7 @@ /x-pack/legacy/plugins/index_lifecycle_management/ @elastic/es-ui /x-pack/legacy/plugins/index_management/ @elastic/es-ui /x-pack/legacy/plugins/license_management/ @elastic/es-ui -/x-pack/legacy/plugins/remote_clusters/ @elastic/es-ui +/x-pack/plugins/remote_clusters/ @elastic/es-ui /x-pack/legacy/plugins/rollup/ @elastic/es-ui /x-pack/plugins/searchprofiler/ @elastic/es-ui /x-pack/legacy/plugins/snapshot_restore/ @elastic/es-ui diff --git a/docs/developer/plugin/development-plugin-resources.asciidoc b/docs/developer/plugin/development-plugin-resources.asciidoc index 71c442aaf52e8..a2fd0e23d0be4 100644 --- a/docs/developer/plugin/development-plugin-resources.asciidoc +++ b/docs/developer/plugin/development-plugin-resources.asciidoc @@ -66,3 +66,8 @@ To enable TypeScript support, create a `tsconfig.json` file at the root of your TypeScript code is automatically converted into JavaScript during development, but not in the distributable version of Kibana. If you use the {repo}blob/{branch}/packages/kbn-plugin-helpers[@kbn/plugin-helpers] to build your plugin, then your `.ts` and `.tsx` files will be permanently transpiled before your plugin is archived. If you have your own build process, make sure to run the TypeScript compiler on your source files and ship the compilation output so that your plugin will work with the distributable version of Kibana. + +==== {kib} platform migration guide + +{repo}blob/{branch}/src/core/MIGRATION.md#migrating-legacy-plugins-to-the-new-platform[This guide] +provides an action plan for moving a legacy plugin to the new platform. diff --git a/examples/ui_action_examples/public/hello_world_trigger.ts b/examples/ui_action_examples/public/hello_world_trigger.ts index 999a7d9864707..929c9aecab17b 100644 --- a/examples/ui_action_examples/public/hello_world_trigger.ts +++ b/examples/ui_action_examples/public/hello_world_trigger.ts @@ -18,11 +18,9 @@ */ import { Trigger } from '../../../src/plugins/ui_actions/public'; -import { HELLO_WORLD_ACTION_TYPE } from './hello_world_action'; export const HELLO_WORLD_TRIGGER_ID = 'HELLO_WORLD_TRIGGER_ID'; export const helloWorldTrigger: Trigger = { id: HELLO_WORLD_TRIGGER_ID, - actionIds: [HELLO_WORLD_ACTION_TYPE], }; diff --git a/examples/ui_action_examples/public/plugin.ts b/examples/ui_action_examples/public/plugin.ts index ef0689227d6bd..bf62b4d973d4d 100644 --- a/examples/ui_action_examples/public/plugin.ts +++ b/examples/ui_action_examples/public/plugin.ts @@ -19,7 +19,7 @@ import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; import { UiActionsSetup, UiActionsStart } from '../../../src/plugins/ui_actions/public'; -import { createHelloWorldAction } from './hello_world_action'; +import { createHelloWorldAction, HELLO_WORLD_ACTION_TYPE } from './hello_world_action'; import { helloWorldTrigger } from './hello_world_trigger'; interface UiActionExamplesSetupDependencies { @@ -33,8 +33,9 @@ interface UiActionExamplesStartDependencies { export class UiActionExamplesPlugin implements Plugin { - public setup(core: CoreSetup, deps: UiActionExamplesSetupDependencies) { - deps.uiActions.registerTrigger(helloWorldTrigger); + public setup(core: CoreSetup, { uiActions }: UiActionExamplesSetupDependencies) { + uiActions.registerTrigger(helloWorldTrigger); + uiActions.attachAction(helloWorldTrigger.id, HELLO_WORLD_ACTION_TYPE); } public start(coreStart: CoreStart, deps: UiActionExamplesStartDependencies) { diff --git a/examples/ui_actions_explorer/public/plugin.tsx b/examples/ui_actions_explorer/public/plugin.tsx index 9c5f967a466bf..981ad97a31b46 100644 --- a/examples/ui_actions_explorer/public/plugin.tsx +++ b/examples/ui_actions_explorer/public/plugin.tsx @@ -56,15 +56,12 @@ export class UiActionsExplorerPlugin implements Plugin, deps: SetupDeps) { deps.uiActions.registerTrigger({ id: COUNTRY_TRIGGER, - actionIds: [], }); deps.uiActions.registerTrigger({ id: PHONE_TRIGGER, - actionIds: [], }); deps.uiActions.registerTrigger({ id: USER_TRIGGER, - actionIds: [], }); deps.uiActions.registerAction(lookUpWeatherAction); deps.uiActions.registerAction(viewInMapsAction); diff --git a/package.json b/package.json index 26e1112ead697..e4fdaf32a014a 100644 --- a/package.json +++ b/package.json @@ -80,12 +80,14 @@ }, "resolutions": { "**/@types/node": "10.12.27", - "**/@types/react": "^16.9.13", + "**/@types/react": "^16.9.19", "**/@types/react-router": "^5.1.3", "**/@types/hapi": "^17.0.18", "**/@types/angular": "^1.6.56", + "**/@types/hoist-non-react-statics": "^3.3.1", "**/typescript": "3.7.2", "**/graphql-toolkit/lodash": "^4.17.13", + "**/hoist-non-react-statics": "^3.3.2", "**/isomorphic-git/**/base64-js": "^1.2.1", "**/image-diff/gm/debug": "^2.6.9", "**/react-dom": "^16.12.0", @@ -120,7 +122,7 @@ "@elastic/charts": "^17.0.2", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.6.0", - "@elastic/eui": "18.3.0", + "@elastic/eui": "19.0.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", "@elastic/numeral": "2.3.5", @@ -234,19 +236,19 @@ "react-input-range": "^1.3.0", "react-markdown": "^3.4.1", "react-monaco-editor": "~0.27.0", - "react-redux": "^5.1.2", + "react-redux": "^7.1.3", "react-resize-detector": "^4.2.0", "react-router-dom": "^5.1.2", "react-sizeme": "^2.3.6", "react-use": "^13.13.0", "reactcss": "1.2.3", - "redux": "4.0.0", - "redux-actions": "2.6.5", - "redux-thunk": "2.3.0", + "redux": "^4.0.5", + "redux-actions": "^2.6.5", + "redux-thunk": "^2.3.0", "regenerator-runtime": "^0.13.3", "regression": "2.0.1", "request": "^2.88.0", - "reselect": "^3.0.1", + "reselect": "^4.0.0", "resize-observer-polyfill": "^1.5.0", "rison-node": "1.0.2", "rxjs": "^6.5.3", @@ -294,8 +296,8 @@ "@kbn/eslint-import-resolver-kibana": "2.0.0", "@kbn/eslint-plugin-eslint": "1.0.0", "@kbn/expect": "1.0.0", - "@kbn/plugin-generator": "1.0.0", "@kbn/optimizer": "1.0.0", + "@kbn/plugin-generator": "1.0.0", "@kbn/test": "1.0.0", "@kbn/utility-types": "1.0.0", "@microsoft/api-documenter": "7.7.2", @@ -318,7 +320,7 @@ "@types/deep-freeze-strict": "^1.1.0", "@types/delete-empty": "^2.0.0", "@types/elasticsearch": "^5.0.33", - "@types/enzyme": "^3.9.0", + "@types/enzyme": "^3.10.5", "@types/eslint": "^6.1.3", "@types/fetch-mock": "^7.3.1", "@types/flot": "^0.0.31", @@ -356,16 +358,15 @@ "@types/podium": "^1.0.0", "@types/prop-types": "^15.5.3", "@types/reach__router": "^1.2.6", - "@types/react": "^16.9.11", - "@types/react-dom": "^16.9.4", + "@types/react": "^16.9.19", + "@types/react-dom": "^16.9.5", "@types/react-grid-layout": "^0.16.7", - "@types/react-redux": "^6.0.6", + "@types/react-redux": "^7.1.7", "@types/react-resize-detector": "^4.0.1", "@types/react-router": "^5.1.3", "@types/react-router-dom": "^5.1.3", "@types/react-virtualized": "^9.18.7", "@types/recompose": "^0.30.6", - "@types/redux": "^3.6.31", "@types/redux-actions": "^2.6.1", "@types/request": "^2.48.2", "@types/selenium-webdriver": "^4.0.5", @@ -394,14 +395,14 @@ "chai": "3.5.0", "chance": "1.0.18", "cheerio": "0.22.0", - "chromedriver": "79.0.0", + "chromedriver": "^80.0.1", "classnames": "2.2.6", "dedent": "^0.7.0", "delete-empty": "^2.0.0", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.15.1", - "enzyme-adapter-utils": "^1.12.1", - "enzyme-to-json": "^3.4.3", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.2", + "enzyme-adapter-utils": "^1.13.0", + "enzyme-to-json": "^3.4.4", "eslint": "^6.8.0", "eslint-config-prettier": "^6.9.0", "eslint-plugin-babel": "^5.3.0", diff --git a/packages/kbn-config-schema/src/types/duration_type.test.ts b/packages/kbn-config-schema/src/types/duration_type.test.ts index 09e92ce727f2a..57e917dc99b2b 100644 --- a/packages/kbn-config-schema/src/types/duration_type.test.ts +++ b/packages/kbn-config-schema/src/types/duration_type.test.ts @@ -101,7 +101,7 @@ describe('#defaultValue', () => { source: duration({ defaultValue: 600 }), target: duration({ defaultValue: siblingRef('source') }), fromContext: duration({ defaultValue: contextRef('val') }), - }).validate(undefined, { val: momentDuration(700, 'ms') }) + }).validate({}, { val: momentDuration(700, 'ms') }) ).toMatchInlineSnapshot(` Object { "fromContext": "PT0.7S", @@ -115,7 +115,7 @@ Object { source: duration({ defaultValue: '1h' }), target: duration({ defaultValue: siblingRef('source') }), fromContext: duration({ defaultValue: contextRef('val') }), - }).validate(undefined, { val: momentDuration(2, 'hour') }) + }).validate({}, { val: momentDuration(2, 'hour') }) ).toMatchInlineSnapshot(` Object { "fromContext": "PT2H", @@ -129,7 +129,7 @@ Object { source: duration({ defaultValue: momentDuration(1, 'hour') }), target: duration({ defaultValue: siblingRef('source') }), fromContext: duration({ defaultValue: contextRef('val') }), - }).validate(undefined, { val: momentDuration(2, 'hour') }) + }).validate({}, { val: momentDuration(2, 'hour') }) ).toMatchInlineSnapshot(` Object { "fromContext": "PT2H", diff --git a/packages/kbn-config-schema/src/types/maybe_type.test.ts b/packages/kbn-config-schema/src/types/maybe_type.test.ts index ecc1d218e186d..c35fa18593520 100644 --- a/packages/kbn-config-schema/src/types/maybe_type.test.ts +++ b/packages/kbn-config-schema/src/types/maybe_type.test.ts @@ -60,3 +60,41 @@ test('includes namespace in failure', () => { const type = schema.maybe(schema.string()); expect(() => type.validate(null, {}, 'foo-namespace')).toThrowErrorMatchingSnapshot(); }); + +describe('maybe + object', () => { + test('returns undefined if undefined object', () => { + const type = schema.maybe(schema.object({})); + expect(type.validate(undefined)).toEqual(undefined); + }); + + test('returns undefined if undefined object with no defaults', () => { + const type = schema.maybe( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ); + + expect(type.validate(undefined)).toEqual(undefined); + }); + + test('returns empty object if maybe keys', () => { + const type = schema.object({ + name: schema.maybe(schema.string()), + }); + expect(type.validate({})).toEqual({}); + }); + + test('returns empty object if maybe nested object', () => { + const type = schema.object({ + name: schema.maybe( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ), + }); + + expect(type.validate({})).toEqual({}); + }); +}); diff --git a/packages/kbn-config-schema/src/types/maybe_type.ts b/packages/kbn-config-schema/src/types/maybe_type.ts index 06a9369110203..415f6315c5723 100644 --- a/packages/kbn-config-schema/src/types/maybe_type.ts +++ b/packages/kbn-config-schema/src/types/maybe_type.ts @@ -25,7 +25,7 @@ export class MaybeType extends Type { type .getSchema() .optional() - .default() + .default(() => undefined, 'undefined') ); } } diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts index 5786984cf7ebd..64739d7a4c4da 100644 --- a/packages/kbn-config-schema/src/types/object_type.test.ts +++ b/packages/kbn-config-schema/src/types/object_type.test.ts @@ -30,6 +30,11 @@ test('returns value by default', () => { expect(type.validate(value)).toEqual({ name: 'test' }); }); +test('returns empty object if undefined', () => { + const type = schema.object({}); + expect(type.validate(undefined)).toEqual({}); +}); + test('properly parse the value if input is a string', () => { const type = schema.object({ name: schema.string(), @@ -112,14 +117,26 @@ test('undefined object within object', () => { }), }); + expect(type.validate(undefined)).toEqual({ + foo: { + bar: 'hello world', + }, + }); + expect(type.validate({})).toEqual({ foo: { bar: 'hello world', }, }); + + expect(type.validate({ foo: {} })).toEqual({ + foo: { + bar: 'hello world', + }, + }); }); -test('object within object with required', () => { +test('object within object with key without defaultValue', () => { const type = schema.object({ foo: schema.object({ bar: schema.string(), @@ -127,6 +144,9 @@ test('object within object with required', () => { }); const value = { foo: {} }; + expect(() => type.validate(undefined)).toThrowErrorMatchingInlineSnapshot( + `"[foo.bar]: expected value of type [string] but got [undefined]"` + ); expect(() => type.validate(value)).toThrowErrorMatchingInlineSnapshot( `"[foo.bar]: expected value of type [string] but got [undefined]"` ); diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index d2e6c708c263c..4f3d68a6bac97 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -33,23 +33,23 @@ export type ObjectResultType

= Readonly<{ [K in keyof P]: TypeO export type ObjectTypeOptions

= TypeOptions< { [K in keyof P]: TypeOf } > & { + /** Should uknown keys not be defined in the schema be allowed. Defaults to `false` */ allowUnknowns?: boolean; }; export class ObjectType

extends Type> { private props: Record; - constructor(props: P, options: ObjectTypeOptions

= {}) { + constructor(props: P, { allowUnknowns = false, ...typeOptions }: ObjectTypeOptions

= {}) { const schemaKeys = {} as Record; for (const [key, value] of Object.entries(props)) { schemaKeys[key] = value.getSchema(); } - const { allowUnknowns, ...typeOptions } = options; const schema = internals .object() .keys(schemaKeys) - .optional() .default() + .optional() .unknown(Boolean(allowUnknowns)); super(schema, typeOptions); diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts index 1114f65bacb19..f37bebb49efe9 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -24,9 +24,9 @@ type Operator = (source: Rx.Observable) => Rx.Observable; type MapFn = (item: T1, index: number) => T2; /** - * Wrap an operator chain in a closure so that is can have some local - * state. The `fn` is called each time the final observable is - * subscribed so the pipeline/closure is setup for each subscription. + * Wrap an operator chain in a closure so that it can have some local + * state. The `fn` is called each time the returned observable is + * subscribed; the closure is recreated for each subscription. */ export const pipeClosure = (fn: Operator): Operator => { return (source: Rx.Observable) => { diff --git a/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.test.ts b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.test.ts new file mode 100644 index 0000000000000..7a8575a6c91fe --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.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 * as Rx from 'rxjs'; +import { REPO_ROOT } from '@kbn/dev-utils'; + +import { Update } from '../common'; + +import { OptimizerState } from './optimizer_reducer'; +import { OptimizerConfig } from './optimizer_config'; +import { handleOptimizerCompletion } from './handle_optimizer_completion'; +import { toArray } from 'rxjs/operators'; + +const createUpdate$ = (phase: OptimizerState['phase']) => + Rx.of>({ + state: { + phase, + compilerStates: [], + durSec: 0, + offlineBundles: [], + onlineBundles: [], + startTime: Date.now(), + }, + }); + +const config = (watch?: boolean) => + OptimizerConfig.create({ + repoRoot: REPO_ROOT, + watch, + }); +const collect = (stream: Rx.Observable): Promise => stream.pipe(toArray()).toPromise(); + +it('errors if the optimizer completes when in watch mode', async () => { + const update$ = createUpdate$('success'); + + await expect( + collect(update$.pipe(handleOptimizerCompletion(config(true)))) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"optimizer unexpectedly completed when in watch mode"` + ); +}); + +it('errors if the optimizer completes in phase "issue"', async () => { + const update$ = createUpdate$('issue'); + + await expect( + collect(update$.pipe(handleOptimizerCompletion(config()))) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"webpack issue"`); +}); + +it('errors if the optimizer completes in phase "initializing"', async () => { + const update$ = createUpdate$('initializing'); + + await expect( + collect(update$.pipe(handleOptimizerCompletion(config()))) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"optimizer unexpectedly exit in phase \\"initializing\\""` + ); +}); + +it('errors if the optimizer completes in phase "reallocating"', async () => { + const update$ = createUpdate$('reallocating'); + + await expect( + collect(update$.pipe(handleOptimizerCompletion(config()))) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"optimizer unexpectedly exit in phase \\"reallocating\\""` + ); +}); + +it('errors if the optimizer completes in phase "running"', async () => { + const update$ = createUpdate$('running'); + + await expect( + collect(update$.pipe(handleOptimizerCompletion(config()))) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"optimizer unexpectedly exit in phase \\"running\\""` + ); +}); + +it('passes through errors on the source stream', async () => { + const error = new Error('foo'); + const update$ = Rx.throwError(error); + + await expect(collect(update$.pipe(handleOptimizerCompletion(config())))).rejects.toThrowError( + error + ); +}); diff --git a/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts new file mode 100644 index 0000000000000..fe2fa320818a2 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts @@ -0,0 +1,56 @@ +/* + * 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 { tap } from 'rxjs/operators'; +import { createFailError } from '@kbn/dev-utils'; + +import { pipeClosure, Update } from '../common'; + +import { OptimizerState } from './optimizer_reducer'; +import { OptimizerConfig } from './optimizer_config'; + +export function handleOptimizerCompletion(config: OptimizerConfig) { + return pipeClosure((source$: Rx.Observable>) => { + let prevState: OptimizerState | undefined; + + return source$.pipe( + tap({ + next: update => { + prevState = update.state; + }, + complete: () => { + if (config.watch) { + throw new Error('optimizer unexpectedly completed when in watch mode'); + } + + if (prevState?.phase === 'success') { + return; + } + + if (prevState?.phase === 'issue') { + throw createFailError('webpack issue'); + } + + throw new Error(`optimizer unexpectedly exit in phase "${prevState?.phase}"`); + }, + }) + ); + }); +} diff --git a/packages/kbn-optimizer/src/optimizer/index.ts b/packages/kbn-optimizer/src/optimizer/index.ts index b7f14cf3c517f..3df8ed9302668 100644 --- a/packages/kbn-optimizer/src/optimizer/index.ts +++ b/packages/kbn-optimizer/src/optimizer/index.ts @@ -24,3 +24,4 @@ export * from './cache_keys'; export * from './watch_bundles_for_changes'; export * from './run_workers'; export * from './bundle_cache'; +export * from './handle_optimizer_completion'; diff --git a/packages/kbn-optimizer/src/run_optimizer.ts b/packages/kbn-optimizer/src/run_optimizer.ts index e6cce8d306e35..d2daa79feab7e 100644 --- a/packages/kbn-optimizer/src/run_optimizer.ts +++ b/packages/kbn-optimizer/src/run_optimizer.ts @@ -32,6 +32,7 @@ import { runWorkers, OptimizerInitializedEvent, createOptimizerReducer, + handleOptimizerCompletion, } from './optimizer'; export type OptimizerUpdate = Update; @@ -77,6 +78,7 @@ export function runOptimizer(config: OptimizerConfig) { }, createOptimizerReducer(config) ); - }) + }), + handleOptimizerCompletion(config) ); } diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 314bcf31e6d05..2ccff3e9c3df2 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(705); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(704); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); @@ -105,10 +105,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(516); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Project", function() { return _utils_project__WEBPACK_IMPORTED_MODULE_3__["Project"]; }); -/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(579); +/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(578); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__["copyWorkspacePackages"]; }); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(580); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(579); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -152,7 +152,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(690); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(689); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -2506,9 +2506,9 @@ module.exports = require("path"); __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); -/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(687); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(688); +/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(586); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(686); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(687); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -2551,8 +2551,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34); /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(501); -/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(581); -/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(586); +/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(580); +/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(585); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -44027,7 +44027,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515); /* harmony import */ var _project__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(516); -/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(579); +/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(578); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -47547,7 +47547,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(515); /* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); /* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); -/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(564); +/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(563); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -48399,33 +48399,38 @@ function bugsTypos(bugs, warn) { /* 522 */ /***/ (function(module, exports) { -exports = module.exports = SemVer; - -// The debug function is excluded entirely from the minified version. -/* nomin */ var debug; -/* nomin */ if (typeof process === 'object' && - /* nomin */ process.env && - /* nomin */ process.env.NODE_DEBUG && - /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) - /* nomin */ debug = function() { - /* nomin */ var args = Array.prototype.slice.call(arguments, 0); - /* nomin */ args.unshift('SEMVER'); - /* nomin */ console.log.apply(console, args); - /* nomin */ }; -/* nomin */ else - /* nomin */ debug = function() {}; +exports = module.exports = SemVer + +var debug +/* istanbul ignore next */ +if (typeof process === 'object' && + process.env && + process.env.NODE_DEBUG && + /\bsemver\b/i.test(process.env.NODE_DEBUG)) { + debug = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift('SEMVER') + console.log.apply(console, args) + } +} else { + debug = function () {} +} // Note: this is the semver.org version of the spec that it implements // Not necessarily the package version of this code. -exports.SEMVER_SPEC_VERSION = '2.0.0'; +exports.SEMVER_SPEC_VERSION = '2.0.0' + +var MAX_LENGTH = 256 +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || + /* istanbul ignore next */ 9007199254740991 -var MAX_LENGTH = 256; -var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16 // The actual regexps go on exports.re -var re = exports.re = []; -var src = exports.src = []; -var R = 0; +var re = exports.re = [] +var src = exports.src = [] +var R = 0 // The following Regular Expressions can be used for tokenizing, // validating, and parsing SemVer version strings. @@ -48433,71 +48438,67 @@ var R = 0; // ## Numeric Identifier // A single `0`, or a non-zero digit followed by zero or more digits. -var NUMERICIDENTIFIER = R++; -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; -var NUMERICIDENTIFIERLOOSE = R++; -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; - +var NUMERICIDENTIFIER = R++ +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' +var NUMERICIDENTIFIERLOOSE = R++ +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. -var NONNUMERICIDENTIFIER = R++; -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; - +var NONNUMERICIDENTIFIER = R++ +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' // ## Main Version // Three dot-separated numeric identifiers. -var MAINVERSION = R++; +var MAINVERSION = R++ src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')'; + '(' + src[NUMERICIDENTIFIER] + ')' -var MAINVERSIONLOOSE = R++; +var MAINVERSIONLOOSE = R++ src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; + '(' + src[NUMERICIDENTIFIERLOOSE] + ')' // ## Pre-release Version Identifier // A numeric identifier, or a non-numeric identifier. -var PRERELEASEIDENTIFIER = R++; +var PRERELEASEIDENTIFIER = R++ src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; + '|' + src[NONNUMERICIDENTIFIER] + ')' -var PRERELEASEIDENTIFIERLOOSE = R++; +var PRERELEASEIDENTIFIERLOOSE = R++ src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - + '|' + src[NONNUMERICIDENTIFIER] + ')' // ## Pre-release Version // Hyphen, followed by one or more dot-separated pre-release version // identifiers. -var PRERELEASE = R++; +var PRERELEASE = R++ src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' -var PRERELEASELOOSE = R++; +var PRERELEASELOOSE = R++ src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. -var BUILDIDENTIFIER = R++; -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; +var BUILDIDENTIFIER = R++ +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata // identifiers. -var BUILD = R++; +var BUILD = R++ src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; - + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' // ## Full Version String // A main version, followed optionally by a pre-release version and @@ -48508,774 +48509,870 @@ src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + // capturing group, because it should not ever be used in version // comparison. -var FULL = R++; +var FULL = R++ var FULLPLAIN = 'v?' + src[MAINVERSION] + src[PRERELEASE] + '?' + - src[BUILD] + '?'; + src[BUILD] + '?' -src[FULL] = '^' + FULLPLAIN + '$'; +src[FULL] = '^' + FULLPLAIN + '$' // like full, but allows v1.2.3 and =1.2.3, which people do sometimes. // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty // common in the npm registry. var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?'; + src[BUILD] + '?' -var LOOSE = R++; -src[LOOSE] = '^' + LOOSEPLAIN + '$'; +var LOOSE = R++ +src[LOOSE] = '^' + LOOSEPLAIN + '$' -var GTLT = R++; -src[GTLT] = '((?:<|>)?=?)'; +var GTLT = R++ +src[GTLT] = '((?:<|>)?=?)' // Something like "2.*" or "1.2.x". // Note that "x.x" is a valid xRange identifer, meaning "any version" // Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++; -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; -var XRANGEIDENTIFIER = R++; -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; +var XRANGEIDENTIFIERLOOSE = R++ +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +var XRANGEIDENTIFIER = R++ +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' -var XRANGEPLAIN = R++; +var XRANGEPLAIN = R++ src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + '(?:' + src[PRERELEASE] + ')?' + src[BUILD] + '?' + - ')?)?'; + ')?)?' -var XRANGEPLAINLOOSE = R++; +var XRANGEPLAINLOOSE = R++ src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + '(?:' + src[PRERELEASELOOSE] + ')?' + src[BUILD] + '?' + - ')?)?'; + ')?)?' + +var XRANGE = R++ +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' +var XRANGELOOSE = R++ +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' -var XRANGE = R++; -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; -var XRANGELOOSE = R++; -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++ +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])' // Tilde ranges. // Meaning is "reasonably at or greater than" -var LONETILDE = R++; -src[LONETILDE] = '(?:~>?)'; +var LONETILDE = R++ +src[LONETILDE] = '(?:~>?)' -var TILDETRIM = R++; -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); -var tildeTrimReplace = '$1~'; +var TILDETRIM = R++ +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') +var tildeTrimReplace = '$1~' -var TILDE = R++; -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; -var TILDELOOSE = R++; -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; +var TILDE = R++ +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' +var TILDELOOSE = R++ +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' // Caret ranges. // Meaning is "at least and backwards compatible with" -var LONECARET = R++; -src[LONECARET] = '(?:\\^)'; +var LONECARET = R++ +src[LONECARET] = '(?:\\^)' -var CARETTRIM = R++; -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); -var caretTrimReplace = '$1^'; +var CARETTRIM = R++ +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') +var caretTrimReplace = '$1^' -var CARET = R++; -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; -var CARETLOOSE = R++; -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; +var CARET = R++ +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' +var CARETLOOSE = R++ +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' // A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++; -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; -var COMPARATOR = R++; -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; - +var COMPARATORLOOSE = R++ +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' +var COMPARATOR = R++ +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' // An expression to strip any whitespace between the gtlt and the thing // it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++; +var COMPARATORTRIM = R++ src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' // this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); -var comparatorTrimReplace = '$1$2$3'; - +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') +var comparatorTrimReplace = '$1$2$3' // Something like `1.2.3 - 1.2.4` // Note that these all use the loose form, because they'll be // checked against either the strict or loose comparator form // later. -var HYPHENRANGE = R++; +var HYPHENRANGE = R++ src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + '\\s+-\\s+' + '(' + src[XRANGEPLAIN] + ')' + - '\\s*$'; + '\\s*$' -var HYPHENRANGELOOSE = R++; +var HYPHENRANGELOOSE = R++ src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + '\\s+-\\s+' + '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$'; + '\\s*$' // Star ranges basically just allow anything at all. -var STAR = R++; -src[STAR] = '(<|>)?=?\\s*\\*'; +var STAR = R++ +src[STAR] = '(<|>)?=?\\s*\\*' // Compile to actual regexp objects. // All are flag-free, unless they were created above with a flag. for (var i = 0; i < R; i++) { - debug(i, src[i]); - if (!re[i]) - re[i] = new RegExp(src[i]); + debug(i, src[i]) + if (!re[i]) { + re[i] = new RegExp(src[i]) + } } -exports.parse = parse; -function parse(version, loose) { - if (version instanceof SemVer) - return version; +exports.parse = parse +function parse (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (version instanceof SemVer) { + return version + } - if (typeof version !== 'string') - return null; + if (typeof version !== 'string') { + return null + } - if (version.length > MAX_LENGTH) - return null; + if (version.length > MAX_LENGTH) { + return null + } - var r = loose ? re[LOOSE] : re[FULL]; - if (!r.test(version)) - return null; + var r = options.loose ? re[LOOSE] : re[FULL] + if (!r.test(version)) { + return null + } try { - return new SemVer(version, loose); + return new SemVer(version, options) } catch (er) { - return null; + return null } } -exports.valid = valid; -function valid(version, loose) { - var v = parse(version, loose); - return v ? v.version : null; +exports.valid = valid +function valid (version, options) { + var v = parse(version, options) + return v ? v.version : null } - -exports.clean = clean; -function clean(version, loose) { - var s = parse(version.trim().replace(/^[=v]+/, ''), loose); - return s ? s.version : null; +exports.clean = clean +function clean (version, options) { + var s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null } -exports.SemVer = SemVer; +exports.SemVer = SemVer -function SemVer(version, loose) { +function SemVer (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } if (version instanceof SemVer) { - if (version.loose === loose) - return version; - else - version = version.version; + if (version.loose === options.loose) { + return version + } else { + version = version.version + } } else if (typeof version !== 'string') { - throw new TypeError('Invalid Version: ' + version); + throw new TypeError('Invalid Version: ' + version) } - if (version.length > MAX_LENGTH) + if (version.length > MAX_LENGTH) { throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + } + + if (!(this instanceof SemVer)) { + return new SemVer(version, options) + } - if (!(this instanceof SemVer)) - return new SemVer(version, loose); + debug('SemVer', version, options) + this.options = options + this.loose = !!options.loose - debug('SemVer', version, loose); - this.loose = loose; - var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); + var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) - if (!m) - throw new TypeError('Invalid Version: ' + version); + if (!m) { + throw new TypeError('Invalid Version: ' + version) + } - this.raw = version; + this.raw = version // these are actually numbers - this.major = +m[1]; - this.minor = +m[2]; - this.patch = +m[3]; + this.major = +m[1] + this.minor = +m[2] + this.patch = +m[3] - if (this.major > MAX_SAFE_INTEGER || this.major < 0) + if (this.major > MAX_SAFE_INTEGER || this.major < 0) { throw new TypeError('Invalid major version') + } - if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { throw new TypeError('Invalid minor version') + } - if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { throw new TypeError('Invalid patch version') + } // numberify any prerelease numeric ids - if (!m[4]) - this.prerelease = []; - else - this.prerelease = m[4].split('.').map(function(id) { + if (!m[4]) { + this.prerelease = [] + } else { + this.prerelease = m[4].split('.').map(function (id) { if (/^[0-9]+$/.test(id)) { - var num = +id; - if (num >= 0 && num < MAX_SAFE_INTEGER) - return num; + var num = +id + if (num >= 0 && num < MAX_SAFE_INTEGER) { + return num + } } - return id; - }); + return id + }) + } - this.build = m[5] ? m[5].split('.') : []; - this.format(); + this.build = m[5] ? m[5].split('.') : [] + this.format() } -SemVer.prototype.format = function() { - this.version = this.major + '.' + this.minor + '.' + this.patch; - if (this.prerelease.length) - this.version += '-' + this.prerelease.join('.'); - return this.version; -}; +SemVer.prototype.format = function () { + this.version = this.major + '.' + this.minor + '.' + this.patch + if (this.prerelease.length) { + this.version += '-' + this.prerelease.join('.') + } + return this.version +} -SemVer.prototype.toString = function() { - return this.version; -}; +SemVer.prototype.toString = function () { + return this.version +} -SemVer.prototype.compare = function(other) { - debug('SemVer.compare', this.version, this.loose, other); - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); +SemVer.prototype.compare = function (other) { + debug('SemVer.compare', this.version, this.options, other) + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - return this.compareMain(other) || this.comparePre(other); -}; + return this.compareMain(other) || this.comparePre(other) +} -SemVer.prototype.compareMain = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); +SemVer.prototype.compareMain = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } return compareIdentifiers(this.major, other.major) || compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch); -}; + compareIdentifiers(this.patch, other.patch) +} -SemVer.prototype.comparePre = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); +SemVer.prototype.comparePre = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) - return -1; - else if (!this.prerelease.length && other.prerelease.length) - return 1; - else if (!this.prerelease.length && !other.prerelease.length) - return 0; + if (this.prerelease.length && !other.prerelease.length) { + return -1 + } else if (!this.prerelease.length && other.prerelease.length) { + return 1 + } else if (!this.prerelease.length && !other.prerelease.length) { + return 0 + } - var i = 0; + var i = 0 do { - var a = this.prerelease[i]; - var b = other.prerelease[i]; - debug('prerelease compare', i, a, b); - if (a === undefined && b === undefined) - return 0; - else if (b === undefined) - return 1; - else if (a === undefined) - return -1; - else if (a === b) - continue; - else - return compareIdentifiers(a, b); - } while (++i); -}; + var a = this.prerelease[i] + var b = other.prerelease[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} // preminor will bump the version up to the next minor release, and immediately // down to pre-release. premajor and prepatch work the same way. -SemVer.prototype.inc = function(release, identifier) { +SemVer.prototype.inc = function (release, identifier) { switch (release) { case 'premajor': - this.prerelease.length = 0; - this.patch = 0; - this.minor = 0; - this.major++; - this.inc('pre', identifier); - break; + this.prerelease.length = 0 + this.patch = 0 + this.minor = 0 + this.major++ + this.inc('pre', identifier) + break case 'preminor': - this.prerelease.length = 0; - this.patch = 0; - this.minor++; - this.inc('pre', identifier); - break; + this.prerelease.length = 0 + this.patch = 0 + this.minor++ + this.inc('pre', identifier) + break case 'prepatch': // If this is already a prerelease, it will bump to the next version // drop any prereleases that might already exist, since they are not // relevant at this point. - this.prerelease.length = 0; - this.inc('patch', identifier); - this.inc('pre', identifier); - break; + this.prerelease.length = 0 + this.inc('patch', identifier) + this.inc('pre', identifier) + break // If the input is a non-prerelease version, this acts the same as // prepatch. case 'prerelease': - if (this.prerelease.length === 0) - this.inc('patch', identifier); - this.inc('pre', identifier); - break; + if (this.prerelease.length === 0) { + this.inc('patch', identifier) + } + this.inc('pre', identifier) + break case 'major': // If this is a pre-major version, bump up to the same major version. // Otherwise increment major. // 1.0.0-5 bumps to 1.0.0 // 1.1.0 bumps to 2.0.0 - if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) - this.major++; - this.minor = 0; - this.patch = 0; - this.prerelease = []; - break; + if (this.minor !== 0 || + this.patch !== 0 || + this.prerelease.length === 0) { + this.major++ + } + this.minor = 0 + this.patch = 0 + this.prerelease = [] + break case 'minor': // If this is a pre-minor version, bump up to the same minor version. // Otherwise increment minor. // 1.2.0-5 bumps to 1.2.0 // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) - this.minor++; - this.patch = 0; - this.prerelease = []; - break; + if (this.patch !== 0 || this.prerelease.length === 0) { + this.minor++ + } + this.patch = 0 + this.prerelease = [] + break case 'patch': // If this is not a pre-release version, it will increment the patch. // If it is a pre-release it will bump up to the same patch version. // 1.2.0-5 patches to 1.2.0 // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) - this.patch++; - this.prerelease = []; - break; + if (this.prerelease.length === 0) { + this.patch++ + } + this.prerelease = [] + break // This probably shouldn't be used publicly. // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. case 'pre': - if (this.prerelease.length === 0) - this.prerelease = [0]; - else { - var i = this.prerelease.length; + if (this.prerelease.length === 0) { + this.prerelease = [0] + } else { + var i = this.prerelease.length while (--i >= 0) { if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++; - i = -2; + this.prerelease[i]++ + i = -2 } } - if (i === -1) // didn't increment anything - this.prerelease.push(0); + if (i === -1) { + // didn't increment anything + this.prerelease.push(0) + } } if (identifier) { // 1.2.0-beta.1 bumps to 1.2.0-beta.2, // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 if (this.prerelease[0] === identifier) { - if (isNaN(this.prerelease[1])) - this.prerelease = [identifier, 0]; - } else - this.prerelease = [identifier, 0]; + if (isNaN(this.prerelease[1])) { + this.prerelease = [identifier, 0] + } + } else { + this.prerelease = [identifier, 0] + } } - break; + break default: - throw new Error('invalid increment argument: ' + release); + throw new Error('invalid increment argument: ' + release) } - this.format(); - this.raw = this.version; - return this; -}; + this.format() + this.raw = this.version + return this +} -exports.inc = inc; -function inc(version, release, loose, identifier) { - if (typeof(loose) === 'string') { - identifier = loose; - loose = undefined; +exports.inc = inc +function inc (version, release, loose, identifier) { + if (typeof (loose) === 'string') { + identifier = loose + loose = undefined } try { - return new SemVer(version, loose).inc(release, identifier).version; + return new SemVer(version, loose).inc(release, identifier).version } catch (er) { - return null; + return null } } -exports.diff = diff; -function diff(version1, version2) { +exports.diff = diff +function diff (version1, version2) { if (eq(version1, version2)) { - return null; + return null } else { - var v1 = parse(version1); - var v2 = parse(version2); + var v1 = parse(version1) + var v2 = parse(version2) + var prefix = '' if (v1.prerelease.length || v2.prerelease.length) { - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return 'pre'+key; - } - } - } - return 'prerelease'; + prefix = 'pre' + var defaultResult = 'prerelease' } for (var key in v1) { if (key === 'major' || key === 'minor' || key === 'patch') { if (v1[key] !== v2[key]) { - return key; + return prefix + key } } } + return defaultResult // may be undefined } } -exports.compareIdentifiers = compareIdentifiers; +exports.compareIdentifiers = compareIdentifiers -var numeric = /^[0-9]+$/; -function compareIdentifiers(a, b) { - var anum = numeric.test(a); - var bnum = numeric.test(b); +var numeric = /^[0-9]+$/ +function compareIdentifiers (a, b) { + var anum = numeric.test(a) + var bnum = numeric.test(b) if (anum && bnum) { - a = +a; - b = +b; + a = +a + b = +b } - return (anum && !bnum) ? -1 : - (bnum && !anum) ? 1 : - a < b ? -1 : - a > b ? 1 : - 0; + return a === b ? 0 + : (anum && !bnum) ? -1 + : (bnum && !anum) ? 1 + : a < b ? -1 + : 1 } -exports.rcompareIdentifiers = rcompareIdentifiers; -function rcompareIdentifiers(a, b) { - return compareIdentifiers(b, a); +exports.rcompareIdentifiers = rcompareIdentifiers +function rcompareIdentifiers (a, b) { + return compareIdentifiers(b, a) } -exports.major = major; -function major(a, loose) { - return new SemVer(a, loose).major; +exports.major = major +function major (a, loose) { + return new SemVer(a, loose).major } -exports.minor = minor; -function minor(a, loose) { - return new SemVer(a, loose).minor; +exports.minor = minor +function minor (a, loose) { + return new SemVer(a, loose).minor } -exports.patch = patch; -function patch(a, loose) { - return new SemVer(a, loose).patch; +exports.patch = patch +function patch (a, loose) { + return new SemVer(a, loose).patch } -exports.compare = compare; -function compare(a, b, loose) { - return new SemVer(a, loose).compare(new SemVer(b, loose)); +exports.compare = compare +function compare (a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)) } -exports.compareLoose = compareLoose; -function compareLoose(a, b) { - return compare(a, b, true); +exports.compareLoose = compareLoose +function compareLoose (a, b) { + return compare(a, b, true) } -exports.rcompare = rcompare; -function rcompare(a, b, loose) { - return compare(b, a, loose); +exports.rcompare = rcompare +function rcompare (a, b, loose) { + return compare(b, a, loose) } -exports.sort = sort; -function sort(list, loose) { - return list.sort(function(a, b) { - return exports.compare(a, b, loose); - }); +exports.sort = sort +function sort (list, loose) { + return list.sort(function (a, b) { + return exports.compare(a, b, loose) + }) } -exports.rsort = rsort; -function rsort(list, loose) { - return list.sort(function(a, b) { - return exports.rcompare(a, b, loose); - }); +exports.rsort = rsort +function rsort (list, loose) { + return list.sort(function (a, b) { + return exports.rcompare(a, b, loose) + }) } -exports.gt = gt; -function gt(a, b, loose) { - return compare(a, b, loose) > 0; +exports.gt = gt +function gt (a, b, loose) { + return compare(a, b, loose) > 0 } -exports.lt = lt; -function lt(a, b, loose) { - return compare(a, b, loose) < 0; +exports.lt = lt +function lt (a, b, loose) { + return compare(a, b, loose) < 0 } -exports.eq = eq; -function eq(a, b, loose) { - return compare(a, b, loose) === 0; +exports.eq = eq +function eq (a, b, loose) { + return compare(a, b, loose) === 0 } -exports.neq = neq; -function neq(a, b, loose) { - return compare(a, b, loose) !== 0; +exports.neq = neq +function neq (a, b, loose) { + return compare(a, b, loose) !== 0 } -exports.gte = gte; -function gte(a, b, loose) { - return compare(a, b, loose) >= 0; +exports.gte = gte +function gte (a, b, loose) { + return compare(a, b, loose) >= 0 } -exports.lte = lte; -function lte(a, b, loose) { - return compare(a, b, loose) <= 0; +exports.lte = lte +function lte (a, b, loose) { + return compare(a, b, loose) <= 0 } -exports.cmp = cmp; -function cmp(a, op, b, loose) { - var ret; +exports.cmp = cmp +function cmp (a, op, b, loose) { switch (op) { case '===': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a === b; - break; - case '!==': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a !== b; - break; - case '': case '=': case '==': ret = eq(a, b, loose); break; - case '!=': ret = neq(a, b, loose); break; - case '>': ret = gt(a, b, loose); break; - case '>=': ret = gte(a, b, loose); break; - case '<': ret = lt(a, b, loose); break; - case '<=': ret = lte(a, b, loose); break; - default: throw new TypeError('Invalid operator: ' + op); - } - return ret; -} - -exports.Comparator = Comparator; -function Comparator(comp, loose) { - if (comp instanceof Comparator) { - if (comp.loose === loose) - return comp; - else - comp = comp.value; - } - - if (!(this instanceof Comparator)) - return new Comparator(comp, loose); + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a === b - debug('comparator', comp, loose); - this.loose = loose; - this.parse(comp); + case '!==': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a !== b - if (this.semver === ANY) - this.value = ''; - else - this.value = this.operator + this.semver.version; + case '': + case '=': + case '==': + return eq(a, b, loose) - debug('comp', this); -} + case '!=': + return neq(a, b, loose) -var ANY = {}; -Comparator.prototype.parse = function(comp) { - var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var m = comp.match(r); + case '>': + return gt(a, b, loose) - if (!m) - throw new TypeError('Invalid comparator: ' + comp); + case '>=': + return gte(a, b, loose) - this.operator = m[1]; - if (this.operator === '=') - this.operator = ''; + case '<': + return lt(a, b, loose) - // if it literally is just '>' or '' then allow anything. - if (!m[2]) - this.semver = ANY; - else - this.semver = new SemVer(m[2], this.loose); -}; + case '<=': + return lte(a, b, loose) -Comparator.prototype.toString = function() { - return this.value; -}; + default: + throw new TypeError('Invalid operator: ' + op) + } +} -Comparator.prototype.test = function(version) { - debug('Comparator.test', version, this.loose); +exports.Comparator = Comparator +function Comparator (comp, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } - if (this.semver === ANY) - return true; + if (comp instanceof Comparator) { + if (comp.loose === !!options.loose) { + return comp + } else { + comp = comp.value + } + } - if (typeof version === 'string') - version = new SemVer(version, this.loose); + if (!(this instanceof Comparator)) { + return new Comparator(comp, options) + } - return cmp(version, this.operator, this.semver, this.loose); -}; + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose + this.parse(comp) -Comparator.prototype.intersects = function(comp, loose) { - if (!(comp instanceof Comparator)) { - throw new TypeError('a Comparator is required'); + if (this.semver === ANY) { + this.value = '' + } else { + this.value = this.operator + this.semver.version } - var rangeTmp; - + debug('comp', this) +} + +var ANY = {} +Comparator.prototype.parse = function (comp) { + var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var m = comp.match(r) + + if (!m) { + throw new TypeError('Invalid comparator: ' + comp) + } + + this.operator = m[1] + if (this.operator === '=') { + this.operator = '' + } + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) { + this.semver = ANY + } else { + this.semver = new SemVer(m[2], this.options.loose) + } +} + +Comparator.prototype.toString = function () { + return this.value +} + +Comparator.prototype.test = function (version) { + debug('Comparator.test', version, this.options.loose) + + if (this.semver === ANY) { + return true + } + + if (typeof version === 'string') { + version = new SemVer(version, this.options) + } + + return cmp(version, this.operator, this.semver, this.options) +} + +Comparator.prototype.intersects = function (comp, options) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required') + } + + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + var rangeTmp + if (this.operator === '') { - rangeTmp = new Range(comp.value, loose); - return satisfies(this.value, rangeTmp, loose); + rangeTmp = new Range(comp.value, options) + return satisfies(this.value, rangeTmp, options) } else if (comp.operator === '') { - rangeTmp = new Range(this.value, loose); - return satisfies(comp.semver, rangeTmp, loose); + rangeTmp = new Range(this.value, options) + return satisfies(comp.semver, rangeTmp, options) } var sameDirectionIncreasing = (this.operator === '>=' || this.operator === '>') && - (comp.operator === '>=' || comp.operator === '>'); + (comp.operator === '>=' || comp.operator === '>') var sameDirectionDecreasing = (this.operator === '<=' || this.operator === '<') && - (comp.operator === '<=' || comp.operator === '<'); - var sameSemVer = this.semver.version === comp.semver.version; + (comp.operator === '<=' || comp.operator === '<') + var sameSemVer = this.semver.version === comp.semver.version var differentDirectionsInclusive = (this.operator === '>=' || this.operator === '<=') && - (comp.operator === '>=' || comp.operator === '<='); + (comp.operator === '>=' || comp.operator === '<=') var oppositeDirectionsLessThan = - cmp(this.semver, '<', comp.semver, loose) && + cmp(this.semver, '<', comp.semver, options) && ((this.operator === '>=' || this.operator === '>') && - (comp.operator === '<=' || comp.operator === '<')); + (comp.operator === '<=' || comp.operator === '<')) var oppositeDirectionsGreaterThan = - cmp(this.semver, '>', comp.semver, loose) && + cmp(this.semver, '>', comp.semver, options) && ((this.operator === '<=' || this.operator === '<') && - (comp.operator === '>=' || comp.operator === '>')); + (comp.operator === '>=' || comp.operator === '>')) return sameDirectionIncreasing || sameDirectionDecreasing || (sameSemVer && differentDirectionsInclusive) || - oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; -}; + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan +} +exports.Range = Range +function Range (range, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } -exports.Range = Range; -function Range(range, loose) { if (range instanceof Range) { - if (range.loose === loose) { - return range; + if (range.loose === !!options.loose && + range.includePrerelease === !!options.includePrerelease) { + return range } else { - return new Range(range.raw, loose); + return new Range(range.raw, options) } } if (range instanceof Comparator) { - return new Range(range.value, loose); + return new Range(range.value, options) } - if (!(this instanceof Range)) - return new Range(range, loose); + if (!(this instanceof Range)) { + return new Range(range, options) + } - this.loose = loose; + this.options = options + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease // First, split based on boolean or || - this.raw = range; - this.set = range.split(/\s*\|\|\s*/).map(function(range) { - return this.parseRange(range.trim()); - }, this).filter(function(c) { + this.raw = range + this.set = range.split(/\s*\|\|\s*/).map(function (range) { + return this.parseRange(range.trim()) + }, this).filter(function (c) { // throw out any that are not relevant for whatever reason - return c.length; - }); + return c.length + }) if (!this.set.length) { - throw new TypeError('Invalid SemVer Range: ' + range); + throw new TypeError('Invalid SemVer Range: ' + range) } - this.format(); + this.format() } -Range.prototype.format = function() { - this.range = this.set.map(function(comps) { - return comps.join(' ').trim(); - }).join('||').trim(); - return this.range; -}; +Range.prototype.format = function () { + this.range = this.set.map(function (comps) { + return comps.join(' ').trim() + }).join('||').trim() + return this.range +} -Range.prototype.toString = function() { - return this.range; -}; +Range.prototype.toString = function () { + return this.range +} -Range.prototype.parseRange = function(range) { - var loose = this.loose; - range = range.trim(); - debug('range', range, loose); +Range.prototype.parseRange = function (range) { + var loose = this.options.loose + range = range.trim() // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; - range = range.replace(hr, hyphenReplace); - debug('hyphen replace', range); + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] + range = range.replace(hr, hyphenReplace) + debug('hyphen replace', range) // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); - debug('comparator trim', range, re[COMPARATORTRIM]); + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, re[COMPARATORTRIM]) // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace); + range = range.replace(re[TILDETRIM], tildeTrimReplace) // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace); + range = range.replace(re[CARETTRIM], caretTrimReplace) // normalize spaces - range = range.split(/\s+/).join(' '); + range = range.split(/\s+/).join(' ') // At this point, the range is completely trimmed and // ready to be split into comparators. - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var set = range.split(' ').map(function(comp) { - return parseComparator(comp, loose); - }).join(' ').split(/\s+/); - if (this.loose) { + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var set = range.split(' ').map(function (comp) { + return parseComparator(comp, this.options) + }, this).join(' ').split(/\s+/) + if (this.options.loose) { // in loose mode, throw out any that are not valid comparators - set = set.filter(function(comp) { - return !!comp.match(compRe); - }); + set = set.filter(function (comp) { + return !!comp.match(compRe) + }) } - set = set.map(function(comp) { - return new Comparator(comp, loose); - }); + set = set.map(function (comp) { + return new Comparator(comp, this.options) + }, this) - return set; -}; + return set +} -Range.prototype.intersects = function(range, loose) { +Range.prototype.intersects = function (range, options) { if (!(range instanceof Range)) { - throw new TypeError('a Range is required'); + throw new TypeError('a Range is required') } - return this.set.some(function(thisComparators) { - return thisComparators.every(function(thisComparator) { - return range.set.some(function(rangeComparators) { - return rangeComparators.every(function(rangeComparator) { - return thisComparator.intersects(rangeComparator, loose); - }); - }); - }); - }); -}; + return this.set.some(function (thisComparators) { + return thisComparators.every(function (thisComparator) { + return range.set.some(function (rangeComparators) { + return rangeComparators.every(function (rangeComparator) { + return thisComparator.intersects(rangeComparator, options) + }) + }) + }) + }) +} // Mostly just for testing and legacy API reasons -exports.toComparators = toComparators; -function toComparators(range, loose) { - return new Range(range, loose).set.map(function(comp) { - return comp.map(function(c) { - return c.value; - }).join(' ').trim().split(' '); - }); +exports.toComparators = toComparators +function toComparators (range, options) { + return new Range(range, options).set.map(function (comp) { + return comp.map(function (c) { + return c.value + }).join(' ').trim().split(' ') + }) } // comprised of xranges, tildes, stars, and gtlt's at this point. // already replaced the hyphen ranges // turn into a set of JUST comparators. -function parseComparator(comp, loose) { - debug('comp', comp); - comp = replaceCarets(comp, loose); - debug('caret', comp); - comp = replaceTildes(comp, loose); - debug('tildes', comp); - comp = replaceXRanges(comp, loose); - debug('xrange', comp); - comp = replaceStars(comp, loose); - debug('stars', comp); - return comp; +function parseComparator (comp, options) { + debug('comp', comp, options) + comp = replaceCarets(comp, options) + debug('caret', comp) + comp = replaceTildes(comp, options) + debug('tildes', comp) + comp = replaceXRanges(comp, options) + debug('xrange', comp) + comp = replaceStars(comp, options) + debug('stars', comp) + return comp } -function isX(id) { - return !id || id.toLowerCase() === 'x' || id === '*'; +function isX (id) { + return !id || id.toLowerCase() === 'x' || id === '*' } // ~, ~> --> * (any, kinda silly) @@ -49284,39 +49381,38 @@ function isX(id) { // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 -function replaceTildes(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceTilde(comp, loose); - }).join(' '); -} - -function replaceTilde(comp, loose) { - var r = loose ? re[TILDELOOSE] : re[TILDE]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('tilde', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) +function replaceTildes (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceTilde(comp, options) + }).join(' ') +} + +function replaceTilde (comp, options) { + var r = options.loose ? re[TILDELOOSE] : re[TILDE] + return comp.replace(r, function (_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { // ~1.2 == >=1.2.0 <1.3.0 - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else if (pr) { - debug('replaceTilde pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else if (pr) { + debug('replaceTilde pr', pr) + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } else { // ~1.2.3 == >=1.2.3 <1.3.0 ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; + ' <' + M + '.' + (+m + 1) + '.0' + } - debug('tilde return', ret); - return ret; - }); + debug('tilde return', ret) + return ret + }) } // ^ --> * (any, kinda silly) @@ -49325,138 +49421,144 @@ function replaceTilde(comp, loose) { // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 // ^1.2.3 --> >=1.2.3 <2.0.0 // ^1.2.0 --> >=1.2.0 <2.0.0 -function replaceCarets(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceCaret(comp, loose); - }).join(' '); -} - -function replaceCaret(comp, loose) { - debug('caret', comp, loose); - var r = loose ? re[CARETLOOSE] : re[CARET]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('caret', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) { - if (M === '0') - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else - ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; +function replaceCarets (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceCaret(comp, options) + }).join(' ') +} + +function replaceCaret (comp, options) { + debug('caret', comp, options) + var r = options.loose ? re[CARETLOOSE] : re[CARET] + return comp.replace(r, function (_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + if (M === '0') { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else { + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' + } } else if (pr) { - debug('replaceCaret pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; + debug('replaceCaret pr', pr) if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + (+M + 1) + '.0.0'; + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + (+M + 1) + '.0.0' + } } else { - debug('no pr'); + debug('no pr') if (M === '0') { - if (m === '0') + if (m === '0') { ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + m + '.' + (+p + 1); - else + ' <' + M + '.' + m + '.' + (+p + 1) + } else { ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - } else + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { ret = '>=' + M + '.' + m + '.' + p + - ' <' + (+M + 1) + '.0.0'; + ' <' + (+M + 1) + '.0.0' + } } - debug('caret return', ret); - return ret; - }); + debug('caret return', ret) + return ret + }) } -function replaceXRanges(comp, loose) { - debug('replaceXRanges', comp, loose); - return comp.split(/\s+/).map(function(comp) { - return replaceXRange(comp, loose); - }).join(' '); +function replaceXRanges (comp, options) { + debug('replaceXRanges', comp, options) + return comp.split(/\s+/).map(function (comp) { + return replaceXRange(comp, options) + }).join(' ') } -function replaceXRange(comp, loose) { - comp = comp.trim(); - var r = loose ? re[XRANGELOOSE] : re[XRANGE]; - return comp.replace(r, function(ret, gtlt, M, m, p, pr) { - debug('xRange', comp, ret, gtlt, M, m, p, pr); - var xM = isX(M); - var xm = xM || isX(m); - var xp = xm || isX(p); - var anyX = xp; +function replaceXRange (comp, options) { + comp = comp.trim() + var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] + return comp.replace(r, function (ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr) + var xM = isX(M) + var xm = xM || isX(m) + var xp = xm || isX(p) + var anyX = xp - if (gtlt === '=' && anyX) - gtlt = ''; + if (gtlt === '=' && anyX) { + gtlt = '' + } if (xM) { if (gtlt === '>' || gtlt === '<') { // nothing is allowed - ret = '<0.0.0'; + ret = '<0.0.0' } else { // nothing is forbidden - ret = '*'; + ret = '*' } } else if (gtlt && anyX) { + // we know patch is an x, because we have any x at all. // replace X with 0 - if (xm) - m = 0; - if (xp) - p = 0; + if (xm) { + m = 0 + } + p = 0 if (gtlt === '>') { // >1 => >=2.0.0 // >1.2 => >=1.3.0 // >1.2.3 => >= 1.2.4 - gtlt = '>='; + gtlt = '>=' if (xm) { - M = +M + 1; - m = 0; - p = 0; - } else if (xp) { - m = +m + 1; - p = 0; + M = +M + 1 + m = 0 + p = 0 + } else { + m = +m + 1 + p = 0 } } else if (gtlt === '<=') { // <=0.7.x is actually <0.8.0, since any 0.7.x should // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<'; - if (xm) - M = +M + 1; - else - m = +m + 1; + gtlt = '<' + if (xm) { + M = +M + 1 + } else { + m = +m + 1 + } } - ret = gtlt + M + '.' + m + '.' + p; + ret = gtlt + M + '.' + m + '.' + p } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' } - debug('xRange return', ret); + debug('xRange return', ret) - return ret; - }); + return ret + }) } // Because * is AND-ed with everything else in the comparator, // and '' means "any version", just remove the *s entirely. -function replaceStars(comp, loose) { - debug('replaceStars', comp, loose); +function replaceStars (comp, options) { + debug('replaceStars', comp, options) // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], ''); + return comp.trim().replace(re[STAR], '') } // This function is passed to string.replace(re[HYPHENRANGE]) @@ -49464,238 +49566,323 @@ function replaceStars(comp, loose) { // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 // 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do // 1.2 - 3.4 => >=1.2.0 <3.5.0 -function hyphenReplace($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr, tb) { - - if (isX(fM)) - from = ''; - else if (isX(fm)) - from = '>=' + fM + '.0.0'; - else if (isX(fp)) - from = '>=' + fM + '.' + fm + '.0'; - else - from = '>=' + from; - - if (isX(tM)) - to = ''; - else if (isX(tm)) - to = '<' + (+tM + 1) + '.0.0'; - else if (isX(tp)) - to = '<' + tM + '.' + (+tm + 1) + '.0'; - else if (tpr) - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; - else - to = '<=' + to; +function hyphenReplace ($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + if (isX(fM)) { + from = '' + } else if (isX(fm)) { + from = '>=' + fM + '.0.0' + } else if (isX(fp)) { + from = '>=' + fM + '.' + fm + '.0' + } else { + from = '>=' + from + } - return (from + ' ' + to).trim(); -} + if (isX(tM)) { + to = '' + } else if (isX(tm)) { + to = '<' + (+tM + 1) + '.0.0' + } else if (isX(tp)) { + to = '<' + tM + '.' + (+tm + 1) + '.0' + } else if (tpr) { + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + } else { + to = '<=' + to + } + return (from + ' ' + to).trim() +} // if ANY of the sets match ALL of its comparators, then pass -Range.prototype.test = function(version) { - if (!version) - return false; +Range.prototype.test = function (version) { + if (!version) { + return false + } - if (typeof version === 'string') - version = new SemVer(version, this.loose); + if (typeof version === 'string') { + version = new SemVer(version, this.options) + } for (var i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version)) - return true; + if (testSet(this.set[i], version, this.options)) { + return true + } } - return false; -}; + return false +} -function testSet(set, version) { +function testSet (set, version, options) { for (var i = 0; i < set.length; i++) { - if (!set[i].test(version)) - return false; + if (!set[i].test(version)) { + return false + } } - if (version.prerelease.length) { + if (version.prerelease.length && !options.includePrerelease) { // Find the set of versions that are allowed to have prereleases // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 // That should allow `1.2.3-pr.2` to pass. // However, `1.2.4-alpha.notready` should NOT be allowed, // even though it's within the range set by the comparators. - for (var i = 0; i < set.length; i++) { - debug(set[i].semver); - if (set[i].semver === ANY) - continue; + for (i = 0; i < set.length; i++) { + debug(set[i].semver) + if (set[i].semver === ANY) { + continue + } if (set[i].semver.prerelease.length > 0) { - var allowed = set[i].semver; + var allowed = set[i].semver if (allowed.major === version.major && allowed.minor === version.minor && - allowed.patch === version.patch) - return true; + allowed.patch === version.patch) { + return true + } } } // Version has a -pre, but it's not one of the ones we like. - return false; + return false } - return true; + return true } -exports.satisfies = satisfies; -function satisfies(version, range, loose) { +exports.satisfies = satisfies +function satisfies (version, range, options) { try { - range = new Range(range, loose); + range = new Range(range, options) } catch (er) { - return false; + return false } - return range.test(version); + return range.test(version) } -exports.maxSatisfying = maxSatisfying; -function maxSatisfying(versions, range, loose) { - var max = null; - var maxSV = null; +exports.maxSatisfying = maxSatisfying +function maxSatisfying (versions, range, options) { + var max = null + var maxSV = null try { - var rangeObj = new Range(range, loose); + var rangeObj = new Range(range, options) } catch (er) { - return null; + return null } versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) - max = v; - maxSV = new SemVer(max, loose); + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) } } }) - return max; + return max } -exports.minSatisfying = minSatisfying; -function minSatisfying(versions, range, loose) { - var min = null; - var minSV = null; +exports.minSatisfying = minSatisfying +function minSatisfying (versions, range, options) { + var min = null + var minSV = null try { - var rangeObj = new Range(range, loose); + var rangeObj = new Range(range, options) } catch (er) { - return null; + return null } versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!min || minSV.compare(v) === 1) { // compare(min, v, true) - min = v; - minSV = new SemVer(min, loose); + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) } } }) - return min; + return min +} + +exports.minVersion = minVersion +function minVersion (range, loose) { + range = new Range(range, loose) + + var minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver + } + + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver + } + + minver = null + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] + + comparators.forEach(function (comparator) { + // Clone to avoid manipulating the comparator's semver object. + var compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!minver || gt(minver, compver)) { + minver = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error('Unexpected operation: ' + comparator.operator) + } + }) + } + + if (minver && range.test(minver)) { + return minver + } + + return null } -exports.validRange = validRange; -function validRange(range, loose) { +exports.validRange = validRange +function validRange (range, options) { try { // Return '*' instead of '' so that truthiness works. // This will throw if it's invalid anyway - return new Range(range, loose).range || '*'; + return new Range(range, options).range || '*' } catch (er) { - return null; + return null } } // Determine if version is less than all the versions possible in the range -exports.ltr = ltr; -function ltr(version, range, loose) { - return outside(version, range, '<', loose); +exports.ltr = ltr +function ltr (version, range, options) { + return outside(version, range, '<', options) } // Determine if version is greater than all the versions possible in the range. -exports.gtr = gtr; -function gtr(version, range, loose) { - return outside(version, range, '>', loose); +exports.gtr = gtr +function gtr (version, range, options) { + return outside(version, range, '>', options) } -exports.outside = outside; -function outside(version, range, hilo, loose) { - version = new SemVer(version, loose); - range = new Range(range, loose); +exports.outside = outside +function outside (version, range, hilo, options) { + version = new SemVer(version, options) + range = new Range(range, options) - var gtfn, ltefn, ltfn, comp, ecomp; + var gtfn, ltefn, ltfn, comp, ecomp switch (hilo) { case '>': - gtfn = gt; - ltefn = lte; - ltfn = lt; - comp = '>'; - ecomp = '>='; - break; + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break case '<': - gtfn = lt; - ltefn = gte; - ltfn = gt; - comp = '<'; - ecomp = '<='; - break; + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break default: - throw new TypeError('Must provide a hilo val of "<" or ">"'); + throw new TypeError('Must provide a hilo val of "<" or ">"') } // If it satisifes the range it is not outside - if (satisfies(version, range, loose)) { - return false; + if (satisfies(version, range, options)) { + return false } // From now on, variable terms are as if we're in "gtr" mode. // but note that everything is flipped for the "ltr" function. for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i]; + var comparators = range.set[i] - var high = null; - var low = null; + var high = null + var low = null - comparators.forEach(function(comparator) { + comparators.forEach(function (comparator) { if (comparator.semver === ANY) { comparator = new Comparator('>=0.0.0') } - high = high || comparator; - low = low || comparator; - if (gtfn(comparator.semver, high.semver, loose)) { - high = comparator; - } else if (ltfn(comparator.semver, low.semver, loose)) { - low = comparator; + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator } - }); + }) // If the edge version comparator has a operator then our version // isn't outside it if (high.operator === comp || high.operator === ecomp) { - return false; + return false } // If the lowest version comparator has an operator and our version // is less than it then it isn't higher than the range if ((!low.operator || low.operator === comp) && ltefn(version, low.semver)) { - return false; + return false } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false; + return false } } - return true; + return true } -exports.prerelease = prerelease; -function prerelease(version, loose) { - var parsed = parse(version, loose); - return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; +exports.prerelease = prerelease +function prerelease (version, options) { + var parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null } -exports.intersects = intersects; -function intersects(r1, r2, loose) { - r1 = new Range(r1, loose) - r2 = new Range(r2, loose) +exports.intersects = intersects +function intersects (r1, r2, options) { + r1 = new Range(r1, options) + r2 = new Range(r2, options) return r1.intersects(r2) } +exports.coerce = coerce +function coerce (version) { + if (version instanceof SemVer) { + return version + } + + if (typeof version !== 'string') { + return null + } + + var match = version.match(re[COERCE]) + + if (match == null) { + return null + } + + return parse(match[1] + + '.' + (match[2] || '0') + + '.' + (match[3] || '0')) +} + /***/ }), /* 523 */ @@ -52531,8 +52718,8 @@ const fs = __webpack_require__(546); const writeFileAtomic = __webpack_require__(550); const sortKeys = __webpack_require__(557); const makeDir = __webpack_require__(559); -const pify = __webpack_require__(562); -const detectIndent = __webpack_require__(563); +const pify = __webpack_require__(561); +const detectIndent = __webpack_require__(562); const init = (fn, filePath, data, options) => { if (!filePath) { @@ -54607,7 +54794,7 @@ module.exports = function (x) { const fs = __webpack_require__(23); const path = __webpack_require__(16); const pify = __webpack_require__(560); -const semver = __webpack_require__(561); +const semver = __webpack_require__(522); const defaults = { mode: 0o777 & (~process.umask()), @@ -54669,1647 +54856,158 @@ const makeDir = (input, options) => Promise.resolve().then(() => { if (error.code === 'ENOENT') { if (path.dirname(pth) === pth) { throw permissionError(pth); - } - - if (error.message.includes('null bytes')) { - throw error; - } - - return make(path.dirname(pth)).then(() => make(pth)); - } - - return stat(pth) - .then(stats => stats.isDirectory() ? pth : Promise.reject()) - .catch(() => { - throw error; - }); - }); - }; - - return make(path.resolve(input)); -}); - -module.exports = makeDir; -module.exports.default = makeDir; - -module.exports.sync = (input, options) => { - checkPath(input); - options = Object.assign({}, defaults, options); - - if (useNativeRecursiveOption && options.fs.mkdirSync === fs.mkdirSync) { - const pth = path.resolve(input); - - fs.mkdirSync(pth, { - mode: options.mode, - recursive: true - }); - - return pth; - } - - const make = pth => { - try { - options.fs.mkdirSync(pth, options.mode); - } catch (error) { - if (error.code === 'EPERM') { - throw error; - } - - if (error.code === 'ENOENT') { - if (path.dirname(pth) === pth) { - throw permissionError(pth); - } - - if (error.message.includes('null bytes')) { - throw error; - } - - make(path.dirname(pth)); - return make(pth); - } - - try { - if (!options.fs.statSync(pth).isDirectory()) { - throw new Error('The path is not a directory'); - } - } catch (_) { - throw error; - } - } - - return pth; - }; - - return make(path.resolve(input)); -}; - - -/***/ }), -/* 560 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, options) => function (...args) { - const P = options.promiseModule; - - return new P((resolve, reject) => { - if (options.multiArgs) { - args.push((...result) => { - if (options.errorFirst) { - if (result[0]) { - reject(result); - } else { - result.shift(); - resolve(result); - } - } else { - resolve(result); - } - }); - } else if (options.errorFirst) { - args.push((error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - } else { - args.push(resolve); - } - - fn.apply(this, args); - }); -}; - -module.exports = (input, options) => { - options = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, options); - - const objType = typeof input; - if (!(input !== null && (objType === 'object' || objType === 'function'))) { - throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); - } - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return options.include ? options.include.some(match) : !options.exclude.some(match); - }; - - let ret; - if (objType === 'function') { - ret = function (...args) { - return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); - }; - } else { - ret = Object.create(Object.getPrototypeOf(input)); - } - - for (const key in input) { // eslint-disable-line guard-for-in - const property = input[key]; - ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; - } - - return ret; -}; - - -/***/ }), -/* 561 */ -/***/ (function(module, exports) { - -exports = module.exports = SemVer - -var debug -/* istanbul ignore next */ -if (typeof process === 'object' && - process.env && - process.env.NODE_DEBUG && - /\bsemver\b/i.test(process.env.NODE_DEBUG)) { - debug = function () { - var args = Array.prototype.slice.call(arguments, 0) - args.unshift('SEMVER') - console.log.apply(console, args) - } -} else { - debug = function () {} -} - -// Note: this is the semver.org version of the spec that it implements -// Not necessarily the package version of this code. -exports.SEMVER_SPEC_VERSION = '2.0.0' - -var MAX_LENGTH = 256 -var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || - /* istanbul ignore next */ 9007199254740991 - -// Max safe segment length for coercion. -var MAX_SAFE_COMPONENT_LENGTH = 16 - -// The actual regexps go on exports.re -var re = exports.re = [] -var src = exports.src = [] -var R = 0 - -// The following Regular Expressions can be used for tokenizing, -// validating, and parsing SemVer version strings. - -// ## Numeric Identifier -// A single `0`, or a non-zero digit followed by zero or more digits. - -var NUMERICIDENTIFIER = R++ -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' -var NUMERICIDENTIFIERLOOSE = R++ -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' - -// ## Non-numeric Identifier -// Zero or more digits, followed by a letter or hyphen, and then zero or -// more letters, digits, or hyphens. - -var NONNUMERICIDENTIFIER = R++ -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' - -// ## Main Version -// Three dot-separated numeric identifiers. - -var MAINVERSION = R++ -src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')' - -var MAINVERSIONLOOSE = R++ -src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')' - -// ## Pre-release Version Identifier -// A numeric identifier, or a non-numeric identifier. - -var PRERELEASEIDENTIFIER = R++ -src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')' - -var PRERELEASEIDENTIFIERLOOSE = R++ -src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')' - -// ## Pre-release Version -// Hyphen, followed by one or more dot-separated pre-release version -// identifiers. - -var PRERELEASE = R++ -src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' - -var PRERELEASELOOSE = R++ -src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' - -// ## Build Metadata Identifier -// Any combination of digits, letters, or hyphens. - -var BUILDIDENTIFIER = R++ -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' - -// ## Build Metadata -// Plus sign, followed by one or more period-separated build metadata -// identifiers. - -var BUILD = R++ -src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' - -// ## Full Version String -// A main version, followed optionally by a pre-release version and -// build metadata. - -// Note that the only major, minor, patch, and pre-release sections of -// the version string are capturing groups. The build metadata is not a -// capturing group, because it should not ever be used in version -// comparison. - -var FULL = R++ -var FULLPLAIN = 'v?' + src[MAINVERSION] + - src[PRERELEASE] + '?' + - src[BUILD] + '?' - -src[FULL] = '^' + FULLPLAIN + '$' - -// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. -// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty -// common in the npm registry. -var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?' - -var LOOSE = R++ -src[LOOSE] = '^' + LOOSEPLAIN + '$' - -var GTLT = R++ -src[GTLT] = '((?:<|>)?=?)' - -// Something like "2.*" or "1.2.x". -// Note that "x.x" is a valid xRange identifer, meaning "any version" -// Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++ -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' -var XRANGEIDENTIFIER = R++ -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' - -var XRANGEPLAIN = R++ -src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + - ')?)?' - -var XRANGEPLAINLOOSE = R++ -src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + - ')?)?' - -var XRANGE = R++ -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' -var XRANGELOOSE = R++ -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' - -// Coercion. -// Extract anything that could conceivably be a part of a valid semver -var COERCE = R++ -src[COERCE] = '(?:^|[^\\d])' + - '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:$|[^\\d])' - -// Tilde ranges. -// Meaning is "reasonably at or greater than" -var LONETILDE = R++ -src[LONETILDE] = '(?:~>?)' - -var TILDETRIM = R++ -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') -var tildeTrimReplace = '$1~' - -var TILDE = R++ -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' -var TILDELOOSE = R++ -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' - -// Caret ranges. -// Meaning is "at least and backwards compatible with" -var LONECARET = R++ -src[LONECARET] = '(?:\\^)' - -var CARETTRIM = R++ -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') -var caretTrimReplace = '$1^' - -var CARET = R++ -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' -var CARETLOOSE = R++ -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' - -// A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++ -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' -var COMPARATOR = R++ -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' - -// An expression to strip any whitespace between the gtlt and the thing -// it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++ -src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' - -// this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') -var comparatorTrimReplace = '$1$2$3' - -// Something like `1.2.3 - 1.2.4` -// Note that these all use the loose form, because they'll be -// checked against either the strict or loose comparator form -// later. -var HYPHENRANGE = R++ -src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + - '\\s*$' - -var HYPHENRANGELOOSE = R++ -src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$' - -// Star ranges basically just allow anything at all. -var STAR = R++ -src[STAR] = '(<|>)?=?\\s*\\*' - -// Compile to actual regexp objects. -// All are flag-free, unless they were created above with a flag. -for (var i = 0; i < R; i++) { - debug(i, src[i]) - if (!re[i]) { - re[i] = new RegExp(src[i]) - } -} - -exports.parse = parse -function parse (version, options) { - if (!options || typeof options !== 'object') { - options = { - loose: !!options, - includePrerelease: false - } - } - - if (version instanceof SemVer) { - return version - } - - if (typeof version !== 'string') { - return null - } - - if (version.length > MAX_LENGTH) { - return null - } - - var r = options.loose ? re[LOOSE] : re[FULL] - if (!r.test(version)) { - return null - } - - try { - return new SemVer(version, options) - } catch (er) { - return null - } -} - -exports.valid = valid -function valid (version, options) { - var v = parse(version, options) - return v ? v.version : null -} - -exports.clean = clean -function clean (version, options) { - var s = parse(version.trim().replace(/^[=v]+/, ''), options) - return s ? s.version : null -} - -exports.SemVer = SemVer - -function SemVer (version, options) { - if (!options || typeof options !== 'object') { - options = { - loose: !!options, - includePrerelease: false - } - } - if (version instanceof SemVer) { - if (version.loose === options.loose) { - return version - } else { - version = version.version - } - } else if (typeof version !== 'string') { - throw new TypeError('Invalid Version: ' + version) - } - - if (version.length > MAX_LENGTH) { - throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') - } - - if (!(this instanceof SemVer)) { - return new SemVer(version, options) - } - - debug('SemVer', version, options) - this.options = options - this.loose = !!options.loose - - var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) - - if (!m) { - throw new TypeError('Invalid Version: ' + version) - } - - this.raw = version - - // these are actually numbers - this.major = +m[1] - this.minor = +m[2] - this.patch = +m[3] - - if (this.major > MAX_SAFE_INTEGER || this.major < 0) { - throw new TypeError('Invalid major version') - } - - if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { - throw new TypeError('Invalid minor version') - } - - if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { - throw new TypeError('Invalid patch version') - } - - // numberify any prerelease numeric ids - if (!m[4]) { - this.prerelease = [] - } else { - this.prerelease = m[4].split('.').map(function (id) { - if (/^[0-9]+$/.test(id)) { - var num = +id - if (num >= 0 && num < MAX_SAFE_INTEGER) { - return num - } - } - return id - }) - } - - this.build = m[5] ? m[5].split('.') : [] - this.format() -} - -SemVer.prototype.format = function () { - this.version = this.major + '.' + this.minor + '.' + this.patch - if (this.prerelease.length) { - this.version += '-' + this.prerelease.join('.') - } - return this.version -} - -SemVer.prototype.toString = function () { - return this.version -} - -SemVer.prototype.compare = function (other) { - debug('SemVer.compare', this.version, this.options, other) - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - return this.compareMain(other) || this.comparePre(other) -} - -SemVer.prototype.compareMain = function (other) { - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - return compareIdentifiers(this.major, other.major) || - compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch) -} - -SemVer.prototype.comparePre = function (other) { - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) { - return -1 - } else if (!this.prerelease.length && other.prerelease.length) { - return 1 - } else if (!this.prerelease.length && !other.prerelease.length) { - return 0 - } - - var i = 0 - do { - var a = this.prerelease[i] - var b = other.prerelease[i] - debug('prerelease compare', i, a, b) - if (a === undefined && b === undefined) { - return 0 - } else if (b === undefined) { - return 1 - } else if (a === undefined) { - return -1 - } else if (a === b) { - continue - } else { - return compareIdentifiers(a, b) - } - } while (++i) -} - -// preminor will bump the version up to the next minor release, and immediately -// down to pre-release. premajor and prepatch work the same way. -SemVer.prototype.inc = function (release, identifier) { - switch (release) { - case 'premajor': - this.prerelease.length = 0 - this.patch = 0 - this.minor = 0 - this.major++ - this.inc('pre', identifier) - break - case 'preminor': - this.prerelease.length = 0 - this.patch = 0 - this.minor++ - this.inc('pre', identifier) - break - case 'prepatch': - // If this is already a prerelease, it will bump to the next version - // drop any prereleases that might already exist, since they are not - // relevant at this point. - this.prerelease.length = 0 - this.inc('patch', identifier) - this.inc('pre', identifier) - break - // If the input is a non-prerelease version, this acts the same as - // prepatch. - case 'prerelease': - if (this.prerelease.length === 0) { - this.inc('patch', identifier) - } - this.inc('pre', identifier) - break - - case 'major': - // If this is a pre-major version, bump up to the same major version. - // Otherwise increment major. - // 1.0.0-5 bumps to 1.0.0 - // 1.1.0 bumps to 2.0.0 - if (this.minor !== 0 || - this.patch !== 0 || - this.prerelease.length === 0) { - this.major++ - } - this.minor = 0 - this.patch = 0 - this.prerelease = [] - break - case 'minor': - // If this is a pre-minor version, bump up to the same minor version. - // Otherwise increment minor. - // 1.2.0-5 bumps to 1.2.0 - // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) { - this.minor++ - } - this.patch = 0 - this.prerelease = [] - break - case 'patch': - // If this is not a pre-release version, it will increment the patch. - // If it is a pre-release it will bump up to the same patch version. - // 1.2.0-5 patches to 1.2.0 - // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) { - this.patch++ - } - this.prerelease = [] - break - // This probably shouldn't be used publicly. - // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. - case 'pre': - if (this.prerelease.length === 0) { - this.prerelease = [0] - } else { - var i = this.prerelease.length - while (--i >= 0) { - if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++ - i = -2 - } - } - if (i === -1) { - // didn't increment anything - this.prerelease.push(0) - } - } - if (identifier) { - // 1.2.0-beta.1 bumps to 1.2.0-beta.2, - // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - if (this.prerelease[0] === identifier) { - if (isNaN(this.prerelease[1])) { - this.prerelease = [identifier, 0] - } - } else { - this.prerelease = [identifier, 0] - } - } - break - - default: - throw new Error('invalid increment argument: ' + release) - } - this.format() - this.raw = this.version - return this -} - -exports.inc = inc -function inc (version, release, loose, identifier) { - if (typeof (loose) === 'string') { - identifier = loose - loose = undefined - } - - try { - return new SemVer(version, loose).inc(release, identifier).version - } catch (er) { - return null - } -} - -exports.diff = diff -function diff (version1, version2) { - if (eq(version1, version2)) { - return null - } else { - var v1 = parse(version1) - var v2 = parse(version2) - var prefix = '' - if (v1.prerelease.length || v2.prerelease.length) { - prefix = 'pre' - var defaultResult = 'prerelease' - } - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return prefix + key - } - } - } - return defaultResult // may be undefined - } -} - -exports.compareIdentifiers = compareIdentifiers - -var numeric = /^[0-9]+$/ -function compareIdentifiers (a, b) { - var anum = numeric.test(a) - var bnum = numeric.test(b) - - if (anum && bnum) { - a = +a - b = +b - } - - return a === b ? 0 - : (anum && !bnum) ? -1 - : (bnum && !anum) ? 1 - : a < b ? -1 - : 1 -} - -exports.rcompareIdentifiers = rcompareIdentifiers -function rcompareIdentifiers (a, b) { - return compareIdentifiers(b, a) -} - -exports.major = major -function major (a, loose) { - return new SemVer(a, loose).major -} - -exports.minor = minor -function minor (a, loose) { - return new SemVer(a, loose).minor -} - -exports.patch = patch -function patch (a, loose) { - return new SemVer(a, loose).patch -} - -exports.compare = compare -function compare (a, b, loose) { - return new SemVer(a, loose).compare(new SemVer(b, loose)) -} - -exports.compareLoose = compareLoose -function compareLoose (a, b) { - return compare(a, b, true) -} - -exports.rcompare = rcompare -function rcompare (a, b, loose) { - return compare(b, a, loose) -} - -exports.sort = sort -function sort (list, loose) { - return list.sort(function (a, b) { - return exports.compare(a, b, loose) - }) -} - -exports.rsort = rsort -function rsort (list, loose) { - return list.sort(function (a, b) { - return exports.rcompare(a, b, loose) - }) -} - -exports.gt = gt -function gt (a, b, loose) { - return compare(a, b, loose) > 0 -} - -exports.lt = lt -function lt (a, b, loose) { - return compare(a, b, loose) < 0 -} - -exports.eq = eq -function eq (a, b, loose) { - return compare(a, b, loose) === 0 -} - -exports.neq = neq -function neq (a, b, loose) { - return compare(a, b, loose) !== 0 -} - -exports.gte = gte -function gte (a, b, loose) { - return compare(a, b, loose) >= 0 -} - -exports.lte = lte -function lte (a, b, loose) { - return compare(a, b, loose) <= 0 -} - -exports.cmp = cmp -function cmp (a, op, b, loose) { - switch (op) { - case '===': - if (typeof a === 'object') - a = a.version - if (typeof b === 'object') - b = b.version - return a === b - - case '!==': - if (typeof a === 'object') - a = a.version - if (typeof b === 'object') - b = b.version - return a !== b - - case '': - case '=': - case '==': - return eq(a, b, loose) - - case '!=': - return neq(a, b, loose) - - case '>': - return gt(a, b, loose) - - case '>=': - return gte(a, b, loose) - - case '<': - return lt(a, b, loose) - - case '<=': - return lte(a, b, loose) - - default: - throw new TypeError('Invalid operator: ' + op) - } -} - -exports.Comparator = Comparator -function Comparator (comp, options) { - if (!options || typeof options !== 'object') { - options = { - loose: !!options, - includePrerelease: false - } - } - - if (comp instanceof Comparator) { - if (comp.loose === !!options.loose) { - return comp - } else { - comp = comp.value - } - } - - if (!(this instanceof Comparator)) { - return new Comparator(comp, options) - } - - debug('comparator', comp, options) - this.options = options - this.loose = !!options.loose - this.parse(comp) - - if (this.semver === ANY) { - this.value = '' - } else { - this.value = this.operator + this.semver.version - } - - debug('comp', this) -} - -var ANY = {} -Comparator.prototype.parse = function (comp) { - var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] - var m = comp.match(r) - - if (!m) { - throw new TypeError('Invalid comparator: ' + comp) - } - - this.operator = m[1] - if (this.operator === '=') { - this.operator = '' - } - - // if it literally is just '>' or '' then allow anything. - if (!m[2]) { - this.semver = ANY - } else { - this.semver = new SemVer(m[2], this.options.loose) - } -} - -Comparator.prototype.toString = function () { - return this.value -} - -Comparator.prototype.test = function (version) { - debug('Comparator.test', version, this.options.loose) - - if (this.semver === ANY) { - return true - } - - if (typeof version === 'string') { - version = new SemVer(version, this.options) - } - - return cmp(version, this.operator, this.semver, this.options) -} - -Comparator.prototype.intersects = function (comp, options) { - if (!(comp instanceof Comparator)) { - throw new TypeError('a Comparator is required') - } - - if (!options || typeof options !== 'object') { - options = { - loose: !!options, - includePrerelease: false - } - } - - var rangeTmp - - if (this.operator === '') { - rangeTmp = new Range(comp.value, options) - return satisfies(this.value, rangeTmp, options) - } else if (comp.operator === '') { - rangeTmp = new Range(this.value, options) - return satisfies(comp.semver, rangeTmp, options) - } - - var sameDirectionIncreasing = - (this.operator === '>=' || this.operator === '>') && - (comp.operator === '>=' || comp.operator === '>') - var sameDirectionDecreasing = - (this.operator === '<=' || this.operator === '<') && - (comp.operator === '<=' || comp.operator === '<') - var sameSemVer = this.semver.version === comp.semver.version - var differentDirectionsInclusive = - (this.operator === '>=' || this.operator === '<=') && - (comp.operator === '>=' || comp.operator === '<=') - var oppositeDirectionsLessThan = - cmp(this.semver, '<', comp.semver, options) && - ((this.operator === '>=' || this.operator === '>') && - (comp.operator === '<=' || comp.operator === '<')) - var oppositeDirectionsGreaterThan = - cmp(this.semver, '>', comp.semver, options) && - ((this.operator === '<=' || this.operator === '<') && - (comp.operator === '>=' || comp.operator === '>')) - - return sameDirectionIncreasing || sameDirectionDecreasing || - (sameSemVer && differentDirectionsInclusive) || - oppositeDirectionsLessThan || oppositeDirectionsGreaterThan -} - -exports.Range = Range -function Range (range, options) { - if (!options || typeof options !== 'object') { - options = { - loose: !!options, - includePrerelease: false - } - } - - if (range instanceof Range) { - if (range.loose === !!options.loose && - range.includePrerelease === !!options.includePrerelease) { - return range - } else { - return new Range(range.raw, options) - } - } - - if (range instanceof Comparator) { - return new Range(range.value, options) - } - - if (!(this instanceof Range)) { - return new Range(range, options) - } - - this.options = options - this.loose = !!options.loose - this.includePrerelease = !!options.includePrerelease - - // First, split based on boolean or || - this.raw = range - this.set = range.split(/\s*\|\|\s*/).map(function (range) { - return this.parseRange(range.trim()) - }, this).filter(function (c) { - // throw out any that are not relevant for whatever reason - return c.length - }) - - if (!this.set.length) { - throw new TypeError('Invalid SemVer Range: ' + range) - } - - this.format() -} - -Range.prototype.format = function () { - this.range = this.set.map(function (comps) { - return comps.join(' ').trim() - }).join('||').trim() - return this.range -} - -Range.prototype.toString = function () { - return this.range -} - -Range.prototype.parseRange = function (range) { - var loose = this.options.loose - range = range.trim() - // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] - range = range.replace(hr, hyphenReplace) - debug('hyphen replace', range) - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) - debug('comparator trim', range, re[COMPARATORTRIM]) - - // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace) - - // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace) - - // normalize spaces - range = range.split(/\s+/).join(' ') - - // At this point, the range is completely trimmed and - // ready to be split into comparators. - - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] - var set = range.split(' ').map(function (comp) { - return parseComparator(comp, this.options) - }, this).join(' ').split(/\s+/) - if (this.options.loose) { - // in loose mode, throw out any that are not valid comparators - set = set.filter(function (comp) { - return !!comp.match(compRe) - }) - } - set = set.map(function (comp) { - return new Comparator(comp, this.options) - }, this) - - return set -} - -Range.prototype.intersects = function (range, options) { - if (!(range instanceof Range)) { - throw new TypeError('a Range is required') - } - - return this.set.some(function (thisComparators) { - return thisComparators.every(function (thisComparator) { - return range.set.some(function (rangeComparators) { - return rangeComparators.every(function (rangeComparator) { - return thisComparator.intersects(rangeComparator, options) - }) - }) - }) - }) -} - -// Mostly just for testing and legacy API reasons -exports.toComparators = toComparators -function toComparators (range, options) { - return new Range(range, options).set.map(function (comp) { - return comp.map(function (c) { - return c.value - }).join(' ').trim().split(' ') - }) -} - -// comprised of xranges, tildes, stars, and gtlt's at this point. -// already replaced the hyphen ranges -// turn into a set of JUST comparators. -function parseComparator (comp, options) { - debug('comp', comp, options) - comp = replaceCarets(comp, options) - debug('caret', comp) - comp = replaceTildes(comp, options) - debug('tildes', comp) - comp = replaceXRanges(comp, options) - debug('xrange', comp) - comp = replaceStars(comp, options) - debug('stars', comp) - return comp -} - -function isX (id) { - return !id || id.toLowerCase() === 'x' || id === '*' -} - -// ~, ~> --> * (any, kinda silly) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 -function replaceTildes (comp, options) { - return comp.trim().split(/\s+/).map(function (comp) { - return replaceTilde(comp, options) - }).join(' ') -} - -function replaceTilde (comp, options) { - var r = options.loose ? re[TILDELOOSE] : re[TILDE] - return comp.replace(r, function (_, M, m, p, pr) { - debug('tilde', comp, _, M, m, p, pr) - var ret - - if (isX(M)) { - ret = '' - } else if (isX(m)) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' - } else if (isX(p)) { - // ~1.2 == >=1.2.0 <1.3.0 - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' - } else if (pr) { - debug('replaceTilde pr', pr) - ret = '>=' + M + '.' + m + '.' + p + '-' + pr + - ' <' + M + '.' + (+m + 1) + '.0' - } else { - // ~1.2.3 == >=1.2.3 <1.3.0 - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0' - } - - debug('tilde return', ret) - return ret - }) -} - -// ^ --> * (any, kinda silly) -// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 -// ^1.2.3 --> >=1.2.3 <2.0.0 -// ^1.2.0 --> >=1.2.0 <2.0.0 -function replaceCarets (comp, options) { - return comp.trim().split(/\s+/).map(function (comp) { - return replaceCaret(comp, options) - }).join(' ') -} - -function replaceCaret (comp, options) { - debug('caret', comp, options) - var r = options.loose ? re[CARETLOOSE] : re[CARET] - return comp.replace(r, function (_, M, m, p, pr) { - debug('caret', comp, _, M, m, p, pr) - var ret - - if (isX(M)) { - ret = '' - } else if (isX(m)) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' - } else if (isX(p)) { - if (M === '0') { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' - } else { - ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' - } - } else if (pr) { - debug('replaceCaret pr', pr) - if (M === '0') { - if (m === '0') { - ret = '>=' + M + '.' + m + '.' + p + '-' + pr + - ' <' + M + '.' + m + '.' + (+p + 1) - } else { - ret = '>=' + M + '.' + m + '.' + p + '-' + pr + - ' <' + M + '.' + (+m + 1) + '.0' - } - } else { - ret = '>=' + M + '.' + m + '.' + p + '-' + pr + - ' <' + (+M + 1) + '.0.0' - } - } else { - debug('no pr') - if (M === '0') { - if (m === '0') { - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + m + '.' + (+p + 1) - } else { - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0' - } - } else { - ret = '>=' + M + '.' + m + '.' + p + - ' <' + (+M + 1) + '.0.0' - } - } - - debug('caret return', ret) - return ret - }) -} - -function replaceXRanges (comp, options) { - debug('replaceXRanges', comp, options) - return comp.split(/\s+/).map(function (comp) { - return replaceXRange(comp, options) - }).join(' ') -} - -function replaceXRange (comp, options) { - comp = comp.trim() - var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] - return comp.replace(r, function (ret, gtlt, M, m, p, pr) { - debug('xRange', comp, ret, gtlt, M, m, p, pr) - var xM = isX(M) - var xm = xM || isX(m) - var xp = xm || isX(p) - var anyX = xp - - if (gtlt === '=' && anyX) { - gtlt = '' - } - - if (xM) { - if (gtlt === '>' || gtlt === '<') { - // nothing is allowed - ret = '<0.0.0' - } else { - // nothing is forbidden - ret = '*' - } - } else if (gtlt && anyX) { - // we know patch is an x, because we have any x at all. - // replace X with 0 - if (xm) { - m = 0 - } - p = 0 - - if (gtlt === '>') { - // >1 => >=2.0.0 - // >1.2 => >=1.3.0 - // >1.2.3 => >= 1.2.4 - gtlt = '>=' - if (xm) { - M = +M + 1 - m = 0 - p = 0 - } else { - m = +m + 1 - p = 0 - } - } else if (gtlt === '<=') { - // <=0.7.x is actually <0.8.0, since any 0.7.x should - // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<' - if (xm) { - M = +M + 1 - } else { - m = +m + 1 - } - } - - ret = gtlt + M + '.' + m + '.' + p - } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' - } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' - } - - debug('xRange return', ret) - - return ret - }) -} - -// Because * is AND-ed with everything else in the comparator, -// and '' means "any version", just remove the *s entirely. -function replaceStars (comp, options) { - debug('replaceStars', comp, options) - // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], '') -} - -// This function is passed to string.replace(re[HYPHENRANGE]) -// M, m, patch, prerelease, build -// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 -// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do -// 1.2 - 3.4 => >=1.2.0 <3.5.0 -function hyphenReplace ($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr, tb) { - if (isX(fM)) { - from = '' - } else if (isX(fm)) { - from = '>=' + fM + '.0.0' - } else if (isX(fp)) { - from = '>=' + fM + '.' + fm + '.0' - } else { - from = '>=' + from - } - - if (isX(tM)) { - to = '' - } else if (isX(tm)) { - to = '<' + (+tM + 1) + '.0.0' - } else if (isX(tp)) { - to = '<' + tM + '.' + (+tm + 1) + '.0' - } else if (tpr) { - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr - } else { - to = '<=' + to - } - - return (from + ' ' + to).trim() -} - -// if ANY of the sets match ALL of its comparators, then pass -Range.prototype.test = function (version) { - if (!version) { - return false - } - - if (typeof version === 'string') { - version = new SemVer(version, this.options) - } - - for (var i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version, this.options)) { - return true - } - } - return false -} - -function testSet (set, version, options) { - for (var i = 0; i < set.length; i++) { - if (!set[i].test(version)) { - return false - } - } - - if (version.prerelease.length && !options.includePrerelease) { - // Find the set of versions that are allowed to have prereleases - // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 - // That should allow `1.2.3-pr.2` to pass. - // However, `1.2.4-alpha.notready` should NOT be allowed, - // even though it's within the range set by the comparators. - for (i = 0; i < set.length; i++) { - debug(set[i].semver) - if (set[i].semver === ANY) { - continue - } - - if (set[i].semver.prerelease.length > 0) { - var allowed = set[i].semver - if (allowed.major === version.major && - allowed.minor === version.minor && - allowed.patch === version.patch) { - return true - } - } - } - - // Version has a -pre, but it's not one of the ones we like. - return false - } - - return true -} - -exports.satisfies = satisfies -function satisfies (version, range, options) { - try { - range = new Range(range, options) - } catch (er) { - return false - } - return range.test(version) -} - -exports.maxSatisfying = maxSatisfying -function maxSatisfying (versions, range, options) { - var max = null - var maxSV = null - try { - var rangeObj = new Range(range, options) - } catch (er) { - return null - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { - // satisfies(v, range, options) - if (!max || maxSV.compare(v) === -1) { - // compare(max, v, true) - max = v - maxSV = new SemVer(max, options) - } - } - }) - return max -} - -exports.minSatisfying = minSatisfying -function minSatisfying (versions, range, options) { - var min = null - var minSV = null - try { - var rangeObj = new Range(range, options) - } catch (er) { - return null - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { - // satisfies(v, range, options) - if (!min || minSV.compare(v) === 1) { - // compare(min, v, true) - min = v - minSV = new SemVer(min, options) - } - } - }) - return min -} + } -exports.minVersion = minVersion -function minVersion (range, loose) { - range = new Range(range, loose) + if (error.message.includes('null bytes')) { + throw error; + } - var minver = new SemVer('0.0.0') - if (range.test(minver)) { - return minver - } + return make(path.dirname(pth)).then(() => make(pth)); + } - minver = new SemVer('0.0.0-0') - if (range.test(minver)) { - return minver - } + return stat(pth) + .then(stats => stats.isDirectory() ? pth : Promise.reject()) + .catch(() => { + throw error; + }); + }); + }; - minver = null - for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i] + return make(path.resolve(input)); +}); - comparators.forEach(function (comparator) { - // Clone to avoid manipulating the comparator's semver object. - var compver = new SemVer(comparator.semver.version) - switch (comparator.operator) { - case '>': - if (compver.prerelease.length === 0) { - compver.patch++ - } else { - compver.prerelease.push(0) - } - compver.raw = compver.format() - /* fallthrough */ - case '': - case '>=': - if (!minver || gt(minver, compver)) { - minver = compver - } - break - case '<': - case '<=': - /* Ignore maximum versions */ - break - /* istanbul ignore next */ - default: - throw new Error('Unexpected operation: ' + comparator.operator) - } - }) - } +module.exports = makeDir; +module.exports.default = makeDir; - if (minver && range.test(minver)) { - return minver - } +module.exports.sync = (input, options) => { + checkPath(input); + options = Object.assign({}, defaults, options); - return null -} + if (useNativeRecursiveOption && options.fs.mkdirSync === fs.mkdirSync) { + const pth = path.resolve(input); -exports.validRange = validRange -function validRange (range, options) { - try { - // Return '*' instead of '' so that truthiness works. - // This will throw if it's invalid anyway - return new Range(range, options).range || '*' - } catch (er) { - return null - } -} + fs.mkdirSync(pth, { + mode: options.mode, + recursive: true + }); -// Determine if version is less than all the versions possible in the range -exports.ltr = ltr -function ltr (version, range, options) { - return outside(version, range, '<', options) -} + return pth; + } -// Determine if version is greater than all the versions possible in the range. -exports.gtr = gtr -function gtr (version, range, options) { - return outside(version, range, '>', options) -} + const make = pth => { + try { + options.fs.mkdirSync(pth, options.mode); + } catch (error) { + if (error.code === 'EPERM') { + throw error; + } -exports.outside = outside -function outside (version, range, hilo, options) { - version = new SemVer(version, options) - range = new Range(range, options) + if (error.code === 'ENOENT') { + if (path.dirname(pth) === pth) { + throw permissionError(pth); + } - var gtfn, ltefn, ltfn, comp, ecomp - switch (hilo) { - case '>': - gtfn = gt - ltefn = lte - ltfn = lt - comp = '>' - ecomp = '>=' - break - case '<': - gtfn = lt - ltefn = gte - ltfn = gt - comp = '<' - ecomp = '<=' - break - default: - throw new TypeError('Must provide a hilo val of "<" or ">"') - } + if (error.message.includes('null bytes')) { + throw error; + } - // If it satisifes the range it is not outside - if (satisfies(version, range, options)) { - return false - } + make(path.dirname(pth)); + return make(pth); + } - // From now on, variable terms are as if we're in "gtr" mode. - // but note that everything is flipped for the "ltr" function. + try { + if (!options.fs.statSync(pth).isDirectory()) { + throw new Error('The path is not a directory'); + } + } catch (_) { + throw error; + } + } - for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i] + return pth; + }; - var high = null - var low = null + return make(path.resolve(input)); +}; - comparators.forEach(function (comparator) { - if (comparator.semver === ANY) { - comparator = new Comparator('>=0.0.0') - } - high = high || comparator - low = low || comparator - if (gtfn(comparator.semver, high.semver, options)) { - high = comparator - } else if (ltfn(comparator.semver, low.semver, options)) { - low = comparator - } - }) - // If the edge version comparator has a operator then our version - // isn't outside it - if (high.operator === comp || high.operator === ecomp) { - return false - } +/***/ }), +/* 560 */ +/***/ (function(module, exports, __webpack_require__) { - // If the lowest version comparator has an operator and our version - // is less than it then it isn't higher than the range - if ((!low.operator || low.operator === comp) && - ltefn(version, low.semver)) { - return false - } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false - } - } - return true -} +"use strict"; -exports.prerelease = prerelease -function prerelease (version, options) { - var parsed = parse(version, options) - return (parsed && parsed.prerelease.length) ? parsed.prerelease : null -} -exports.intersects = intersects -function intersects (r1, r2, options) { - r1 = new Range(r1, options) - r2 = new Range(r2, options) - return r1.intersects(r2) -} +const processFn = (fn, options) => function (...args) { + const P = options.promiseModule; -exports.coerce = coerce -function coerce (version) { - if (version instanceof SemVer) { - return version - } + return new P((resolve, reject) => { + if (options.multiArgs) { + args.push((...result) => { + if (options.errorFirst) { + if (result[0]) { + reject(result); + } else { + result.shift(); + resolve(result); + } + } else { + resolve(result); + } + }); + } else if (options.errorFirst) { + args.push((error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + } else { + args.push(resolve); + } - if (typeof version !== 'string') { - return null - } + fn.apply(this, args); + }); +}; - var match = version.match(re[COERCE]) +module.exports = (input, options) => { + options = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, options); - if (match == null) { - return null - } + const objType = typeof input; + if (!(input !== null && (objType === 'object' || objType === 'function'))) { + throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); + } - return parse(match[1] + - '.' + (match[2] || '0') + - '.' + (match[3] || '0')) -} + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); + return options.include ? options.include.some(match) : !options.exclude.some(match); + }; + + let ret; + if (objType === 'function') { + ret = function (...args) { + return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); + }; + } else { + ret = Object.create(Object.getPrototypeOf(input)); + } + + for (const key in input) { // eslint-disable-line guard-for-in + const property = input[key]; + ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; + } + + return ret; +}; /***/ }), -/* 562 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56384,7 +55082,7 @@ module.exports = (input, options) => { /***/ }), -/* 563 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56513,7 +55211,7 @@ module.exports = str => { /***/ }), -/* 564 */ +/* 563 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56522,7 +55220,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackage", function() { return runScriptInPackage; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackageStreaming", function() { return runScriptInPackageStreaming; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "yarnWorkspacesInfo", function() { return yarnWorkspacesInfo; }); -/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(565); +/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(564); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -56592,7 +55290,7 @@ async function yarnWorkspacesInfo(directory) { } /***/ }), -/* 565 */ +/* 564 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56603,9 +55301,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(351); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(566); +/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(565); /* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(log_symbols__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(571); +/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(570); /* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } @@ -56671,12 +55369,12 @@ function spawnStreaming(command, args, opts, { } /***/ }), -/* 566 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(567); +const chalk = __webpack_require__(566); const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; @@ -56698,16 +55396,16 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 567 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(568); -const stdoutColor = __webpack_require__(569).stdout; +const ansiStyles = __webpack_require__(567); +const stdoutColor = __webpack_require__(568).stdout; -const template = __webpack_require__(570); +const template = __webpack_require__(569); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -56933,7 +55631,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 568 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57106,7 +55804,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 569 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57248,7 +55946,7 @@ module.exports = { /***/ }), -/* 570 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57383,7 +56081,7 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 571 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -57391,12 +56089,12 @@ module.exports = (chalk, tmp) => { // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(572); -module.exports.cli = __webpack_require__(576); +module.exports = __webpack_require__(571); +module.exports.cli = __webpack_require__(575); /***/ }), -/* 572 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57411,9 +56109,9 @@ var stream = __webpack_require__(27); var util = __webpack_require__(29); var fs = __webpack_require__(23); -var through = __webpack_require__(573); -var duplexer = __webpack_require__(574); -var StringDecoder = __webpack_require__(575).StringDecoder; +var through = __webpack_require__(572); +var duplexer = __webpack_require__(573); +var StringDecoder = __webpack_require__(574).StringDecoder; module.exports = Logger; @@ -57602,7 +56300,7 @@ function lineMerger(host) { /***/ }), -/* 573 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27) @@ -57716,7 +56414,7 @@ function through (write, end, opts) { /***/ }), -/* 574 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27) @@ -57809,13 +56507,13 @@ function duplex(writer, reader) { /***/ }), -/* 575 */ +/* 574 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 576 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57826,11 +56524,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(577); +var minimist = __webpack_require__(576); var path = __webpack_require__(16); -var Logger = __webpack_require__(572); -var pkg = __webpack_require__(578); +var Logger = __webpack_require__(571); +var pkg = __webpack_require__(577); module.exports = cli; @@ -57884,7 +56582,7 @@ function usage($0, p) { /***/ }), -/* 577 */ +/* 576 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -58126,13 +56824,13 @@ function isNumber (x) { /***/ }), -/* 578 */ +/* 577 */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham \",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}"); /***/ }), -/* 579 */ +/* 578 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -58145,7 +56843,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); /* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(517); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(501); @@ -58240,7 +56938,7 @@ function packagesFromGlobPattern({ } /***/ }), -/* 580 */ +/* 579 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -58309,7 +57007,7 @@ function getProjectPaths({ } /***/ }), -/* 581 */ +/* 580 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -58317,13 +57015,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAllChecksums", function() { return getAllChecksums; }); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(582); +/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(581); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(351); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(583); +/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(582); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -58540,19 +57238,19 @@ async function getAllChecksums(kbn, log) { } /***/ }), -/* 582 */ +/* 581 */ /***/ (function(module, exports) { module.exports = require("crypto"); /***/ }), -/* 583 */ +/* 582 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readYarnLock", function() { return readYarnLock; }); -/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(584); +/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(583); /* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(20); /* @@ -58596,7 +57294,7 @@ async function readYarnLock(kbn) { } /***/ }), -/* 584 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { module.exports = @@ -60155,7 +58853,7 @@ module.exports = invariant; /* 9 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(582); +module.exports = __webpack_require__(581); /***/ }), /* 10 */, @@ -62479,7 +61177,7 @@ function onceStrict (fn) { /* 63 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(585); +module.exports = __webpack_require__(584); /***/ }), /* 64 */, @@ -68874,13 +67572,13 @@ module.exports = process && support(supportLevel); /******/ ]); /***/ }), -/* 585 */ +/* 584 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 586 */ +/* 585 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -68977,7 +67675,7 @@ class BootstrapCacheFile { } /***/ }), -/* 587 */ +/* 586 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -68985,9 +67683,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CleanCommand", function() { return CleanCommand; }); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(588); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(676); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(675); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -69087,21 +67785,21 @@ const CleanCommand = { }; /***/ }), -/* 588 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const path = __webpack_require__(16); -const globby = __webpack_require__(589); -const isGlob = __webpack_require__(606); -const slash = __webpack_require__(667); +const globby = __webpack_require__(588); +const isGlob = __webpack_require__(605); +const slash = __webpack_require__(666); const gracefulFs = __webpack_require__(22); -const isPathCwd = __webpack_require__(669); -const isPathInside = __webpack_require__(670); -const rimraf = __webpack_require__(671); -const pMap = __webpack_require__(672); +const isPathCwd = __webpack_require__(668); +const isPathInside = __webpack_require__(669); +const rimraf = __webpack_require__(670); +const pMap = __webpack_require__(671); const rimrafP = promisify(rimraf); @@ -69215,19 +67913,19 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options /***/ }), -/* 589 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(590); -const merge2 = __webpack_require__(591); -const glob = __webpack_require__(592); -const fastGlob = __webpack_require__(597); -const dirGlob = __webpack_require__(663); -const gitignore = __webpack_require__(665); -const {FilterStream, UniqueStream} = __webpack_require__(668); +const arrayUnion = __webpack_require__(589); +const merge2 = __webpack_require__(590); +const glob = __webpack_require__(591); +const fastGlob = __webpack_require__(596); +const dirGlob = __webpack_require__(662); +const gitignore = __webpack_require__(664); +const {FilterStream, UniqueStream} = __webpack_require__(667); const DEFAULT_FILTER = () => false; @@ -69400,7 +68098,7 @@ module.exports.gitignore = gitignore; /***/ }), -/* 590 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69412,7 +68110,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 591 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69526,7 +68224,7 @@ function pauseStreams (streams, options) { /***/ }), -/* 592 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -69575,13 +68273,13 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(593) +var inherits = __webpack_require__(592) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var globSync = __webpack_require__(595) -var common = __webpack_require__(596) +var globSync = __webpack_require__(594) +var common = __webpack_require__(595) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -70322,7 +69020,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 593 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -70332,12 +69030,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(594); + module.exports = __webpack_require__(593); } /***/ }), -/* 594 */ +/* 593 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -70370,7 +69068,7 @@ if (typeof Object.create === 'function') { /***/ }), -/* 595 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync @@ -70380,12 +69078,12 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(592).Glob +var Glob = __webpack_require__(591).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var common = __webpack_require__(596) +var common = __webpack_require__(595) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -70862,7 +69560,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 596 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { exports.alphasort = alphasort @@ -71108,17 +69806,17 @@ function childrenIgnored (self, path) { /***/ }), -/* 597 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(598); -const async_1 = __webpack_require__(626); -const stream_1 = __webpack_require__(659); -const sync_1 = __webpack_require__(660); -const settings_1 = __webpack_require__(662); -const utils = __webpack_require__(599); +const taskManager = __webpack_require__(597); +const async_1 = __webpack_require__(625); +const stream_1 = __webpack_require__(658); +const sync_1 = __webpack_require__(659); +const settings_1 = __webpack_require__(661); +const utils = __webpack_require__(598); function FastGlob(source, options) { try { assertPatternsInput(source); @@ -71176,13 +69874,13 @@ module.exports = FastGlob; /***/ }), -/* 598 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(599); +const utils = __webpack_require__(598); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -71250,28 +69948,28 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 599 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const array = __webpack_require__(600); +const array = __webpack_require__(599); exports.array = array; -const errno = __webpack_require__(601); +const errno = __webpack_require__(600); exports.errno = errno; -const fs = __webpack_require__(602); +const fs = __webpack_require__(601); exports.fs = fs; -const path = __webpack_require__(603); +const path = __webpack_require__(602); exports.path = path; -const pattern = __webpack_require__(604); +const pattern = __webpack_require__(603); exports.pattern = pattern; -const stream = __webpack_require__(625); +const stream = __webpack_require__(624); exports.stream = stream; /***/ }), -/* 600 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71284,7 +69982,7 @@ exports.flatten = flatten; /***/ }), -/* 601 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71297,7 +69995,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 602 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71322,7 +70020,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 603 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71343,16 +70041,16 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 604 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const globParent = __webpack_require__(605); -const isGlob = __webpack_require__(606); -const micromatch = __webpack_require__(608); +const globParent = __webpack_require__(604); +const isGlob = __webpack_require__(605); +const micromatch = __webpack_require__(607); const GLOBSTAR = '**'; function isStaticPattern(pattern) { return !isDynamicPattern(pattern); @@ -71441,13 +70139,13 @@ exports.matchAny = matchAny; /***/ }), -/* 605 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isGlob = __webpack_require__(606); +var isGlob = __webpack_require__(605); var pathPosixDirname = __webpack_require__(16).posix.dirname; var isWin32 = __webpack_require__(11).platform() === 'win32'; @@ -71482,7 +70180,7 @@ module.exports = function globParent(str) { /***/ }), -/* 606 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -71492,7 +70190,7 @@ module.exports = function globParent(str) { * Released under the MIT License. */ -var isExtglob = __webpack_require__(607); +var isExtglob = __webpack_require__(606); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -71536,7 +70234,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 607 */ +/* 606 */ /***/ (function(module, exports) { /*! @@ -71562,16 +70260,16 @@ module.exports = function isExtglob(str) { /***/ }), -/* 608 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const util = __webpack_require__(29); -const braces = __webpack_require__(609); -const picomatch = __webpack_require__(619); -const utils = __webpack_require__(622); +const braces = __webpack_require__(608); +const picomatch = __webpack_require__(618); +const utils = __webpack_require__(621); const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); /** @@ -72036,16 +70734,16 @@ module.exports = micromatch; /***/ }), -/* 609 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(610); -const compile = __webpack_require__(612); -const expand = __webpack_require__(616); -const parse = __webpack_require__(617); +const stringify = __webpack_require__(609); +const compile = __webpack_require__(611); +const expand = __webpack_require__(615); +const parse = __webpack_require__(616); /** * Expand the given pattern or create a regex-compatible string. @@ -72213,13 +70911,13 @@ module.exports = braces; /***/ }), -/* 610 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(611); +const utils = __webpack_require__(610); module.exports = (ast, options = {}) => { let stringify = (node, parent = {}) => { @@ -72252,7 +70950,7 @@ module.exports = (ast, options = {}) => { /***/ }), -/* 611 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72371,14 +71069,14 @@ exports.flatten = (...args) => { /***/ }), -/* 612 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(613); -const utils = __webpack_require__(611); +const fill = __webpack_require__(612); +const utils = __webpack_require__(610); const compile = (ast, options = {}) => { let walk = (node, parent = {}) => { @@ -72435,7 +71133,7 @@ module.exports = compile; /***/ }), -/* 613 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72449,7 +71147,7 @@ module.exports = compile; const util = __webpack_require__(29); -const toRegexRange = __webpack_require__(614); +const toRegexRange = __webpack_require__(613); const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); @@ -72691,7 +71389,7 @@ module.exports = fill; /***/ }), -/* 614 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72704,7 +71402,7 @@ module.exports = fill; -const isNumber = __webpack_require__(615); +const isNumber = __webpack_require__(614); const toRegexRange = (min, max, options) => { if (isNumber(min) === false) { @@ -72986,7 +71684,7 @@ module.exports = toRegexRange; /***/ }), -/* 615 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73011,15 +71709,15 @@ module.exports = function(num) { /***/ }), -/* 616 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(613); -const stringify = __webpack_require__(610); -const utils = __webpack_require__(611); +const fill = __webpack_require__(612); +const stringify = __webpack_require__(609); +const utils = __webpack_require__(610); const append = (queue = '', stash = '', enclose = false) => { let result = []; @@ -73131,13 +71829,13 @@ module.exports = expand; /***/ }), -/* 617 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(610); +const stringify = __webpack_require__(609); /** * Constants @@ -73159,7 +71857,7 @@ const { CHAR_SINGLE_QUOTE, /* ' */ CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(618); +} = __webpack_require__(617); /** * parse @@ -73471,7 +72169,7 @@ module.exports = parse; /***/ }), -/* 618 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73535,26 +72233,26 @@ module.exports = { /***/ }), -/* 619 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(620); +module.exports = __webpack_require__(619); /***/ }), -/* 620 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const scan = __webpack_require__(621); -const parse = __webpack_require__(624); -const utils = __webpack_require__(622); +const scan = __webpack_require__(620); +const parse = __webpack_require__(623); +const utils = __webpack_require__(621); /** * Creates a matcher function from one or more glob patterns. The @@ -73857,7 +72555,7 @@ picomatch.toRegex = (source, options) => { * @return {Object} */ -picomatch.constants = __webpack_require__(623); +picomatch.constants = __webpack_require__(622); /** * Expose "picomatch" @@ -73867,13 +72565,13 @@ module.exports = picomatch; /***/ }), -/* 621 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(622); +const utils = __webpack_require__(621); const { CHAR_ASTERISK, /* * */ @@ -73891,7 +72589,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(623); +} = __webpack_require__(622); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -74093,7 +72791,7 @@ module.exports = (input, options) => { /***/ }), -/* 622 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74105,7 +72803,7 @@ const { REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL, REGEX_REMOVE_BACKSLASH -} = __webpack_require__(623); +} = __webpack_require__(622); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -74143,7 +72841,7 @@ exports.escapeLast = (input, char, lastIdx) => { /***/ }), -/* 623 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74329,14 +73027,14 @@ module.exports = { /***/ }), -/* 624 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(622); -const constants = __webpack_require__(623); +const utils = __webpack_require__(621); +const constants = __webpack_require__(622); /** * Constants @@ -75347,13 +74045,13 @@ module.exports = parse; /***/ }), -/* 625 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(591); +const merge2 = __webpack_require__(590); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { @@ -75365,14 +74063,14 @@ exports.merge = merge; /***/ }), -/* 626 */ +/* 625 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(627); -const provider_1 = __webpack_require__(654); +const stream_1 = __webpack_require__(626); +const provider_1 = __webpack_require__(653); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -75400,16 +74098,16 @@ exports.default = ProviderAsync; /***/ }), -/* 627 */ +/* 626 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const fsStat = __webpack_require__(628); -const fsWalk = __webpack_require__(633); -const reader_1 = __webpack_require__(653); +const fsStat = __webpack_require__(627); +const fsWalk = __webpack_require__(632); +const reader_1 = __webpack_require__(652); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -75462,15 +74160,15 @@ exports.default = ReaderStream; /***/ }), -/* 628 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(629); -const sync = __webpack_require__(630); -const settings_1 = __webpack_require__(631); +const async = __webpack_require__(628); +const sync = __webpack_require__(629); +const settings_1 = __webpack_require__(630); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -75493,7 +74191,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 629 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75531,7 +74229,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 630 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75560,13 +74258,13 @@ exports.read = read; /***/ }), -/* 631 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(632); +const fs = __webpack_require__(631); class Settings { constructor(_options = {}) { this._options = _options; @@ -75583,7 +74281,7 @@ exports.default = Settings; /***/ }), -/* 632 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75606,16 +74304,16 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 633 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(634); -const stream_1 = __webpack_require__(649); -const sync_1 = __webpack_require__(650); -const settings_1 = __webpack_require__(652); +const async_1 = __webpack_require__(633); +const stream_1 = __webpack_require__(648); +const sync_1 = __webpack_require__(649); +const settings_1 = __webpack_require__(651); exports.Settings = settings_1.default; function walk(dir, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -75645,13 +74343,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 634 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(635); +const async_1 = __webpack_require__(634); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -75682,17 +74380,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 635 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __webpack_require__(379); -const fsScandir = __webpack_require__(636); -const fastq = __webpack_require__(645); -const common = __webpack_require__(647); -const reader_1 = __webpack_require__(648); +const fsScandir = __webpack_require__(635); +const fastq = __webpack_require__(644); +const common = __webpack_require__(646); +const reader_1 = __webpack_require__(647); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -75782,15 +74480,15 @@ exports.default = AsyncReader; /***/ }), -/* 636 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(637); -const sync = __webpack_require__(642); -const settings_1 = __webpack_require__(643); +const async = __webpack_require__(636); +const sync = __webpack_require__(641); +const settings_1 = __webpack_require__(642); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -75813,16 +74511,16 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 637 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(628); -const rpl = __webpack_require__(638); -const constants_1 = __webpack_require__(639); -const utils = __webpack_require__(640); +const fsStat = __webpack_require__(627); +const rpl = __webpack_require__(637); +const constants_1 = __webpack_require__(638); +const utils = __webpack_require__(639); function read(dir, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(dir, settings, callback); @@ -75911,7 +74609,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 638 */ +/* 637 */ /***/ (function(module, exports) { module.exports = runParallel @@ -75965,7 +74663,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 639 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75981,18 +74679,18 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSIO /***/ }), -/* 640 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(641); +const fs = __webpack_require__(640); exports.fs = fs; /***/ }), -/* 641 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76017,15 +74715,15 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 642 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(628); -const constants_1 = __webpack_require__(639); -const utils = __webpack_require__(640); +const fsStat = __webpack_require__(627); +const constants_1 = __webpack_require__(638); +const utils = __webpack_require__(639); function read(dir, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(dir, settings); @@ -76076,15 +74774,15 @@ exports.readdir = readdir; /***/ }), -/* 643 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(628); -const fs = __webpack_require__(644); +const fsStat = __webpack_require__(627); +const fs = __webpack_require__(643); class Settings { constructor(_options = {}) { this._options = _options; @@ -76107,7 +74805,7 @@ exports.default = Settings; /***/ }), -/* 644 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76132,13 +74830,13 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 645 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var reusify = __webpack_require__(646) +var reusify = __webpack_require__(645) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -76312,7 +75010,7 @@ module.exports = fastqueue /***/ }), -/* 646 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76352,7 +75050,7 @@ module.exports = reusify /***/ }), -/* 647 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76383,13 +75081,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 648 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(647); +const common = __webpack_require__(646); class Reader { constructor(_root, _settings) { this._root = _root; @@ -76401,14 +75099,14 @@ exports.default = Reader; /***/ }), -/* 649 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const async_1 = __webpack_require__(635); +const async_1 = __webpack_require__(634); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -76438,13 +75136,13 @@ exports.default = StreamProvider; /***/ }), -/* 650 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(651); +const sync_1 = __webpack_require__(650); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -76459,15 +75157,15 @@ exports.default = SyncProvider; /***/ }), -/* 651 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(636); -const common = __webpack_require__(647); -const reader_1 = __webpack_require__(648); +const fsScandir = __webpack_require__(635); +const common = __webpack_require__(646); +const reader_1 = __webpack_require__(647); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -76525,14 +75223,14 @@ exports.default = SyncReader; /***/ }), -/* 652 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsScandir = __webpack_require__(636); +const fsScandir = __webpack_require__(635); class Settings { constructor(_options = {}) { this._options = _options; @@ -76558,15 +75256,15 @@ exports.default = Settings; /***/ }), -/* 653 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(628); -const utils = __webpack_require__(599); +const fsStat = __webpack_require__(627); +const utils = __webpack_require__(598); class Reader { constructor(_settings) { this._settings = _settings; @@ -76598,17 +75296,17 @@ exports.default = Reader; /***/ }), -/* 654 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const deep_1 = __webpack_require__(655); -const entry_1 = __webpack_require__(656); -const error_1 = __webpack_require__(657); -const entry_2 = __webpack_require__(658); +const deep_1 = __webpack_require__(654); +const entry_1 = __webpack_require__(655); +const error_1 = __webpack_require__(656); +const entry_2 = __webpack_require__(657); class Provider { constructor(_settings) { this._settings = _settings; @@ -76653,13 +75351,13 @@ exports.default = Provider; /***/ }), -/* 655 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(599); +const utils = __webpack_require__(598); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -76719,13 +75417,13 @@ exports.default = DeepFilter; /***/ }), -/* 656 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(599); +const utils = __webpack_require__(598); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -76780,13 +75478,13 @@ exports.default = EntryFilter; /***/ }), -/* 657 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(599); +const utils = __webpack_require__(598); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -76802,13 +75500,13 @@ exports.default = ErrorFilter; /***/ }), -/* 658 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(599); +const utils = __webpack_require__(598); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -76835,15 +75533,15 @@ exports.default = EntryTransformer; /***/ }), -/* 659 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const stream_2 = __webpack_require__(627); -const provider_1 = __webpack_require__(654); +const stream_2 = __webpack_require__(626); +const provider_1 = __webpack_require__(653); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -76871,14 +75569,14 @@ exports.default = ProviderStream; /***/ }), -/* 660 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(661); -const provider_1 = __webpack_require__(654); +const sync_1 = __webpack_require__(660); +const provider_1 = __webpack_require__(653); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -76901,15 +75599,15 @@ exports.default = ProviderSync; /***/ }), -/* 661 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(628); -const fsWalk = __webpack_require__(633); -const reader_1 = __webpack_require__(653); +const fsStat = __webpack_require__(627); +const fsWalk = __webpack_require__(632); +const reader_1 = __webpack_require__(652); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -76951,7 +75649,7 @@ exports.default = ReaderSync; /***/ }), -/* 662 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77011,13 +75709,13 @@ exports.default = Settings; /***/ }), -/* 663 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(664); +const pathType = __webpack_require__(663); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -77093,7 +75791,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 664 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77143,7 +75841,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 665 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77151,9 +75849,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); const {promisify} = __webpack_require__(29); const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(597); -const gitIgnore = __webpack_require__(666); -const slash = __webpack_require__(667); +const fastGlob = __webpack_require__(596); +const gitIgnore = __webpack_require__(665); +const slash = __webpack_require__(666); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -77267,7 +75965,7 @@ module.exports.sync = options => { /***/ }), -/* 666 */ +/* 665 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -77858,7 +76556,7 @@ if ( /***/ }), -/* 667 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77876,7 +76574,7 @@ module.exports = path => { /***/ }), -/* 668 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77929,7 +76627,7 @@ module.exports = { /***/ }), -/* 669 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77951,7 +76649,7 @@ module.exports = path_ => { /***/ }), -/* 670 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77979,7 +76677,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 671 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(30) @@ -77987,7 +76685,7 @@ const path = __webpack_require__(16) const fs = __webpack_require__(23) let glob = undefined try { - glob = __webpack_require__(592) + glob = __webpack_require__(591) } catch (_err) { // treat glob as optional. } @@ -78353,12 +77051,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 672 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(673); +const AggregateError = __webpack_require__(672); module.exports = async ( iterable, @@ -78441,13 +77139,13 @@ module.exports = async ( /***/ }), -/* 673 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(674); -const cleanStack = __webpack_require__(675); +const indentString = __webpack_require__(673); +const cleanStack = __webpack_require__(674); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -78495,7 +77193,7 @@ module.exports = AggregateError; /***/ }), -/* 674 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78537,7 +77235,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 675 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78584,15 +77282,15 @@ module.exports = (stack, options) => { /***/ }), -/* 676 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(677); -const cliCursor = __webpack_require__(681); -const cliSpinners = __webpack_require__(685); -const logSymbols = __webpack_require__(566); +const chalk = __webpack_require__(676); +const cliCursor = __webpack_require__(680); +const cliSpinners = __webpack_require__(684); +const logSymbols = __webpack_require__(565); class Ora { constructor(options) { @@ -78739,16 +77437,16 @@ module.exports.promise = (action, options) => { /***/ }), -/* 677 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(678); -const stdoutColor = __webpack_require__(679).stdout; +const ansiStyles = __webpack_require__(677); +const stdoutColor = __webpack_require__(678).stdout; -const template = __webpack_require__(680); +const template = __webpack_require__(679); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -78974,7 +77672,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 678 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79147,7 +77845,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 679 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79289,7 +77987,7 @@ module.exports = { /***/ }), -/* 680 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79424,12 +78122,12 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 681 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(682); +const restoreCursor = __webpack_require__(681); let hidden = false; @@ -79470,12 +78168,12 @@ exports.toggle = (force, stream) => { /***/ }), -/* 682 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(683); +const onetime = __webpack_require__(682); const signalExit = __webpack_require__(377); module.exports = onetime(() => { @@ -79486,12 +78184,12 @@ module.exports = onetime(() => { /***/ }), -/* 683 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(684); +const mimicFn = __webpack_require__(683); module.exports = (fn, opts) => { // TODO: Remove this in v3 @@ -79532,7 +78230,7 @@ module.exports = (fn, opts) => { /***/ }), -/* 684 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79548,22 +78246,22 @@ module.exports = (to, from) => { /***/ }), -/* 685 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(686); +module.exports = __webpack_require__(685); /***/ }), -/* 686 */ +/* 685 */ /***/ (function(module) { module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 687 */ +/* 686 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79623,7 +78321,7 @@ const RunCommand = { }; /***/ }), -/* 688 */ +/* 687 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79634,7 +78332,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(689); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(688); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -79718,7 +78416,7 @@ const WatchCommand = { }; /***/ }), -/* 689 */ +/* 688 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79792,7 +78490,7 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 690 */ +/* 689 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79800,15 +78498,15 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(691); +/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(690); /* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(692); +/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(691); /* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(501); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(699); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(700); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(698); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(699); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -79896,7 +78594,7 @@ function toArray(value) { } /***/ }), -/* 691 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79930,13 +78628,13 @@ module.exports = (str, count, opts) => { /***/ }), -/* 692 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringWidth = __webpack_require__(693); -const stripAnsi = __webpack_require__(697); +const stringWidth = __webpack_require__(692); +const stripAnsi = __webpack_require__(696); const ESCAPES = new Set([ '\u001B', @@ -80130,13 +78828,13 @@ module.exports = (str, cols, opts) => { /***/ }), -/* 693 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stripAnsi = __webpack_require__(694); -const isFullwidthCodePoint = __webpack_require__(696); +const stripAnsi = __webpack_require__(693); +const isFullwidthCodePoint = __webpack_require__(695); module.exports = str => { if (typeof str !== 'string' || str.length === 0) { @@ -80173,18 +78871,18 @@ module.exports = str => { /***/ }), -/* 694 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(695); +const ansiRegex = __webpack_require__(694); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 695 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80201,7 +78899,7 @@ module.exports = () => { /***/ }), -/* 696 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80254,18 +78952,18 @@ module.exports = x => { /***/ }), -/* 697 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(698); +const ansiRegex = __webpack_require__(697); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 698 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80282,7 +78980,7 @@ module.exports = () => { /***/ }), -/* 699 */ +/* 698 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -80435,7 +79133,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 700 */ +/* 699 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -80443,10 +79141,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(701); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(700); /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -80578,15 +79276,15 @@ class Kibana { } /***/ }), -/* 701 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const minimatch = __webpack_require__(505); -const arrayUnion = __webpack_require__(702); -const arrayDiffer = __webpack_require__(703); -const arrify = __webpack_require__(704); +const arrayUnion = __webpack_require__(701); +const arrayDiffer = __webpack_require__(702); +const arrify = __webpack_require__(703); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -80610,7 +79308,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 702 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80622,7 +79320,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 703 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80637,7 +79335,7 @@ module.exports = arrayDiffer; /***/ }), -/* 704 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80667,15 +79365,15 @@ module.exports = arrify; /***/ }), -/* 705 */ +/* 704 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(929); +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(928); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); /* @@ -80700,19 +79398,19 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 706 */ +/* 705 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(707); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(588); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); @@ -80848,7 +79546,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { } /***/ }), -/* 707 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80856,13 +79554,13 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(379); const path = __webpack_require__(16); const os = __webpack_require__(11); -const pAll = __webpack_require__(708); -const arrify = __webpack_require__(710); -const globby = __webpack_require__(711); -const isGlob = __webpack_require__(606); -const cpFile = __webpack_require__(914); -const junk = __webpack_require__(926); -const CpyError = __webpack_require__(927); +const pAll = __webpack_require__(707); +const arrify = __webpack_require__(709); +const globby = __webpack_require__(710); +const isGlob = __webpack_require__(605); +const cpFile = __webpack_require__(913); +const junk = __webpack_require__(925); +const CpyError = __webpack_require__(926); const defaultOptions = { ignoreJunk: true @@ -80981,12 +79679,12 @@ module.exports = (source, destination, { /***/ }), -/* 708 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(709); +const pMap = __webpack_require__(708); module.exports = (iterable, options) => pMap(iterable, element => element(), options); // TODO: Remove this for the next major release @@ -80994,7 +79692,7 @@ module.exports.default = module.exports; /***/ }), -/* 709 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81073,7 +79771,7 @@ module.exports.default = pMap; /***/ }), -/* 710 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81103,17 +79801,17 @@ module.exports = arrify; /***/ }), -/* 711 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(712); -const glob = __webpack_require__(714); -const fastGlob = __webpack_require__(719); -const dirGlob = __webpack_require__(907); -const gitignore = __webpack_require__(910); +const arrayUnion = __webpack_require__(711); +const glob = __webpack_require__(713); +const fastGlob = __webpack_require__(718); +const dirGlob = __webpack_require__(906); +const gitignore = __webpack_require__(909); const DEFAULT_FILTER = () => false; @@ -81258,12 +79956,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 712 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(713); +var arrayUniq = __webpack_require__(712); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -81271,7 +79969,7 @@ module.exports = function () { /***/ }), -/* 713 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81340,7 +80038,7 @@ if ('Set' in global) { /***/ }), -/* 714 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -81389,13 +80087,13 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(715) +var inherits = __webpack_require__(714) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var globSync = __webpack_require__(717) -var common = __webpack_require__(718) +var globSync = __webpack_require__(716) +var common = __webpack_require__(717) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -82136,7 +80834,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 715 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -82146,12 +80844,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(716); + module.exports = __webpack_require__(715); } /***/ }), -/* 716 */ +/* 715 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -82184,7 +80882,7 @@ if (typeof Object.create === 'function') { /***/ }), -/* 717 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync @@ -82194,12 +80892,12 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(714).Glob +var Glob = __webpack_require__(713).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var common = __webpack_require__(718) +var common = __webpack_require__(717) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -82676,7 +81374,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 718 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { exports.alphasort = alphasort @@ -82922,10 +81620,10 @@ function childrenIgnored (self, path) { /***/ }), -/* 719 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(720); +const pkg = __webpack_require__(719); module.exports = pkg.async; module.exports.default = pkg.async; @@ -82938,19 +81636,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 720 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(721); -var taskManager = __webpack_require__(722); -var reader_async_1 = __webpack_require__(878); -var reader_stream_1 = __webpack_require__(902); -var reader_sync_1 = __webpack_require__(903); -var arrayUtils = __webpack_require__(905); -var streamUtils = __webpack_require__(906); +var optionsManager = __webpack_require__(720); +var taskManager = __webpack_require__(721); +var reader_async_1 = __webpack_require__(877); +var reader_stream_1 = __webpack_require__(901); +var reader_sync_1 = __webpack_require__(902); +var arrayUtils = __webpack_require__(904); +var streamUtils = __webpack_require__(905); /** * Synchronous API. */ @@ -83016,7 +81714,7 @@ function isString(source) { /***/ }), -/* 721 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83054,13 +81752,13 @@ exports.prepare = prepare; /***/ }), -/* 722 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(723); +var patternUtils = __webpack_require__(722); /** * Generate tasks based on parent directory of each pattern. */ @@ -83151,16 +81849,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 723 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var globParent = __webpack_require__(724); -var isGlob = __webpack_require__(727); -var micromatch = __webpack_require__(728); +var globParent = __webpack_require__(723); +var isGlob = __webpack_require__(726); +var micromatch = __webpack_require__(727); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -83306,15 +82004,15 @@ exports.matchAny = matchAny; /***/ }), -/* 724 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(725); -var pathDirname = __webpack_require__(726); +var isglob = __webpack_require__(724); +var pathDirname = __webpack_require__(725); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -83337,7 +82035,7 @@ module.exports = function globParent(str) { /***/ }), -/* 725 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -83347,7 +82045,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(607); +var isExtglob = __webpack_require__(606); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -83368,7 +82066,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 726 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83518,7 +82216,7 @@ module.exports.win32 = win32; /***/ }), -/* 727 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -83528,7 +82226,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(607); +var isExtglob = __webpack_require__(606); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -83570,7 +82268,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 728 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83581,18 +82279,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(29); -var braces = __webpack_require__(729); -var toRegex = __webpack_require__(831); -var extend = __webpack_require__(839); +var braces = __webpack_require__(728); +var toRegex = __webpack_require__(830); +var extend = __webpack_require__(838); /** * Local dependencies */ -var compilers = __webpack_require__(842); -var parsers = __webpack_require__(874); -var cache = __webpack_require__(875); -var utils = __webpack_require__(876); +var compilers = __webpack_require__(841); +var parsers = __webpack_require__(873); +var cache = __webpack_require__(874); +var utils = __webpack_require__(875); var MAX_LENGTH = 1024 * 64; /** @@ -84454,7 +83152,7 @@ module.exports = micromatch; /***/ }), -/* 729 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84464,18 +83162,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(730); -var unique = __webpack_require__(742); -var extend = __webpack_require__(739); +var toRegex = __webpack_require__(729); +var unique = __webpack_require__(741); +var extend = __webpack_require__(738); /** * Local dependencies */ -var compilers = __webpack_require__(743); -var parsers = __webpack_require__(758); -var Braces = __webpack_require__(768); -var utils = __webpack_require__(744); +var compilers = __webpack_require__(742); +var parsers = __webpack_require__(757); +var Braces = __webpack_require__(767); +var utils = __webpack_require__(743); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -84779,15 +83477,15 @@ module.exports = braces; /***/ }), -/* 730 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(731); -var extend = __webpack_require__(739); -var not = __webpack_require__(741); +var define = __webpack_require__(730); +var extend = __webpack_require__(738); +var not = __webpack_require__(740); var MAX_LENGTH = 1024 * 64; /** @@ -84934,7 +83632,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 731 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84947,7 +83645,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(732); +var isDescriptor = __webpack_require__(731); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -84972,7 +83670,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 732 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84985,9 +83683,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(733); -var isAccessor = __webpack_require__(734); -var isData = __webpack_require__(737); +var typeOf = __webpack_require__(732); +var isAccessor = __webpack_require__(733); +var isData = __webpack_require__(736); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -85001,7 +83699,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 733 */ +/* 732 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -85154,7 +83852,7 @@ function isBuffer(val) { /***/ }), -/* 734 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85167,7 +83865,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(735); +var typeOf = __webpack_require__(734); // accessor descriptor properties var accessor = { @@ -85230,10 +83928,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 735 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(736); +var isBuffer = __webpack_require__(735); var toString = Object.prototype.toString; /** @@ -85352,7 +84050,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 736 */ +/* 735 */ /***/ (function(module, exports) { /*! @@ -85379,7 +84077,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 737 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85392,7 +84090,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(738); +var typeOf = __webpack_require__(737); // data descriptor properties var data = { @@ -85441,10 +84139,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 738 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(736); +var isBuffer = __webpack_require__(735); var toString = Object.prototype.toString; /** @@ -85563,13 +84261,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 739 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(739); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -85603,7 +84301,7 @@ function hasOwn(obj, key) { /***/ }), -/* 740 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85623,13 +84321,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 741 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(739); +var extend = __webpack_require__(738); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -85696,7 +84394,7 @@ module.exports = toRegex; /***/ }), -/* 742 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85746,13 +84444,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 743 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(744); +var utils = __webpack_require__(743); module.exports = function(braces, options) { braces.compiler @@ -86035,25 +84733,25 @@ function hasQueue(node) { /***/ }), -/* 744 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(745); +var splitString = __webpack_require__(744); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(739); -utils.flatten = __webpack_require__(751); -utils.isObject = __webpack_require__(749); -utils.fillRange = __webpack_require__(752); -utils.repeat = __webpack_require__(757); -utils.unique = __webpack_require__(742); +utils.extend = __webpack_require__(738); +utils.flatten = __webpack_require__(750); +utils.isObject = __webpack_require__(748); +utils.fillRange = __webpack_require__(751); +utils.repeat = __webpack_require__(756); +utils.unique = __webpack_require__(741); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -86385,7 +85083,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 745 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86398,7 +85096,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(746); +var extend = __webpack_require__(745); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -86563,14 +85261,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 746 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(747); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(746); +var assignSymbols = __webpack_require__(749); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -86630,7 +85328,7 @@ function isEnum(obj, key) { /***/ }), -/* 747 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86643,7 +85341,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(747); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -86651,7 +85349,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 748 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86664,7 +85362,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(748); function isObjectObject(o) { return isObject(o) === true @@ -86695,7 +85393,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 749 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86714,7 +85412,7 @@ module.exports = function isObject(val) { /***/ }), -/* 750 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86761,7 +85459,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 751 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86790,7 +85488,7 @@ function flat(arr, res) { /***/ }), -/* 752 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86804,10 +85502,10 @@ function flat(arr, res) { var util = __webpack_require__(29); -var isNumber = __webpack_require__(753); -var extend = __webpack_require__(739); -var repeat = __webpack_require__(755); -var toRegex = __webpack_require__(756); +var isNumber = __webpack_require__(752); +var extend = __webpack_require__(738); +var repeat = __webpack_require__(754); +var toRegex = __webpack_require__(755); /** * Return a range of numbers or letters. @@ -87005,7 +85703,7 @@ module.exports = fillRange; /***/ }), -/* 753 */ +/* 752 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87018,7 +85716,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(753); module.exports = function isNumber(num) { var type = typeOf(num); @@ -87034,10 +85732,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 754 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(736); +var isBuffer = __webpack_require__(735); var toString = Object.prototype.toString; /** @@ -87156,7 +85854,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 755 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87233,7 +85931,7 @@ function repeat(str, num) { /***/ }), -/* 756 */ +/* 755 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87246,8 +85944,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(755); -var isNumber = __webpack_require__(753); +var repeat = __webpack_require__(754); +var isNumber = __webpack_require__(752); var cache = {}; function toRegexRange(min, max, options) { @@ -87534,7 +86232,7 @@ module.exports = toRegexRange; /***/ }), -/* 757 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87559,14 +86257,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 758 */ +/* 757 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(759); -var utils = __webpack_require__(744); +var Node = __webpack_require__(758); +var utils = __webpack_require__(743); /** * Braces parsers @@ -87926,15 +86624,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 759 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(749); -var define = __webpack_require__(760); -var utils = __webpack_require__(767); +var isObject = __webpack_require__(748); +var define = __webpack_require__(759); +var utils = __webpack_require__(766); var ownNames; /** @@ -88425,7 +87123,7 @@ exports = module.exports = Node; /***/ }), -/* 760 */ +/* 759 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88438,7 +87136,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(761); +var isDescriptor = __webpack_require__(760); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -88463,7 +87161,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 761 */ +/* 760 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88476,9 +87174,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(762); -var isAccessor = __webpack_require__(763); -var isData = __webpack_require__(765); +var typeOf = __webpack_require__(761); +var isAccessor = __webpack_require__(762); +var isData = __webpack_require__(764); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -88492,7 +87190,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 762 */ +/* 761 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -88627,7 +87325,7 @@ function isBuffer(val) { /***/ }), -/* 763 */ +/* 762 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88640,7 +87338,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(764); +var typeOf = __webpack_require__(763); // accessor descriptor properties var accessor = { @@ -88703,7 +87401,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 764 */ +/* 763 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -88838,7 +87536,7 @@ function isBuffer(val) { /***/ }), -/* 765 */ +/* 764 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88851,7 +87549,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(766); +var typeOf = __webpack_require__(765); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -88894,7 +87592,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 766 */ +/* 765 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -89029,13 +87727,13 @@ function isBuffer(val) { /***/ }), -/* 767 */ +/* 766 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(753); var utils = module.exports; /** @@ -90055,17 +88753,17 @@ function assert(val, message) { /***/ }), -/* 768 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(739); -var Snapdragon = __webpack_require__(769); -var compilers = __webpack_require__(743); -var parsers = __webpack_require__(758); -var utils = __webpack_require__(744); +var extend = __webpack_require__(738); +var Snapdragon = __webpack_require__(768); +var compilers = __webpack_require__(742); +var parsers = __webpack_require__(757); +var utils = __webpack_require__(743); /** * Customize Snapdragon parser and renderer @@ -90166,17 +88864,17 @@ module.exports = Braces; /***/ }), -/* 769 */ +/* 768 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(770); -var define = __webpack_require__(731); -var Compiler = __webpack_require__(799); -var Parser = __webpack_require__(828); -var utils = __webpack_require__(808); +var Base = __webpack_require__(769); +var define = __webpack_require__(730); +var Compiler = __webpack_require__(798); +var Parser = __webpack_require__(827); +var utils = __webpack_require__(807); var regexCache = {}; var cache = {}; @@ -90347,20 +89045,20 @@ module.exports.Parser = Parser; /***/ }), -/* 770 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var define = __webpack_require__(771); -var CacheBase = __webpack_require__(772); -var Emitter = __webpack_require__(773); -var isObject = __webpack_require__(749); -var merge = __webpack_require__(790); -var pascal = __webpack_require__(793); -var cu = __webpack_require__(794); +var define = __webpack_require__(770); +var CacheBase = __webpack_require__(771); +var Emitter = __webpack_require__(772); +var isObject = __webpack_require__(748); +var merge = __webpack_require__(789); +var pascal = __webpack_require__(792); +var cu = __webpack_require__(793); /** * Optionally define a custom `cache` namespace to use. @@ -90789,7 +89487,7 @@ module.exports.namespace = namespace; /***/ }), -/* 771 */ +/* 770 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90802,7 +89500,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(761); +var isDescriptor = __webpack_require__(760); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -90827,21 +89525,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 772 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(749); -var Emitter = __webpack_require__(773); -var visit = __webpack_require__(774); -var toPath = __webpack_require__(777); -var union = __webpack_require__(778); -var del = __webpack_require__(782); -var get = __webpack_require__(780); -var has = __webpack_require__(787); -var set = __webpack_require__(781); +var isObject = __webpack_require__(748); +var Emitter = __webpack_require__(772); +var visit = __webpack_require__(773); +var toPath = __webpack_require__(776); +var union = __webpack_require__(777); +var del = __webpack_require__(781); +var get = __webpack_require__(779); +var has = __webpack_require__(786); +var set = __webpack_require__(780); /** * Create a `Cache` constructor that when instantiated will @@ -91095,7 +89793,7 @@ module.exports.namespace = namespace; /***/ }), -/* 773 */ +/* 772 */ /***/ (function(module, exports, __webpack_require__) { @@ -91264,7 +89962,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 774 */ +/* 773 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91277,8 +89975,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(775); -var mapVisit = __webpack_require__(776); +var visit = __webpack_require__(774); +var mapVisit = __webpack_require__(775); module.exports = function(collection, method, val) { var result; @@ -91301,7 +89999,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 775 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91314,7 +90012,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(748); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -91341,14 +90039,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 776 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var visit = __webpack_require__(775); +var visit = __webpack_require__(774); /** * Map `visit` over an array of objects. @@ -91385,7 +90083,7 @@ function isObject(val) { /***/ }), -/* 777 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91398,7 +90096,7 @@ function isObject(val) { -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(753); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -91425,16 +90123,16 @@ function filter(arr) { /***/ }), -/* 778 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(740); -var union = __webpack_require__(779); -var get = __webpack_require__(780); -var set = __webpack_require__(781); +var isObject = __webpack_require__(739); +var union = __webpack_require__(778); +var get = __webpack_require__(779); +var set = __webpack_require__(780); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -91462,7 +90160,7 @@ function arrayify(val) { /***/ }), -/* 779 */ +/* 778 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91498,7 +90196,7 @@ module.exports = function union(init) { /***/ }), -/* 780 */ +/* 779 */ /***/ (function(module, exports) { /*! @@ -91554,7 +90252,7 @@ function toString(val) { /***/ }), -/* 781 */ +/* 780 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91567,10 +90265,10 @@ function toString(val) { -var split = __webpack_require__(745); -var extend = __webpack_require__(739); -var isPlainObject = __webpack_require__(748); -var isObject = __webpack_require__(740); +var split = __webpack_require__(744); +var extend = __webpack_require__(738); +var isPlainObject = __webpack_require__(747); +var isObject = __webpack_require__(739); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -91616,7 +90314,7 @@ function isValidKey(key) { /***/ }), -/* 782 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91629,8 +90327,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(749); -var has = __webpack_require__(783); +var isObject = __webpack_require__(748); +var has = __webpack_require__(782); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -91655,7 +90353,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 783 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91668,9 +90366,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(784); -var hasValues = __webpack_require__(786); -var get = __webpack_require__(780); +var isObject = __webpack_require__(783); +var hasValues = __webpack_require__(785); +var get = __webpack_require__(779); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -91681,7 +90379,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 784 */ +/* 783 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91694,7 +90392,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(785); +var isArray = __webpack_require__(784); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -91702,7 +90400,7 @@ module.exports = function isObject(val) { /***/ }), -/* 785 */ +/* 784 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -91713,7 +90411,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 786 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91756,7 +90454,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 787 */ +/* 786 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91769,9 +90467,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(749); -var hasValues = __webpack_require__(788); -var get = __webpack_require__(780); +var isObject = __webpack_require__(748); +var hasValues = __webpack_require__(787); +var get = __webpack_require__(779); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -91779,7 +90477,7 @@ module.exports = function(val, prop) { /***/ }), -/* 788 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91792,8 +90490,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(789); -var isNumber = __webpack_require__(753); +var typeOf = __webpack_require__(788); +var isNumber = __webpack_require__(752); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -91846,10 +90544,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 789 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(736); +var isBuffer = __webpack_require__(735); var toString = Object.prototype.toString; /** @@ -91971,14 +90669,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 790 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(791); -var forIn = __webpack_require__(792); +var isExtendable = __webpack_require__(790); +var forIn = __webpack_require__(791); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -92042,7 +90740,7 @@ module.exports = mixinDeep; /***/ }), -/* 791 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92055,7 +90753,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(747); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -92063,7 +90761,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 792 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92086,7 +90784,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 793 */ +/* 792 */ /***/ (function(module, exports) { /*! @@ -92113,14 +90811,14 @@ module.exports = pascalcase; /***/ }), -/* 794 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var utils = __webpack_require__(795); +var utils = __webpack_require__(794); /** * Expose class utils @@ -92485,7 +91183,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 795 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92499,10 +91197,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(779); -utils.define = __webpack_require__(731); -utils.isObj = __webpack_require__(749); -utils.staticExtend = __webpack_require__(796); +utils.union = __webpack_require__(778); +utils.define = __webpack_require__(730); +utils.isObj = __webpack_require__(748); +utils.staticExtend = __webpack_require__(795); /** @@ -92513,7 +91211,7 @@ module.exports = utils; /***/ }), -/* 796 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92526,8 +91224,8 @@ module.exports = utils; -var copy = __webpack_require__(797); -var define = __webpack_require__(731); +var copy = __webpack_require__(796); +var define = __webpack_require__(730); var util = __webpack_require__(29); /** @@ -92610,15 +91308,15 @@ module.exports = extend; /***/ }), -/* 797 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(754); -var copyDescriptor = __webpack_require__(798); -var define = __webpack_require__(731); +var typeOf = __webpack_require__(753); +var copyDescriptor = __webpack_require__(797); +var define = __webpack_require__(730); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -92791,7 +91489,7 @@ module.exports.has = has; /***/ }), -/* 798 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92879,16 +91577,16 @@ function isObject(val) { /***/ }), -/* 799 */ +/* 798 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(800); -var define = __webpack_require__(731); -var debug = __webpack_require__(802)('snapdragon:compiler'); -var utils = __webpack_require__(808); +var use = __webpack_require__(799); +var define = __webpack_require__(730); +var debug = __webpack_require__(801)('snapdragon:compiler'); +var utils = __webpack_require__(807); /** * Create a new `Compiler` with the given `options`. @@ -93042,7 +91740,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(827); + var sourcemaps = __webpack_require__(826); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -93063,7 +91761,7 @@ module.exports = Compiler; /***/ }), -/* 800 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -93076,7 +91774,7 @@ module.exports = Compiler; -var utils = __webpack_require__(801); +var utils = __webpack_require__(800); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -93191,7 +91889,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 801 */ +/* 800 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -93205,8 +91903,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(731); -utils.isObject = __webpack_require__(749); +utils.define = __webpack_require__(730); +utils.isObject = __webpack_require__(748); utils.isString = function(val) { @@ -93221,7 +91919,7 @@ module.exports = utils; /***/ }), -/* 802 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -93230,14 +91928,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(803); + module.exports = __webpack_require__(802); } else { - module.exports = __webpack_require__(806); + module.exports = __webpack_require__(805); } /***/ }), -/* 803 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -93246,7 +91944,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(804); +exports = module.exports = __webpack_require__(803); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -93428,7 +92126,7 @@ function localstorage() { /***/ }), -/* 804 */ +/* 803 */ /***/ (function(module, exports, __webpack_require__) { @@ -93444,7 +92142,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(805); +exports.humanize = __webpack_require__(804); /** * The currently active debug mode names, and names to skip. @@ -93636,7 +92334,7 @@ function coerce(val) { /***/ }), -/* 805 */ +/* 804 */ /***/ (function(module, exports) { /** @@ -93794,7 +92492,7 @@ function plural(ms, n, name) { /***/ }), -/* 806 */ +/* 805 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -93810,7 +92508,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(804); +exports = module.exports = __webpack_require__(803); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -93989,7 +92687,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(807); + var net = __webpack_require__(806); stream = new net.Socket({ fd: fd, readable: false, @@ -94048,13 +92746,13 @@ exports.enable(load()); /***/ }), -/* 807 */ +/* 806 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 808 */ +/* 807 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -94064,9 +92762,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(739); -exports.SourceMap = __webpack_require__(809); -exports.sourceMapResolve = __webpack_require__(820); +exports.extend = __webpack_require__(738); +exports.SourceMap = __webpack_require__(808); +exports.sourceMapResolve = __webpack_require__(819); /** * Convert backslash in the given string to forward slashes @@ -94109,7 +92807,7 @@ exports.last = function(arr, n) { /***/ }), -/* 809 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -94117,13 +92815,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(810).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(816).SourceMapConsumer; -exports.SourceNode = __webpack_require__(819).SourceNode; +exports.SourceMapGenerator = __webpack_require__(809).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(815).SourceMapConsumer; +exports.SourceNode = __webpack_require__(818).SourceNode; /***/ }), -/* 810 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94133,10 +92831,10 @@ exports.SourceNode = __webpack_require__(819).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(811); -var util = __webpack_require__(813); -var ArraySet = __webpack_require__(814).ArraySet; -var MappingList = __webpack_require__(815).MappingList; +var base64VLQ = __webpack_require__(810); +var util = __webpack_require__(812); +var ArraySet = __webpack_require__(813).ArraySet; +var MappingList = __webpack_require__(814).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -94545,7 +93243,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 811 */ +/* 810 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94585,7 +93283,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(812); +var base64 = __webpack_require__(811); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -94691,7 +93389,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 812 */ +/* 811 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94764,7 +93462,7 @@ exports.decode = function (charCode) { /***/ }), -/* 813 */ +/* 812 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95187,7 +93885,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 814 */ +/* 813 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95197,7 +93895,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(813); +var util = __webpack_require__(812); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -95314,7 +94012,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 815 */ +/* 814 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95324,7 +94022,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(813); +var util = __webpack_require__(812); /** * Determine whether mappingB is after mappingA with respect to generated @@ -95399,7 +94097,7 @@ exports.MappingList = MappingList; /***/ }), -/* 816 */ +/* 815 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95409,11 +94107,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(813); -var binarySearch = __webpack_require__(817); -var ArraySet = __webpack_require__(814).ArraySet; -var base64VLQ = __webpack_require__(811); -var quickSort = __webpack_require__(818).quickSort; +var util = __webpack_require__(812); +var binarySearch = __webpack_require__(816); +var ArraySet = __webpack_require__(813).ArraySet; +var base64VLQ = __webpack_require__(810); +var quickSort = __webpack_require__(817).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -96487,7 +95185,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 817 */ +/* 816 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -96604,7 +95302,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 818 */ +/* 817 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -96724,7 +95422,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 819 */ +/* 818 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -96734,8 +95432,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(810).SourceMapGenerator; -var util = __webpack_require__(813); +var SourceMapGenerator = __webpack_require__(809).SourceMapGenerator; +var util = __webpack_require__(812); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -97143,17 +95841,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 820 */ +/* 819 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(821) -var resolveUrl = __webpack_require__(822) -var decodeUriComponent = __webpack_require__(823) -var urix = __webpack_require__(825) -var atob = __webpack_require__(826) +var sourceMappingURL = __webpack_require__(820) +var resolveUrl = __webpack_require__(821) +var decodeUriComponent = __webpack_require__(822) +var urix = __webpack_require__(824) +var atob = __webpack_require__(825) @@ -97451,7 +96149,7 @@ module.exports = { /***/ }), -/* 821 */ +/* 820 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -97514,7 +96212,7 @@ void (function(root, factory) { /***/ }), -/* 822 */ +/* 821 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -97532,13 +96230,13 @@ module.exports = resolveUrl /***/ }), -/* 823 */ +/* 822 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(824) +var decodeUriComponent = __webpack_require__(823) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -97549,7 +96247,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 824 */ +/* 823 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97650,7 +96348,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 825 */ +/* 824 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -97673,7 +96371,7 @@ module.exports = urix /***/ }), -/* 826 */ +/* 825 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97687,7 +96385,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 827 */ +/* 826 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97695,8 +96393,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(23); var path = __webpack_require__(16); -var define = __webpack_require__(731); -var utils = __webpack_require__(808); +var define = __webpack_require__(730); +var utils = __webpack_require__(807); /** * Expose `mixin()`. @@ -97839,19 +96537,19 @@ exports.comment = function(node) { /***/ }), -/* 828 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(800); +var use = __webpack_require__(799); var util = __webpack_require__(29); -var Cache = __webpack_require__(829); -var define = __webpack_require__(731); -var debug = __webpack_require__(802)('snapdragon:parser'); -var Position = __webpack_require__(830); -var utils = __webpack_require__(808); +var Cache = __webpack_require__(828); +var define = __webpack_require__(730); +var debug = __webpack_require__(801)('snapdragon:parser'); +var Position = __webpack_require__(829); +var utils = __webpack_require__(807); /** * Create a new `Parser` with the given `input` and `options`. @@ -98379,7 +97077,7 @@ module.exports = Parser; /***/ }), -/* 829 */ +/* 828 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98486,13 +97184,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 830 */ +/* 829 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(731); +var define = __webpack_require__(730); /** * Store position for a node @@ -98507,16 +97205,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 831 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(832); -var define = __webpack_require__(838); -var extend = __webpack_require__(839); -var not = __webpack_require__(841); +var safe = __webpack_require__(831); +var define = __webpack_require__(837); +var extend = __webpack_require__(838); +var not = __webpack_require__(840); var MAX_LENGTH = 1024 * 64; /** @@ -98669,10 +97367,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 832 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(833); +var parse = __webpack_require__(832); var types = parse.types; module.exports = function (re, opts) { @@ -98718,13 +97416,13 @@ function isRegExp (x) { /***/ }), -/* 833 */ +/* 832 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(834); -var types = __webpack_require__(835); -var sets = __webpack_require__(836); -var positions = __webpack_require__(837); +var util = __webpack_require__(833); +var types = __webpack_require__(834); +var sets = __webpack_require__(835); +var positions = __webpack_require__(836); module.exports = function(regexpStr) { @@ -99006,11 +97704,11 @@ module.exports.types = types; /***/ }), -/* 834 */ +/* 833 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(835); -var sets = __webpack_require__(836); +var types = __webpack_require__(834); +var sets = __webpack_require__(835); // All of these are private and only used by randexp. @@ -99123,7 +97821,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 835 */ +/* 834 */ /***/ (function(module, exports) { module.exports = { @@ -99139,10 +97837,10 @@ module.exports = { /***/ }), -/* 836 */ +/* 835 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(835); +var types = __webpack_require__(834); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -99227,10 +97925,10 @@ exports.anyChar = function() { /***/ }), -/* 837 */ +/* 836 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(835); +var types = __webpack_require__(834); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -99250,7 +97948,7 @@ exports.end = function() { /***/ }), -/* 838 */ +/* 837 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99263,8 +97961,8 @@ exports.end = function() { -var isobject = __webpack_require__(749); -var isDescriptor = __webpack_require__(761); +var isobject = __webpack_require__(748); +var isDescriptor = __webpack_require__(760); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -99295,14 +97993,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 839 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(840); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(839); +var assignSymbols = __webpack_require__(749); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -99362,7 +98060,7 @@ function isEnum(obj, key) { /***/ }), -/* 840 */ +/* 839 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99375,7 +98073,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(747); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -99383,14 +98081,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 841 */ +/* 840 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(839); -var safe = __webpack_require__(832); +var extend = __webpack_require__(838); +var safe = __webpack_require__(831); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -99462,14 +98160,14 @@ module.exports = toRegex; /***/ }), -/* 842 */ +/* 841 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(843); -var extglob = __webpack_require__(858); +var nanomatch = __webpack_require__(842); +var extglob = __webpack_require__(857); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -99546,7 +98244,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 843 */ +/* 842 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99557,17 +98255,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(730); -var extend = __webpack_require__(844); +var toRegex = __webpack_require__(729); +var extend = __webpack_require__(843); /** * Local dependencies */ -var compilers = __webpack_require__(846); -var parsers = __webpack_require__(847); -var cache = __webpack_require__(850); -var utils = __webpack_require__(852); +var compilers = __webpack_require__(845); +var parsers = __webpack_require__(846); +var cache = __webpack_require__(849); +var utils = __webpack_require__(851); var MAX_LENGTH = 1024 * 64; /** @@ -100391,14 +99089,14 @@ module.exports = nanomatch; /***/ }), -/* 844 */ +/* 843 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(845); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(844); +var assignSymbols = __webpack_require__(749); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -100458,7 +99156,7 @@ function isEnum(obj, key) { /***/ }), -/* 845 */ +/* 844 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100471,7 +99169,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(747); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -100479,7 +99177,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 846 */ +/* 845 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100825,15 +99523,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 847 */ +/* 846 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(741); -var toRegex = __webpack_require__(730); -var isOdd = __webpack_require__(848); +var regexNot = __webpack_require__(740); +var toRegex = __webpack_require__(729); +var isOdd = __webpack_require__(847); /** * Characters to use in negation regex (we want to "not" match @@ -101219,7 +99917,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 848 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101232,7 +99930,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(849); +var isNumber = __webpack_require__(848); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -101246,7 +99944,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 849 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101274,14 +99972,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 850 */ +/* 849 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(851))(); +module.exports = new (__webpack_require__(850))(); /***/ }), -/* 851 */ +/* 850 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101294,7 +99992,7 @@ module.exports = new (__webpack_require__(851))(); -var MapCache = __webpack_require__(829); +var MapCache = __webpack_require__(828); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -101416,7 +100114,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 852 */ +/* 851 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101429,14 +100127,14 @@ var path = __webpack_require__(16); * Module dependencies */ -var isWindows = __webpack_require__(853)(); -var Snapdragon = __webpack_require__(769); -utils.define = __webpack_require__(854); -utils.diff = __webpack_require__(855); -utils.extend = __webpack_require__(844); -utils.pick = __webpack_require__(856); -utils.typeOf = __webpack_require__(857); -utils.unique = __webpack_require__(742); +var isWindows = __webpack_require__(852)(); +var Snapdragon = __webpack_require__(768); +utils.define = __webpack_require__(853); +utils.diff = __webpack_require__(854); +utils.extend = __webpack_require__(843); +utils.pick = __webpack_require__(855); +utils.typeOf = __webpack_require__(856); +utils.unique = __webpack_require__(741); /** * Returns true if the given value is effectively an empty string @@ -101802,7 +100500,7 @@ utils.unixify = function(options) { /***/ }), -/* 853 */ +/* 852 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -101830,7 +100528,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 854 */ +/* 853 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101843,8 +100541,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(749); -var isDescriptor = __webpack_require__(761); +var isobject = __webpack_require__(748); +var isDescriptor = __webpack_require__(760); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -101875,7 +100573,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 855 */ +/* 854 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101929,7 +100627,7 @@ function diffArray(one, two) { /***/ }), -/* 856 */ +/* 855 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101942,7 +100640,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(748); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -101971,7 +100669,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 857 */ +/* 856 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -102106,7 +100804,7 @@ function isBuffer(val) { /***/ }), -/* 858 */ +/* 857 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102116,18 +100814,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(739); -var unique = __webpack_require__(742); -var toRegex = __webpack_require__(730); +var extend = __webpack_require__(738); +var unique = __webpack_require__(741); +var toRegex = __webpack_require__(729); /** * Local dependencies */ -var compilers = __webpack_require__(859); -var parsers = __webpack_require__(870); -var Extglob = __webpack_require__(873); -var utils = __webpack_require__(872); +var compilers = __webpack_require__(858); +var parsers = __webpack_require__(869); +var Extglob = __webpack_require__(872); +var utils = __webpack_require__(871); var MAX_LENGTH = 1024 * 64; /** @@ -102444,13 +101142,13 @@ module.exports = extglob; /***/ }), -/* 859 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(860); +var brackets = __webpack_require__(859); /** * Extglob compilers @@ -102620,7 +101318,7 @@ module.exports = function(extglob) { /***/ }), -/* 860 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102630,17 +101328,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(861); -var parsers = __webpack_require__(863); +var compilers = __webpack_require__(860); +var parsers = __webpack_require__(862); /** * Module dependencies */ -var debug = __webpack_require__(865)('expand-brackets'); -var extend = __webpack_require__(739); -var Snapdragon = __webpack_require__(769); -var toRegex = __webpack_require__(730); +var debug = __webpack_require__(864)('expand-brackets'); +var extend = __webpack_require__(738); +var Snapdragon = __webpack_require__(768); +var toRegex = __webpack_require__(729); /** * Parses the given POSIX character class `pattern` and returns a @@ -102838,13 +101536,13 @@ module.exports = brackets; /***/ }), -/* 861 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(862); +var posix = __webpack_require__(861); module.exports = function(brackets) { brackets.compiler @@ -102932,7 +101630,7 @@ module.exports = function(brackets) { /***/ }), -/* 862 */ +/* 861 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102961,14 +101659,14 @@ module.exports = { /***/ }), -/* 863 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(864); -var define = __webpack_require__(731); +var utils = __webpack_require__(863); +var define = __webpack_require__(730); /** * Text regex @@ -103187,14 +101885,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 864 */ +/* 863 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(730); -var regexNot = __webpack_require__(741); +var toRegex = __webpack_require__(729); +var regexNot = __webpack_require__(740); var cached; /** @@ -103228,7 +101926,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 865 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -103237,14 +101935,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(866); + module.exports = __webpack_require__(865); } else { - module.exports = __webpack_require__(869); + module.exports = __webpack_require__(868); } /***/ }), -/* 866 */ +/* 865 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -103253,7 +101951,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(867); +exports = module.exports = __webpack_require__(866); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -103435,7 +102133,7 @@ function localstorage() { /***/ }), -/* 867 */ +/* 866 */ /***/ (function(module, exports, __webpack_require__) { @@ -103451,7 +102149,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(868); +exports.humanize = __webpack_require__(867); /** * The currently active debug mode names, and names to skip. @@ -103643,7 +102341,7 @@ function coerce(val) { /***/ }), -/* 868 */ +/* 867 */ /***/ (function(module, exports) { /** @@ -103801,7 +102499,7 @@ function plural(ms, n, name) { /***/ }), -/* 869 */ +/* 868 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -103817,7 +102515,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(867); +exports = module.exports = __webpack_require__(866); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -103996,7 +102694,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(807); + var net = __webpack_require__(806); stream = new net.Socket({ fd: fd, readable: false, @@ -104055,15 +102753,15 @@ exports.enable(load()); /***/ }), -/* 870 */ +/* 869 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(860); -var define = __webpack_require__(871); -var utils = __webpack_require__(872); +var brackets = __webpack_require__(859); +var define = __webpack_require__(870); +var utils = __webpack_require__(871); /** * Characters to use in text regex (we want to "not" match @@ -104218,7 +102916,7 @@ module.exports = parsers; /***/ }), -/* 871 */ +/* 870 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104231,7 +102929,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(761); +var isDescriptor = __webpack_require__(760); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -104256,14 +102954,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 872 */ +/* 871 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(741); -var Cache = __webpack_require__(851); +var regex = __webpack_require__(740); +var Cache = __webpack_require__(850); /** * Utils @@ -104332,7 +103030,7 @@ utils.createRegex = function(str) { /***/ }), -/* 873 */ +/* 872 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104342,16 +103040,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(769); -var define = __webpack_require__(871); -var extend = __webpack_require__(739); +var Snapdragon = __webpack_require__(768); +var define = __webpack_require__(870); +var extend = __webpack_require__(738); /** * Local dependencies */ -var compilers = __webpack_require__(859); -var parsers = __webpack_require__(870); +var compilers = __webpack_require__(858); +var parsers = __webpack_require__(869); /** * Customize Snapdragon parser and renderer @@ -104417,16 +103115,16 @@ module.exports = Extglob; /***/ }), -/* 874 */ +/* 873 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(858); -var nanomatch = __webpack_require__(843); -var regexNot = __webpack_require__(741); -var toRegex = __webpack_require__(831); +var extglob = __webpack_require__(857); +var nanomatch = __webpack_require__(842); +var regexNot = __webpack_require__(740); +var toRegex = __webpack_require__(830); var not; /** @@ -104507,14 +103205,14 @@ function textRegex(pattern) { /***/ }), -/* 875 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(851))(); +module.exports = new (__webpack_require__(850))(); /***/ }), -/* 876 */ +/* 875 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104527,13 +103225,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(769); -utils.define = __webpack_require__(838); -utils.diff = __webpack_require__(855); -utils.extend = __webpack_require__(839); -utils.pick = __webpack_require__(856); -utils.typeOf = __webpack_require__(877); -utils.unique = __webpack_require__(742); +var Snapdragon = __webpack_require__(768); +utils.define = __webpack_require__(837); +utils.diff = __webpack_require__(854); +utils.extend = __webpack_require__(838); +utils.pick = __webpack_require__(855); +utils.typeOf = __webpack_require__(876); +utils.unique = __webpack_require__(741); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -104830,7 +103528,7 @@ utils.unixify = function(options) { /***/ }), -/* 877 */ +/* 876 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -104965,7 +103663,7 @@ function isBuffer(val) { /***/ }), -/* 878 */ +/* 877 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104984,9 +103682,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(879); -var reader_1 = __webpack_require__(892); -var fs_stream_1 = __webpack_require__(896); +var readdir = __webpack_require__(878); +var reader_1 = __webpack_require__(891); +var fs_stream_1 = __webpack_require__(895); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -105047,15 +103745,15 @@ exports.default = ReaderAsync; /***/ }), -/* 879 */ +/* 878 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(880); -const readdirAsync = __webpack_require__(888); -const readdirStream = __webpack_require__(891); +const readdirSync = __webpack_require__(879); +const readdirAsync = __webpack_require__(887); +const readdirStream = __webpack_require__(890); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -105139,7 +103837,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 880 */ +/* 879 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105147,11 +103845,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(881); +const DirectoryReader = __webpack_require__(880); let syncFacade = { - fs: __webpack_require__(886), - forEach: __webpack_require__(887), + fs: __webpack_require__(885), + forEach: __webpack_require__(886), sync: true }; @@ -105180,7 +103878,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 881 */ +/* 880 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105189,9 +103887,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(27).Readable; const EventEmitter = __webpack_require__(379).EventEmitter; const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(882); -const stat = __webpack_require__(884); -const call = __webpack_require__(885); +const normalizeOptions = __webpack_require__(881); +const stat = __webpack_require__(883); +const call = __webpack_require__(884); /** * Asynchronously reads the contents of a directory and streams the results @@ -105567,14 +104265,14 @@ module.exports = DirectoryReader; /***/ }), -/* 882 */ +/* 881 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(883); +const globToRegExp = __webpack_require__(882); module.exports = normalizeOptions; @@ -105751,7 +104449,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 883 */ +/* 882 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -105888,13 +104586,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 884 */ +/* 883 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(885); +const call = __webpack_require__(884); module.exports = stat; @@ -105969,7 +104667,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 885 */ +/* 884 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106030,14 +104728,14 @@ function callOnce (fn) { /***/ }), -/* 886 */ +/* 885 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(885); +const call = __webpack_require__(884); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -106101,7 +104799,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 887 */ +/* 886 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106130,7 +104828,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 888 */ +/* 887 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106138,12 +104836,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(889); -const DirectoryReader = __webpack_require__(881); +const maybe = __webpack_require__(888); +const DirectoryReader = __webpack_require__(880); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(890), + forEach: __webpack_require__(889), async: true }; @@ -106185,7 +104883,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 889 */ +/* 888 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106212,7 +104910,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 890 */ +/* 889 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106248,7 +104946,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 891 */ +/* 890 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106256,11 +104954,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(881); +const DirectoryReader = __webpack_require__(880); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(890), + forEach: __webpack_require__(889), async: true }; @@ -106280,16 +104978,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 892 */ +/* 891 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(893); -var entry_1 = __webpack_require__(895); -var pathUtil = __webpack_require__(894); +var deep_1 = __webpack_require__(892); +var entry_1 = __webpack_require__(894); +var pathUtil = __webpack_require__(893); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -106355,14 +105053,14 @@ exports.default = Reader; /***/ }), -/* 893 */ +/* 892 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(894); -var patternUtils = __webpack_require__(723); +var pathUtils = __webpack_require__(893); +var patternUtils = __webpack_require__(722); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -106445,7 +105143,7 @@ exports.default = DeepFilter; /***/ }), -/* 894 */ +/* 893 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106476,14 +105174,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 895 */ +/* 894 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(894); -var patternUtils = __webpack_require__(723); +var pathUtils = __webpack_require__(893); +var patternUtils = __webpack_require__(722); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -106568,7 +105266,7 @@ exports.default = EntryFilter; /***/ }), -/* 896 */ +/* 895 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106588,8 +105286,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var fsStat = __webpack_require__(897); -var fs_1 = __webpack_require__(901); +var fsStat = __webpack_require__(896); +var fs_1 = __webpack_require__(900); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -106639,14 +105337,14 @@ exports.default = FileSystemStream; /***/ }), -/* 897 */ +/* 896 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(898); -const statProvider = __webpack_require__(900); +const optionsManager = __webpack_require__(897); +const statProvider = __webpack_require__(899); /** * Asynchronous API. */ @@ -106677,13 +105375,13 @@ exports.statSync = statSync; /***/ }), -/* 898 */ +/* 897 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(899); +const fsAdapter = __webpack_require__(898); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -106696,7 +105394,7 @@ exports.prepare = prepare; /***/ }), -/* 899 */ +/* 898 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106719,7 +105417,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 900 */ +/* 899 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106771,7 +105469,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 901 */ +/* 900 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106802,7 +105500,7 @@ exports.default = FileSystem; /***/ }), -/* 902 */ +/* 901 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106822,9 +105520,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var readdir = __webpack_require__(879); -var reader_1 = __webpack_require__(892); -var fs_stream_1 = __webpack_require__(896); +var readdir = __webpack_require__(878); +var reader_1 = __webpack_require__(891); +var fs_stream_1 = __webpack_require__(895); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -106892,7 +105590,7 @@ exports.default = ReaderStream; /***/ }), -/* 903 */ +/* 902 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106911,9 +105609,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(879); -var reader_1 = __webpack_require__(892); -var fs_sync_1 = __webpack_require__(904); +var readdir = __webpack_require__(878); +var reader_1 = __webpack_require__(891); +var fs_sync_1 = __webpack_require__(903); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -106973,7 +105671,7 @@ exports.default = ReaderSync; /***/ }), -/* 904 */ +/* 903 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106992,8 +105690,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(897); -var fs_1 = __webpack_require__(901); +var fsStat = __webpack_require__(896); +var fs_1 = __webpack_require__(900); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -107039,7 +105737,7 @@ exports.default = FileSystemSync; /***/ }), -/* 905 */ +/* 904 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107055,13 +105753,13 @@ exports.flatten = flatten; /***/ }), -/* 906 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(591); +var merge2 = __webpack_require__(590); /** * Merge multiple streams and propagate their errors into one stream in parallel. */ @@ -107076,13 +105774,13 @@ exports.merge = merge; /***/ }), -/* 907 */ +/* 906 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(908); +const pathType = __webpack_require__(907); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -107148,13 +105846,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 908 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(909); +const pify = __webpack_require__(908); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -107197,7 +105895,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 909 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107288,17 +105986,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 910 */ +/* 909 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(719); -const gitIgnore = __webpack_require__(911); -const pify = __webpack_require__(912); -const slash = __webpack_require__(913); +const fastGlob = __webpack_require__(718); +const gitIgnore = __webpack_require__(910); +const pify = __webpack_require__(911); +const slash = __webpack_require__(912); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -107396,7 +106094,7 @@ module.exports.sync = options => { /***/ }), -/* 911 */ +/* 910 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -107865,7 +106563,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 912 */ +/* 911 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107940,7 +106638,7 @@ module.exports = (input, options) => { /***/ }), -/* 913 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107958,17 +106656,17 @@ module.exports = input => { /***/ }), -/* 914 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const pEvent = __webpack_require__(915); -const CpFileError = __webpack_require__(918); -const fs = __webpack_require__(922); -const ProgressEmitter = __webpack_require__(925); +const pEvent = __webpack_require__(914); +const CpFileError = __webpack_require__(917); +const fs = __webpack_require__(921); +const ProgressEmitter = __webpack_require__(924); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -108082,12 +106780,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 915 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(916); +const pTimeout = __webpack_require__(915); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -108378,12 +107076,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 916 */ +/* 915 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(917); +const pFinally = __webpack_require__(916); class TimeoutError extends Error { constructor(message) { @@ -108429,7 +107127,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 917 */ +/* 916 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108451,12 +107149,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 918 */ +/* 917 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(919); +const NestedError = __webpack_require__(918); class CpFileError extends NestedError { constructor(message, nested) { @@ -108470,10 +107168,10 @@ module.exports = CpFileError; /***/ }), -/* 919 */ +/* 918 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(920); +var inherits = __webpack_require__(919); var NestedError = function (message, nested) { this.nested = nested; @@ -108524,7 +107222,7 @@ module.exports = NestedError; /***/ }), -/* 920 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -108532,12 +107230,12 @@ try { if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { - module.exports = __webpack_require__(921); + module.exports = __webpack_require__(920); } /***/ }), -/* 921 */ +/* 920 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -108566,16 +107264,16 @@ if (typeof Object.create === 'function') { /***/ }), -/* 922 */ +/* 921 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const fs = __webpack_require__(22); -const makeDir = __webpack_require__(923); -const pEvent = __webpack_require__(915); -const CpFileError = __webpack_require__(918); +const makeDir = __webpack_require__(922); +const pEvent = __webpack_require__(914); +const CpFileError = __webpack_require__(917); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -108672,7 +107370,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 923 */ +/* 922 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108680,7 +107378,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(23); const path = __webpack_require__(16); const {promisify} = __webpack_require__(29); -const semver = __webpack_require__(924); +const semver = __webpack_require__(923); const defaults = { mode: 0o777 & (~process.umask()), @@ -108829,7 +107527,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 924 */ +/* 923 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -110431,7 +109129,7 @@ function coerce (version, options) { /***/ }), -/* 925 */ +/* 924 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -110472,7 +109170,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 926 */ +/* 925 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -110518,12 +109216,12 @@ exports.default = module.exports; /***/ }), -/* 927 */ +/* 926 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(928); +const NestedError = __webpack_require__(927); class CpyError extends NestedError { constructor(message, nested) { @@ -110537,7 +109235,7 @@ module.exports = CpyError; /***/ }), -/* 928 */ +/* 927 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -110593,7 +109291,7 @@ module.exports = NestedError; /***/ }), -/* 929 */ +/* 928 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; diff --git a/packages/kbn-test/package.json b/packages/kbn-test/package.json index 0cc54fa2a64c4..a01c4ebab8ad0 100644 --- a/packages/kbn-test/package.json +++ b/packages/kbn-test/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "private": true, "scripts": { - "build": "babel src --out-dir target --delete-dir-on-start --extensions .ts,.js,.tsx --ignore *.test.js,**/__tests__/**", + "build": "babel src --out-dir target --delete-dir-on-start --extensions .ts,.js,.tsx --ignore *.test.js,**/__tests__/** --source-maps=inline", "kbn:bootstrap": "yarn build", "kbn:watch": "yarn build --watch" }, diff --git a/packages/kbn-test/src/failed_tests_reporter/test_report.ts b/packages/kbn-test/src/failed_tests_reporter/test_report.ts index 6b759ef1d4c62..43d84163462d3 100644 --- a/packages/kbn-test/src/failed_tests_reporter/test_report.ts +++ b/packages/kbn-test/src/failed_tests_reporter/test_report.ts @@ -47,7 +47,7 @@ export interface TestSuite { /* number of skipped tests as a string */ skipped: string; }; - testcase: TestCase[]; + testcase?: TestCase[]; } export interface TestCase { @@ -89,7 +89,7 @@ export function* makeTestCaseIter(report: TestReport) { const testSuites = 'testsuites' in report ? report.testsuites.testsuite : [report.testsuite]; for (const testSuite of testSuites) { - for (const testCase of testSuite.testcase) { + for (const testCase of testSuite.testcase || []) { yield testCase; } } diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 0b1a31619fdf9..4b4db9d7f37f3 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@elastic/charts": "^17.0.2", "abort-controller": "^3.0.0", - "@elastic/eui": "18.3.0", + "@elastic/eui": "19.0.0", "@kbn/dev-utils": "1.0.0", "@kbn/i18n": "1.0.0", "@yarnpkg/lockfile": "^1.1.0", diff --git a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js index 247290731df57..749dad377f2e2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js @@ -24,7 +24,7 @@ import { mergeOtherBucketAggResponse, updateMissingBucket, } from '../../buckets/_terms_other_bucket_helper'; -import { Vis } from '../../../../../../../core_plugins/visualizations/public'; +import { start as visualizationsStart } from '../../../../../../../core_plugins/visualizations/public/np_ready/public/legacy'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; const visConfigSingleTerm = { @@ -191,7 +191,7 @@ describe('Terms Agg Other bucket helper', () => { ngMock.inject(Private => { const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - vis = new Vis(indexPattern, aggConfig); + vis = new visualizationsStart.Vis(indexPattern, aggConfig); }); } diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts index 40ef7329dee6b..1dc24ca80035c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts @@ -20,21 +20,19 @@ import { get } from 'lodash'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { convertDateRangeToString, DateRangeKey } from './lib/date_range'; import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; +export { convertDateRangeToString, DateRangeKey }; + const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { defaultMessage: 'Date Range', }); -export interface DateRangeKey { - from: number; - to: number; -} - export const dateRangeBucketAgg = new BucketAggType({ name: BUCKET_TYPES.DATE_RANGE, title: dateRangeTitle, @@ -106,16 +104,3 @@ export const dateRangeBucketAgg = new BucketAggType({ }, ], }); - -export const convertDateRangeToString = ( - { from, to }: DateRangeKey, - format: (val: any) => string -) => { - if (!from) { - return 'Before ' + format(to); - } else if (!to) { - return 'After ' + format(from); - } else { - return format(from) + ' to ' + format(to); - } -}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts index e5497bef49165..91bdf53e7f809 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -20,21 +20,19 @@ import { noop, map, omit, isNull } from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { IpRangeKey, convertIPRangeToString } from './lib/ip_range'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; // @ts-ignore import { createFilterIpRange } from './create_filter/ip_range'; import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; +export { IpRangeKey, convertIPRangeToString }; const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', }); -export type IpRangeKey = - | { type: 'mask'; mask: string } - | { type: 'range'; from: string; to: string }; - export const ipRangeBucketAgg = new BucketAggType({ name: BUCKET_TYPES.IP_RANGE, title: ipRangeTitle, @@ -97,13 +95,3 @@ export const ipRangeBucketAgg = new BucketAggType({ }, ], }); - -export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { - if (range.type === 'mask') { - return format(range.mask); - } - const from = range.from ? format(range.from) : '-Infinity'; - const to = range.to ? format(range.to) : 'Infinity'; - - return `${from} to ${to}`; -}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts new file mode 100644 index 0000000000000..01b853fc669b5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts @@ -0,0 +1,36 @@ +/* + * 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 interface DateRangeKey { + from: number; + to: number; +} + +export const convertDateRangeToString = ( + { from, to }: DateRangeKey, + format: (val: any) => string +) => { + if (!from) { + return 'Before ' + format(to); + } else if (!to) { + return 'After ' + format(from); + } else { + return format(from) + ' to ' + format(to); + } +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts new file mode 100644 index 0000000000000..be1ac28934c7c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts @@ -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. + */ + +export type IpRangeKey = + | { type: 'mask'; mask: string } + | { type: 'range'; from: string; to: string }; + +export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { + if (range.type === 'mask') { + return format(range.mask); + } + const from = range.from ? format(range.from) : '-Infinity'; + const to = range.to ? format(range.to) : 'Infinity'; + + return `${from} to ${to}`; +}; diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index ea81193c1dd0a..8e6bae0b588bc 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -77,6 +77,7 @@ export default function(kibana) { order: -1003, url: `${kbnBaseUrl}#/discover`, euiIconType: 'discoverApp', + disableSubUrlTracking: true, category: DEFAULT_APP_CATEGORIES.analyze, }, { @@ -87,6 +88,7 @@ export default function(kibana) { order: -1002, url: `${kbnBaseUrl}#/visualize`, euiIconType: 'visualizeApp', + disableSubUrlTracking: true, category: DEFAULT_APP_CATEGORIES.analyze, }, { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts index fa5354a17b6d9..fe7beafcad18c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts @@ -165,7 +165,7 @@ export class DashboardStateManager { // make sure url ('_a') matches initial state this.kbnUrlStateStorage.set(this.STATE_STORAGE_KEY, initialState, { replace: true }); - // setup state syncing utils. state container will be synched with url into `this.STATE_STORAGE_KEY` query param + // setup state syncing utils. state container will be synced with url into `this.STATE_STORAGE_KEY` query param this.stateSyncRef = syncState({ storageKey: this.STATE_STORAGE_KEY, stateContainer: { @@ -173,10 +173,20 @@ export class DashboardStateManager { set: (state: DashboardAppState | null) => { // sync state required state container to be able to handle null // overriding set() so it could handle null coming from url - this.stateContainer.set({ - ...this.stateDefaults, - ...state, - }); + if (state) { + this.stateContainer.set({ + ...this.stateDefaults, + ...state, + }); + } else { + // Do nothing in case when state from url is empty, + // this fixes: https://github.com/elastic/kibana/issues/57789 + // There are not much cases when state in url could become empty: + // 1. User manually removed `_a` from the url + // 2. Browser is navigating away from the page and most likely there is no `_a` in the url. + // In this case we don't want to do any state updates + // and just allow $scope.$on('destroy') fire later and clean up everything + } }, }, stateStorage: this.kbnUrlStateStorage, diff --git a/src/legacy/core_plugins/kibana/public/discover/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/build_services.ts index f9265323b2dcb..81f1c911f1cc9 100644 --- a/src/legacy/core_plugins/kibana/public/discover/build_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/build_services.ts @@ -36,6 +36,7 @@ import { SharePluginStart } from '../../../../../plugins/share/public'; import { SavedSearch } from './np_ready/types'; import { DocViewsRegistry } from './np_ready/doc_views/doc_views_registry'; import { ChartsPluginStart } from '../../../../../plugins/charts/public'; +import { VisualizationsStart } from '../../../visualizations/public'; export interface DiscoverServices { addBasePath: (path: string) => string; @@ -56,6 +57,7 @@ export interface DiscoverServices { getSavedSearchById: (id: string) => Promise; getSavedSearchUrlById: (id: string) => Promise; uiSettings: IUiSettingsClient; + visualizations: VisualizationsStart; } export async function buildServices( core: CoreStart, @@ -89,5 +91,6 @@ export async function buildServices( timefilter: plugins.data.query.timefilter.timefilter, toastNotifications: core.notifications.toasts, uiSettings: core.uiSettings, + visualizations: plugins.visualizations, }; } diff --git a/src/legacy/core_plugins/kibana/public/discover/legacy.ts b/src/legacy/core_plugins/kibana/public/discover/legacy.ts index ff44fbbe115d5..a1ef646f4fe85 100644 --- a/src/legacy/core_plugins/kibana/public/discover/legacy.ts +++ b/src/legacy/core_plugins/kibana/public/discover/legacy.ts @@ -20,10 +20,18 @@ import { PluginInitializerContext } from 'kibana/public'; import { npSetup, npStart } from 'ui/new_platform'; import { plugin } from './index'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../../../core_plugins/visualizations/public/np_ready/public/legacy'; // Legacy compatibility part - to be removed at cutover, replaced by a kibana.json file export const pluginInstance = plugin({} as PluginInitializerContext); export const setup = pluginInstance.setup(npSetup.core, { ...npSetup.plugins, + visualizations: visualizationsSetup, +}); +export const start = pluginInstance.start(npStart.core, { + ...npStart.plugins, + visualizations: visualizationsStart, }); -export const start = pluginInstance.start(npStart.core, npStart.plugins); diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap index 98cb3ccf6dd91..4126bd9d27ffd 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap @@ -77,12 +77,8 @@ Array [

- - + + 200 @@ -101,12 +97,8 @@ Array [
- - + + status:200 @@ -125,12 +117,8 @@ Array [
- - + + status:[400 TO 499] @@ -149,12 +137,8 @@ Array [
- - + + status:[400 TO 499] AND extension:PHP @@ -173,12 +157,8 @@ Array [
- - + + status:[400 TO 499] AND (extension:php OR extension:html) @@ -291,15 +271,9 @@ Array [
-
-
-              
+          
+
+              
                 {"reason":"Awful error"}
               
             
@@ -320,15 +294,9 @@ Array [
-
-
-              
+          
+
+              
                 {"reason":"Bad error"}
               
             
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx index 77bbab97d95c7..8db3c77ba0f47 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx @@ -41,7 +41,7 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { EuiChartThemeType } from '@elastic/eui/src/themes/charts/themes'; +import { EuiChartThemeType } from '@elastic/eui/dist/eui_charts_theme'; import { Subscription } from 'rxjs'; import { getServices, timezoneProvider } from '../../../kibana_services'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js index 7de792c612993..98a4a926a282e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js @@ -36,6 +36,31 @@ jest.mock('../../../kibana_services', () => { }; }); +// Mocking to prevent errors with React portal. +// Temporary until https://github.com/elastic/kibana/pull/55877 provides other alternatives. +jest.mock('@elastic/eui/lib/components/code/code_block', () => { + const React = require.requireActual('react'); + return { + EuiCodeBlock: ({ children }) => ( +
+
+          {children}
+        
+
+ ), + }; +}); +jest.mock('@elastic/eui/lib/components/code/code', () => { + const React = require.requireActual('react'); + return { + EuiCode: ({ children }) => ( + + {children} + + ), + }; +}); + beforeEach(() => { jest.clearAllMocks(); }); diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index 39a9ca6641fd1..bf5049cd976a3 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -60,7 +60,6 @@ import { ensureDefaultIndexPattern, registerTimefilterWithGlobalStateFactory, } from '../../kibana_services'; -import { Vis } from '../../../../../visualizations/public'; const { core, @@ -71,6 +70,7 @@ const { timefilter, toastNotifications, uiSettings, + visualizations, } = getServices(); import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs'; @@ -990,7 +990,10 @@ function discoverController( }, }; - $scope.vis = new Vis($scope.searchSource.getField('index'), visSavedObject.visState); + $scope.vis = new visualizations.Vis( + $scope.searchSource.getField('index'), + visSavedObject.visState + ); visSavedObject.vis = $scope.vis; $scope.searchSource.onRequestStart((searchSource, options) => { diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index a495b56d5e9ea..e8ded9d99f892 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -16,11 +16,17 @@ * specific language governing permissions and limitations * under the License. */ + +import { BehaviorSubject } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'kibana/public'; import angular, { auto } from 'angular'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { + DataPublicPluginStart, + DataPublicPluginSetup, + getQueryStateContainer, +} from '../../../../../plugins/data/public'; import { registerFeature } from './np_ready/register_feature'; import './kibana_services'; import { IEmbeddableStart, IEmbeddableSetup } from '../../../../../plugins/embeddable/public'; @@ -30,12 +36,20 @@ import { NavigationPublicPluginStart as NavigationStart } from '../../../../../p import { ChartsPluginStart } from '../../../../../plugins/charts/public'; import { buildServices } from './build_services'; import { SharePluginStart } from '../../../../../plugins/share/public'; -import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public'; +import { + KibanaLegacySetup, + AngularRenderedAppUpdater, +} from '../../../../../plugins/kibana_legacy/public'; import { DocViewsRegistry } from './np_ready/doc_views/doc_views_registry'; import { DocViewInput, DocViewInputFn } from './np_ready/doc_views/doc_views_types'; import { DocViewTable } from './np_ready/components/table/table'; import { JsonCodeBlock } from './np_ready/components/json_code_block/json_code_block'; import { HomePublicPluginSetup } from '../../../../../plugins/home/public'; +import { + VisualizationsStart, + VisualizationsSetup, +} from '../../../visualizations/public/np_ready/public'; +import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public'; /** * These are the interfaces with your public contracts. You should export these @@ -51,6 +65,8 @@ export interface DiscoverSetupPlugins { embeddable: IEmbeddableSetup; kibanaLegacy: KibanaLegacySetup; home: HomePublicPluginSetup; + visualizations: VisualizationsSetup; + data: DataPublicPluginSetup; } export interface DiscoverStartPlugins { uiActions: UiActionsStart; @@ -60,6 +76,7 @@ export interface DiscoverStartPlugins { data: DataPublicPluginStart; share: SharePluginStart; inspector: any; + visualizations: VisualizationsStart; } const innerAngularName = 'app/discover'; const embeddableAngularName = 'app/discoverEmbeddable'; @@ -75,6 +92,9 @@ export class DiscoverPlugin implements Plugin { private docViewsRegistry: DocViewsRegistry | null = null; private embeddableInjector: auto.IInjectorService | null = null; private getEmbeddableInjector: (() => Promise) | null = null; + private appStateUpdater = new BehaviorSubject(() => ({})); + private stopUrlTracking: (() => void) | undefined = undefined; + /** * why are those functions public? they are needed for some mocha tests * can be removed once all is Jest @@ -83,6 +103,27 @@ export class DiscoverPlugin implements Plugin { public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>; setup(core: CoreSetup, plugins: DiscoverSetupPlugins): DiscoverSetup { + const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( + plugins.data.query + ); + const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ + baseUrl: core.http.basePath.prepend('/app/kibana'), + defaultSubUrl: '#/discover', + storageKey: 'lastUrl:discover', + navLinkUpdater$: this.appStateUpdater, + toastNotifications: core.notifications.toasts, + stateParams: [ + { + kbnUrlKey: '_g', + stateUpdate$: querySyncStateContainer.state$, + }, + ], + }); + this.stopUrlTracking = () => { + stopQuerySyncStateContainer(); + stopUrlTracker(); + }; + this.getEmbeddableInjector = this.getInjector.bind(this); this.docViewsRegistry = new DocViewsRegistry(this.getEmbeddableInjector); this.docViewsRegistry.addDocView({ @@ -102,6 +143,8 @@ export class DiscoverPlugin implements Plugin { plugins.kibanaLegacy.registerLegacyApp({ id: 'discover', title: 'Discover', + updater$: this.appStateUpdater.asObservable(), + navLinkId: 'kibana:discover', order: -1004, euiIconType: 'discoverApp', mount: async (params: AppMountParameters) => { @@ -111,11 +154,16 @@ export class DiscoverPlugin implements Plugin { if (!this.initializeInnerAngular) { throw Error('Discover plugin method initializeInnerAngular is undefined'); } + appMounted(); await this.initializeServices(); await this.initializeInnerAngular(); const { renderApp } = await import('./np_ready/application'); - return renderApp(innerAngularName, params.element); + const unmount = await renderApp(innerAngularName, params.element); + return () => { + unmount(); + appUnMounted(); + }; }, }); registerFeature(plugins.home); @@ -154,6 +202,12 @@ export class DiscoverPlugin implements Plugin { this.registerEmbeddable(core, plugins); } + stop() { + if (this.stopUrlTracking) { + this.stopUrlTracking(); + } + } + /** * register embeddable with a slimmer embeddable version of inner angular */ diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index 6082fb8428ac3..096877d5824c4 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -35,7 +35,6 @@ import { DataPublicPluginStart, IndexPatternsContract } from '../../../../../plu import { VisualizationsStart } from '../../../visualizations/public'; import { SavedVisualizations } from './np_ready/types'; import { UsageCollectionSetup } from '../../../../../plugins/usage_collection/public'; -import { Chrome } from './legacy_imports'; import { KibanaLegacyStart } from '../../../../../plugins/kibana_legacy/public'; export interface VisualizeKibanaServices { @@ -47,7 +46,6 @@ export interface VisualizeKibanaServices { embeddable: IEmbeddableStart; getBasePath: () => string; indexPatterns: IndexPatternsContract; - legacyChrome: Chrome; localStorage: Storage; navigation: NavigationStart; toastNotifications: ToastsStart; @@ -61,6 +59,7 @@ export interface VisualizeKibanaServices { visualizations: VisualizationsStart; usageCollection?: UsageCollectionSetup; I18nContext: I18nStart['Context']; + setActiveUrl: (newUrl: string) => void; } let services: VisualizeKibanaServices | null = null; diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy.ts index bc2d700f6c6a1..fbbc7ab944daf 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy.ts @@ -18,19 +18,14 @@ */ import { PluginInitializerContext } from 'kibana/public'; -import { legacyChrome, npSetup, npStart } from './legacy_imports'; +import { npSetup, npStart } from 'ui/new_platform'; import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy'; import { plugin } from './index'; const instance = plugin({ env: npSetup.plugins.kibanaLegacy.env, } as PluginInitializerContext); -instance.setup(npSetup.core, { - ...npSetup.plugins, - __LEGACY: { - legacyChrome, - }, -}); +instance.setup(npSetup.core, npSetup.plugins); instance.start(npStart.core, { ...npStart.plugins, visualizations, diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index ac9fc227406ff..92433799ba420 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -24,11 +24,6 @@ * directly where they are needed. */ -import chrome from 'ui/chrome'; - -export const legacyChrome = chrome; -export { Chrome } from 'ui/chrome'; - // @ts-ignore export { AppState, AppStateProvider } from 'ui/state_management/app_state'; export { State } from 'ui/state_management/state'; @@ -39,8 +34,6 @@ export { StateManagementConfigProvider } from 'ui/state_management/config_provid export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory'; export { PersistedState } from 'ui/persisted_state'; -export { npSetup, npStart } from 'ui/new_platform'; - export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore export { EventsProvider } from 'ui/events'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts index 3d5fd6605f56b..bd7b478f827a6 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts @@ -45,7 +45,7 @@ import { VisualizeKibanaServices } from '../kibana_services'; let angularModuleInstance: IModule | null = null; -export const renderApp = async ( +export const renderApp = ( element: HTMLElement, appBasePath: string, deps: VisualizeKibanaServices @@ -58,7 +58,6 @@ export const renderApp = async ( { core: deps.core, env: deps.pluginInitializerContext.env }, true ); - // custom routing stuff initVisualizeApp(angularModuleInstance, deps); } const $injector = mountVisualizeApp(appBasePath, element); diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 27fb9b63843c4..409d4b41fbe69 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -90,13 +90,13 @@ function VisualizeAppController( }, }, toastNotifications, - legacyChrome, chrome, getBasePath, core: { docLinks }, savedQueryService, uiSettings, I18nContext, + setActiveUrl, } = getServices(); const filterStateManager = new FilterStateManager(globalState, getAppState, filterManager); @@ -441,14 +441,6 @@ function VisualizeAppController( }) ); - subscriptions.add( - subscribeWithScope($scope, timefilter.getAutoRefreshFetch$(), { - next: () => { - $scope.vis.forceReload(); - }, - }) - ); - $scope.$on('$destroy', () => { if ($scope._handler) { $scope._handler.destroy(); @@ -588,10 +580,7 @@ function VisualizeAppController( }); // Manually insert a new url so the back button will open the saved visualization. $window.history.pushState({}, '', savedVisualizationParsedUrl.getRootRelativePath()); - // Since we aren't reloading the page, only inserting a new browser history item, we need to manually update - // the last url for this app, so directly clicking on the Visualize tab will also bring the user to the saved - // url, not the unsaved one. - legacyChrome.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl); + setActiveUrl(savedVisualizationParsedUrl.appPath); const lastDashboardAbsoluteUrl = chrome.navLinks.get('kibana:dashboard').url; const dashboardParsedUrl = absoluteToParsedUrl( diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js index cae1e40cd445a..c0cc499b598f0 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js @@ -36,7 +36,6 @@ export function VisualizeListingController($injector, $scope, createNewVis) { const { addBasePath, chrome, - legacyChrome, savedObjectsClient, savedVisualizations, data: { @@ -100,17 +99,13 @@ export function VisualizeListingController($injector, $scope, createNewVis) { selectedItems.map(item => { return savedObjectsClient.delete(item.savedObjectType, item.id); }) - ) - .then(() => { - legacyChrome.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id)); - }) - .catch(error => { - toastNotifications.addError(error, { - title: i18n.translate('kbn.visualize.visualizeListingDeleteErrorTitle', { - defaultMessage: 'Error deleting visualization', - }), - }); + ).catch(error => { + toastNotifications.addError(error, { + title: i18n.translate('kbn.visualize.visualizeListingDeleteErrorTitle', { + defaultMessage: 'Error deleting visualization', + }), }); + }); }; chrome.setBreadcrumbs([ diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts index 16715677d1e20..22804685db3cc 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts @@ -17,6 +17,7 @@ * under the License. */ +import { BehaviorSubject } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { @@ -28,12 +29,19 @@ import { SavedObjectsClientContract, } from 'kibana/public'; -import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { DataPublicPluginStart } from '../../../../../plugins/data/public'; +import { Storage, createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public'; +import { + DataPublicPluginStart, + DataPublicPluginSetup, + getQueryStateContainer, +} from '../../../../../plugins/data/public'; import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { SharePluginStart } from '../../../../../plugins/share/public'; -import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public'; +import { + KibanaLegacySetup, + AngularRenderedAppUpdater, +} from '../../../../../plugins/kibana_legacy/public'; import { VisualizationsStart } from '../../../visualizations/public'; import { VisualizeConstants } from './np_ready/visualize_constants'; import { setServices, VisualizeKibanaServices } from './kibana_services'; @@ -42,7 +50,6 @@ import { HomePublicPluginSetup, } from '../../../../../plugins/home/public'; import { UsageCollectionSetup } from '../../../../../plugins/usage_collection/public'; -import { Chrome } from './legacy_imports'; export interface VisualizePluginStartDependencies { data: DataPublicPluginStart; @@ -53,12 +60,10 @@ export interface VisualizePluginStartDependencies { } export interface VisualizePluginSetupDependencies { - __LEGACY: { - legacyChrome: Chrome; - }; home: HomePublicPluginSetup; kibanaLegacy: KibanaLegacySetup; usageCollection?: UsageCollectionSetup; + data: DataPublicPluginSetup; } export class VisualizePlugin implements Plugin { @@ -70,46 +75,72 @@ export class VisualizePlugin implements Plugin { share: SharePluginStart; visualizations: VisualizationsStart; } | null = null; + private appStateUpdater = new BehaviorSubject(() => ({})); + private stopUrlTracking: (() => void) | undefined = undefined; constructor(private initializerContext: PluginInitializerContext) {} public async setup( core: CoreSetup, - { home, kibanaLegacy, __LEGACY, usageCollection }: VisualizePluginSetupDependencies + { home, kibanaLegacy, usageCollection, data }: VisualizePluginSetupDependencies ) { + const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( + data.query + ); + const { appMounted, appUnMounted, stop: stopUrlTracker, setActiveUrl } = createKbnUrlTracker({ + baseUrl: core.http.basePath.prepend('/app/kibana'), + defaultSubUrl: '#/visualize', + storageKey: 'lastUrl:visualize', + navLinkUpdater$: this.appStateUpdater, + toastNotifications: core.notifications.toasts, + stateParams: [ + { + kbnUrlKey: '_g', + stateUpdate$: querySyncStateContainer.state$, + }, + ], + }); + this.stopUrlTracking = () => { + stopQuerySyncStateContainer(); + stopUrlTracker(); + }; + kibanaLegacy.registerLegacyApp({ id: 'visualize', title: 'Visualize', + updater$: this.appStateUpdater.asObservable(), + navLinkId: 'kibana:visualize', mount: async (params: AppMountParameters) => { const [coreStart] = await core.getStartServices(); + if (this.startDependencies === null) { throw new Error('not started yet'); } + appMounted(); const { savedObjectsClient, embeddable, navigation, visualizations, - data, + data: dataStart, share, } = this.startDependencies; const deps: VisualizeKibanaServices = { - ...__LEGACY, pluginInitializerContext: this.initializerContext, addBasePath: coreStart.http.basePath.prepend, core: coreStart, chrome: coreStart.chrome, - data, + data: dataStart, embeddable, getBasePath: core.http.basePath.get, - indexPatterns: data.indexPatterns, + indexPatterns: dataStart.indexPatterns, localStorage: new Storage(localStorage), navigation, savedObjectsClient, savedVisualizations: visualizations.getSavedVisualizationsLoader(), - savedQueryService: data.query.savedQueries, + savedQueryService: dataStart.query.savedQueries, share, toastNotifications: coreStart.notifications.toasts, uiSettings: coreStart.uiSettings, @@ -118,11 +149,16 @@ export class VisualizePlugin implements Plugin { visualizations, usageCollection, I18nContext: coreStart.i18n.Context, + setActiveUrl, }; setServices(deps); const { renderApp } = await import('./np_ready/application'); - return renderApp(params.element, params.appBasePath, deps); + const unmount = renderApp(params.element, params.appBasePath, deps); + return () => { + unmount(); + appUnMounted(); + }; }, }); @@ -153,4 +189,10 @@ export class VisualizePlugin implements Plugin { visualizations, }; } + + stop() { + if (this.stopUrlTracking) { + this.stopUrlTracking(); + } + } } diff --git a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js index 55447905e6421..f11aab9b9db88 100644 --- a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js @@ -38,8 +38,10 @@ import afterdatachangePng from './afterdatachange.png'; import afterdatachangeandresizePng from './afterdatachangeandresize.png'; import aftercolorchangePng from './aftercolorchange.png'; import changestartupPng from './changestartup.png'; -import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy'; -import { Vis } from '../../../visualizations/public/np_ready/public/vis'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../../visualizations/public/np_ready/public/legacy'; import { createRegionMapVisualization } from '../region_map_visualization'; import { createRegionMapTypeDefinition } from '../region_map_type'; @@ -158,7 +160,7 @@ describe('RegionMapsVisualizationTests', function() { imageComparator = new ImageComparator(); - vis = new Vis(indexPattern, { + vis = new visualizationsStart.Vis(indexPattern, { type: 'region_map', }); diff --git a/src/legacy/core_plugins/telemetry/server/collection_manager.ts b/src/legacy/core_plugins/telemetry/server/collection_manager.ts index 933c249cd7279..0394dea343adf 100644 --- a/src/legacy/core_plugins/telemetry/server/collection_manager.ts +++ b/src/legacy/core_plugins/telemetry/server/collection_manager.ts @@ -41,8 +41,8 @@ export interface StatsCollectionConfig { usageCollection: UsageCollectionSetup; callCluster: CallCluster; server: any; - start: string; - end: string; + start: string | number; + end: string | number; } export type StatsGetterConfig = UnencryptedStatsGetterConfig | EncryptedStatsGetterConfig; @@ -193,7 +193,7 @@ export class TelemetryCollectionManager { } } catch (err) { statsCollectionConfig.server.log( - ['debu', 'telemetry', 'collection'], + ['debug', 'telemetry', 'collection'], `Failed to collect any usage with registered collections.` ); // swallow error to try next collection; diff --git a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js index ef2ea831e84fd..27e9459c7e06c 100644 --- a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js @@ -32,8 +32,10 @@ import EMS_TILES from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_ import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_bright'; import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated'; import EMS_STYLE_DARK_MAP from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_dark'; -import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy'; -import { Vis } from '../../../visualizations/public/np_ready/public/vis'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../../visualizations/public/np_ready/public/legacy'; import { createTileMapVisualization } from '../tile_map_visualization'; import { createTileMapTypeDefinition } from '../tile_map_type'; @@ -124,7 +126,7 @@ describe('CoordinateMapsVisualizationTest', function() { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new Vis(indexPattern, { + vis = new visualizationsStart.Vis(indexPattern, { type: 'tile_map', }); vis.params = { diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx index 32c99f68a066e..6a466c9cd0211 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx @@ -22,6 +22,10 @@ import { shallow } from 'enzyme'; import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { MetricVisComponent, MetricVisComponentProps } from './metric_vis_component'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { npStart } from 'ui/new_platform'; +import { fieldFormats } from '../../../../../plugins/data/public'; +import { identity } from 'lodash'; jest.mock('ui/new_platform'); @@ -62,6 +66,12 @@ describe('MetricVisComponent', function() { return shallow(); }; + beforeAll(() => { + (npStart.plugins.data.fieldFormats.deserialize as jest.Mock).mockImplementation(() => { + return new (fieldFormats.FieldFormat.from(identity))(); + }); + }); + it('should render component', () => { expect(getComponent().exists()).toBe(true); }); diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 28565e0181b84..67b5d018f4638 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -44,6 +44,9 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { (npStart.plugins.data.fieldFormats.getType as jest.Mock).mockImplementation(() => { return fieldFormats.UrlFormat; }); + (npStart.plugins.data.fieldFormats.deserialize as jest.Mock).mockImplementation(mapping => { + return new fieldFormats.UrlFormat(mapping ? mapping.params : {}); + }); }); const setup = () => { @@ -56,7 +59,7 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { // TODO: remove when Vis is converted to typescript. Only importing Vis as type // @ts-ignore - vis = new Vis(stubIndexPattern, { + vis = new visualizationsStart.Vis(stubIndexPattern, { type: 'metric', aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], }); diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js index fc5a24a66dab3..0dbff60613cb0 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js +++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js @@ -26,10 +26,11 @@ import sinon from 'sinon'; import { tabifyAggResponse, npStart } from '../../legacy_imports'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import { round } from 'lodash'; - -import { Vis } from '../../../../visualizations/public'; import { tableVisTypeDefinition } from '../../table_vis_type'; -import { setup as visualizationsSetup } from '../../../../visualizations/public/np_ready/public/legacy'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../../../visualizations/public/np_ready/public/legacy'; import { getAngularModule } from '../../get_inner_angular'; import { initTableVisLegacyModule } from '../../table_vis_legacy_module'; import { tableVisResponseHandler } from '../../table_vis_response_handler'; @@ -42,10 +43,10 @@ describe('Table Vis - AggTable Directive', function() { const tabifiedData = {}; const init = () => { - const vis1 = new Vis(indexPattern, 'table'); + const vis1 = new visualizationsStart.Vis(indexPattern, 'table'); tabifiedData.metricOnly = tabifyAggResponse(vis1.aggs, fixtures.metricOnly); - const vis2 = new Vis(indexPattern, { + const vis2 = new visualizationsStart.Vis(indexPattern, { type: 'table', params: { showMetricsAtAllLevels: true, @@ -64,7 +65,7 @@ describe('Table Vis - AggTable Directive', function() { metricsAtAllLevels: true, }); - const vis3 = new Vis(indexPattern, { + const vis3 = new visualizationsStart.Vis(indexPattern, { type: 'table', aggs: [ { type: 'avg', schema: 'metric', params: { field: 'bytes' } }, diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js index 3c633f21cbabb..f6ae41b024b7d 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js +++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js @@ -23,10 +23,10 @@ import expect from '@kbn/expect'; import fixtures from 'fixtures/fake_hierarchical_data'; import { tabifyAggResponse, npStart } from '../../legacy_imports'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { Vis } from '../../../../visualizations/public'; import { getAngularModule } from '../../get_inner_angular'; import { initTableVisLegacyModule } from '../../table_vis_legacy_module'; import { tableVisResponseHandler } from '../../table_vis_response_handler'; +import { start as visualizationsStart } from '../../../../visualizations/public/np_ready/public/legacy'; describe('Table Vis - AggTableGroup Directive', function() { let $rootScope; @@ -35,10 +35,10 @@ describe('Table Vis - AggTableGroup Directive', function() { const tabifiedData = {}; const init = () => { - const vis1 = new Vis(indexPattern, 'table'); + const vis1 = new visualizationsStart.Vis(indexPattern, 'table'); tabifiedData.metricOnly = tabifyAggResponse(vis1.aggs, fixtures.metricOnly); - const vis2 = new Vis(indexPattern, { + const vis2 = new visualizationsStart.Vis(indexPattern, { type: 'pie', aggs: [ { type: 'avg', schema: 'metric', params: { field: 'bytes' } }, diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js index 5f7d1ad90ecf8..55ecf98f994d2 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js @@ -20,7 +20,7 @@ import expect from '@kbn/expect'; import ngMock from 'ng_mock'; import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { Vis } from '../../../../visualizations/public/np_ready/public/vis'; +import { start as visualizationsStart } from '../../../../../core_plugins/visualizations/public/np_ready/public/legacy'; import { ImageComparator } from 'test_utils/image_comparator'; import { createTagCloudVisualization } from '../tag_cloud_visualization'; import basicdrawPng from './basicdraw.png'; @@ -76,7 +76,7 @@ describe('TagCloudVisualizationTest', function() { beforeEach(async function() { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new Vis(indexPattern, { + vis = new visualizationsStart.Vis(indexPattern, { type: 'tagcloud', params: { bucket: { accessor: 0, format: {} }, diff --git a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js index 868e5729bd494..378590af29d3a 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js +++ b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js @@ -23,7 +23,6 @@ import ngMock from 'ng_mock'; import $ from 'jquery'; import { createVegaVisualization } from '../vega_visualization'; import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { Vis } from '../../../visualizations/public/np_ready/public/vis'; import { ImageComparator } from 'test_utils/image_comparator'; import vegaliteGraph from '!!raw-loader!./vegalite_graph.hjson'; @@ -41,7 +40,10 @@ import vegaMapImage256 from './vega_map_image_256.png'; import { VegaParser } from '../data_model/vega_parser'; import { SearchCache } from '../data_model/search_cache'; -import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../../visualizations/public/np_ready/public/legacy'; import { createVegaTypeDefinition } from '../vega_type'; // TODO This is an integration test and thus requires a running platform. When moving to the new platform, // this test has to be migrated to the newly created integration test environment. @@ -106,7 +108,7 @@ describe('VegaVisualizations', () => { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new Vis(indexPattern, { type: 'vega' }); + vis = new visualizationsStart.Vis(indexPattern, { type: 'vega' }); }); afterEach(function() { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts index 3d04c04f9b1a6..9c79be98a320c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts @@ -18,10 +18,11 @@ */ export { AggType, AggGroupNames, IAggConfig, IAggType, Schemas } from 'ui/agg_types'; -export { getFormat, getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; +export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; // @ts-ignore export { tabifyAggResponse } from 'ui/agg_response/tabify'; // @ts-ignore export { buildHierarchicalData } from 'ui/agg_response/hierarchical/build_hierarchical_data'; // @ts-ignore export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series'; +export { tabifyGetColumns } from '../../../ui/public/agg_response/tabify/_get_columns'; diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js index e4da572259b69..534a523103774 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js @@ -25,7 +25,7 @@ import expect from '@kbn/expect'; import fixtures from 'fixtures/fake_hierarchical_data'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { Vis } from '../../../../../visualizations/public'; +import { start as visualizationsStart } from '../../../../../visualizations/public/np_ready/public/legacy'; import { getVis, getMockUiState } from '../lib/fixtures/_vis_fixture'; import { tabifyAggResponse } from '../../../legacy_imports'; import { vislibSlicesResponseHandler } from '../../response_handler'; @@ -133,7 +133,7 @@ describe('No global chart settings', function() { responseHandler = vislibSlicesResponseHandler; let id1 = 1; - stubVis1 = new Vis(indexPattern, { + stubVis1 = new visualizationsStart.Vis(indexPattern, { type: 'pie', aggs: rowAgg, }); @@ -222,7 +222,7 @@ describe('Vislib PieChart Class Test Suite', function() { responseHandler = vislibSlicesResponseHandler; let id = 1; - stubVis = new Vis(indexPattern, { + stubVis = new visualizationsStart.Vis(indexPattern, { type: 'pie', aggs: dataAgg, }); diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index a170af33583df..c1563625c3b8c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -22,14 +22,24 @@ import { compact, uniq, map } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keyCodes, htmlIdGenerator } from '@elastic/eui'; +import { IAggConfig } from '../../../../../data/public'; // @ts-ignore -// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { createFiltersFromEvent } from '../../../../../data/public/actions/filters/create_filters_from_event'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; import { VisLegendItem } from './legend_item'; import { getPieNames } from './pie_utils'; -import { getTableAggs } from '../../../legacy_imports'; + +import { Vis } from '../../../../../visualizations/public'; +import { tabifyGetColumns } from '../../../legacy_imports'; + +const getTableAggs = (vis: Vis): IAggConfig[] => { + if (!vis.aggs || !vis.aggs.getResponseAggs) { + return []; + } + const columns = tabifyGetColumns(vis.aggs.getResponseAggs(), !vis.isHierarchical()); + return columns.map(c => c.aggConfig); +}; export interface VisLegendProps { vis: any; diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts index 5e593398333c9..fddcf70c30605 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -34,6 +34,7 @@ import { esFilters, Filter, ISearchSource, + TimefilterContract, } from '../../../../../plugins/data/public'; import { EmbeddableInput, @@ -106,8 +107,10 @@ export class VisualizeEmbeddable extends Embeddable { this.handleChanges(); @@ -345,6 +352,7 @@ export class VisualizeEmbeddable extends Embeddable { diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index 03471174753fa..2f00467a85cda 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -38,6 +38,7 @@ import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { getCapabilities, getHttp, getTypes, getUISettings } from '../np_ready/public/services'; import { showNewVisModal } from '../np_ready/public/wizard'; +import { TimefilterContract } from '../../../../../plugins/data/public'; interface VisualizationAttributes extends SavedObjectAttributes { visState: string; @@ -51,7 +52,10 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< > { public readonly type = VISUALIZE_EMBEDDABLE_TYPE; - constructor(private getSavedVisualizationsLoader: () => SavedVisualizations) { + constructor( + private timefilter: TimefilterContract, + private getSavedVisualizationsLoader: () => SavedVisualizations + ) { super({ savedObjectMetaData: { name: i18n.translate('visualizations.savedObjectName', { defaultMessage: 'Visualization' }), @@ -114,6 +118,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< const indexPattern = await getIndexPattern(savedObject); const indexPatterns = indexPattern ? [indexPattern] : []; return new VisualizeEmbeddable( + this.timefilter, { savedVisualization: savedObject, indexPatterns, diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js index d963315ef79db..8c75ba24051b0 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js @@ -20,7 +20,6 @@ import _ from 'lodash'; import ngMock from 'ng_mock'; import expect from '@kbn/expect'; -import { Vis } from '../..'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import { start as visualizations } from '../../legacy'; @@ -49,7 +48,7 @@ describe('Vis Class', function() { ); beforeEach(function() { - vis = new Vis(indexPattern, stateFixture); + vis = new visualizations.Vis(indexPattern, stateFixture); }); const verifyVis = function(vis) { @@ -85,7 +84,7 @@ describe('Vis Class', function() { describe('setState()', function() { it('should set the state to defaults', function() { - const vis = new Vis(indexPattern); + const vis = new visualizations.Vis(indexPattern); expect(vis).to.have.property('type'); expect(vis.type).to.eql(visTypes.get('histogram')); expect(vis).to.have.property('aggs'); @@ -101,7 +100,7 @@ describe('Vis Class', function() { expect(vis.isHierarchical()).to.be(true); }); it('should return false for non-hierarchical vis (like histogram)', function() { - const vis = new Vis(indexPattern); + const vis = new visualizations.Vis(indexPattern); expect(vis.isHierarchical()).to.be(false); }); }); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts index 1063b1718b851..9fb87cadb2983 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts @@ -49,12 +49,14 @@ const createStartContract = (): VisualizationsStart => ({ }, getSavedVisualizationsLoader: jest.fn(), showNewVisModal: jest.fn(), + Vis: jest.fn(), }); const createInstance = async () => { const plugin = new VisualizationsPlugin({} as PluginInitializerContext); const setup = plugin.setup(coreMock.createSetup(), { + data: dataPluginMock.createSetupContract(), expressions: expressionsPluginMock.createSetupContract(), embeddable: embeddablePluginMock.createStartContract(), usageCollection: usageCollectionPluginMock.createSetupContract(), diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index cbbeb7ff980a6..20bed59faad88 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -36,13 +36,17 @@ import { ExpressionsSetup } from '../../../../../../plugins/expressions/public'; import { IEmbeddableSetup } from '../../../../../../plugins/embeddable/public'; import { visualization as visualizationFunction } from './expressions/visualization_function'; import { visualization as visualizationRenderer } from './expressions/visualization_renderer'; -import { DataPublicPluginStart } from '../../../../../../plugins/data/public'; +import { + DataPublicPluginSetup, + DataPublicPluginStart, +} from '../../../../../../plugins/data/public'; import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection/public'; import { createSavedVisLoader, SavedObjectKibanaServicesWithVisualizations, } from '../../saved_visualizations'; import { SavedVisualizations } from '../../../../kibana/public/visualize/np_ready/types'; +import { VisImpl, VisImplConstructor } from './vis_impl'; import { showNewVisModal } from './wizard'; /** * Interface for this plugin's returned setup/start contracts. @@ -57,12 +61,14 @@ export interface VisualizationsStart { types: TypesStart; getSavedVisualizationsLoader: () => SavedVisualizations; showNewVisModal: typeof showNewVisModal; + Vis: VisImplConstructor; } export interface VisualizationsSetupDeps { expressions: ExpressionsSetup; embeddable: IEmbeddableSetup; usageCollection: UsageCollectionSetup; + data: DataPublicPluginSetup; } export interface VisualizationsStartDeps { @@ -93,7 +99,7 @@ export class VisualizationsPlugin public setup( core: CoreSetup, - { expressions, embeddable, usageCollection }: VisualizationsSetupDeps + { expressions, embeddable, usageCollection, data }: VisualizationsSetupDeps ): VisualizationsSetup { setUISettings(core.uiSettings); setUsageCollector(usageCollection); @@ -101,7 +107,10 @@ export class VisualizationsPlugin expressions.registerFunction(visualizationFunction); expressions.registerRenderer(visualizationRenderer); - const embeddableFactory = new VisualizeEmbeddableFactory(this.getSavedVisualizationsLoader); + const embeddableFactory = new VisualizeEmbeddableFactory( + data.query.timefilter.timefilter, + this.getSavedVisualizationsLoader + ); embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory); return { @@ -131,6 +140,7 @@ export class VisualizationsPlugin types, getSavedVisualizationsLoader: () => this.getSavedVisualizationsLoader(), showNewVisModal, + Vis: VisImpl, }; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts similarity index 84% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts index 71bf9bcf983ff..59a8013523ef6 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts @@ -42,9 +42,8 @@ export interface VisState { aggs: IAggConfigs; } -export declare class VisualizationController { - constructor(element: HTMLElement, vis: Vis); - public render(visData: any, visParams: any, update: { [key in Status]: boolean }): Promise; - public destroy(): void; - public isLoaded?(): Promise | void; +export interface VisualizationController { + render(visData: any, visParams: any, update: { [key in Status]: boolean }): Promise; + destroy(): void; + isLoaded?(): Promise | void; } diff --git a/src/plugins/ui_actions/public/triggers/get_trigger.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts similarity index 50% rename from src/plugins/ui_actions/public/triggers/get_trigger.test.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts index 88dd5a8990c9d..45d65efb5dcdf 100644 --- a/src/plugins/ui_actions/public/triggers/get_trigger.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts @@ -17,32 +17,28 @@ * under the License. */ -import { createApi } from '../api'; -import { createDeps } from '../tests/helpers'; +import { Vis, VisState } from './vis'; +import { VisType } from './types'; +import { IIndexPattern } from '../../../../../../plugins/data/common'; -test('can get Trigger from registry', () => { - const deps = createDeps(); - const { api } = createApi(deps); - api.registerTrigger({ - actionIds: [], - description: 'foo', - id: 'bar', - title: 'baz', - }); +type InitVisStateType = + | Partial + | Partial & { type: string }> + | string; - const trigger = api.getTrigger('bar'); +export type VisImplConstructor = new ( + indexPattern: IIndexPattern, + visState?: InitVisStateType +) => VisImpl; - expect(trigger).toEqual({ - actionIds: [], - description: 'foo', - id: 'bar', - title: 'baz', - }); -}); +export declare class VisImpl implements Vis { + constructor(indexPattern: IIndexPattern, visState?: InitVisStateType); -test('throws if trigger does not exist', () => { - const deps = createDeps(); - const { api } = createApi(deps); + type: VisType; - expect(() => api.getTrigger('foo')).toThrowError('Trigger [triggerId = foo] does not exist.'); -}); + // Since we haven't typed everything here yet, we basically "any" the rest + // of that interface. This should be removed as soon as this type definition + // has been completed. But that way we at least have typing for a couple of + // properties on that type. + [key: string]: any; +} diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js similarity index 98% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js index 0c2e5012df439..6f4ab6d708184 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js @@ -33,7 +33,7 @@ import { AggConfigs, PersistedState } from '../../legacy_imports'; import { updateVisualizationConfig } from './legacy/vis_update'; import { getTypes } from './services'; -class Vis extends EventEmitter { +class VisImpl extends EventEmitter { constructor(indexPattern, visState) { super(); visState = visState || {}; @@ -203,6 +203,6 @@ class Vis extends EventEmitter { } } -Vis.prototype.type = 'histogram'; +VisImpl.prototype.type = 'histogram'; -export { Vis }; +export { VisImpl }; diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts b/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts index ca2305a9cc91c..8b8c5fe94cc95 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts +++ b/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts @@ -26,14 +26,14 @@ */ import { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; -// @ts-ignore -import { updateOldState, Vis } from '../index'; +import { updateOldState } from '../index'; import { extractReferences, injectReferences } from './saved_visualization_references'; import { IIndexPattern } from '../../../../../plugins/data/public'; import { VisSavedObject } from '../embeddable/visualize_embeddable'; import { createSavedSearchesLoader } from '../../../kibana/public/discover'; import { VisualizeConstants } from '../../../kibana/public/visualize'; +import { VisImpl } from '../np_ready/public/vis_impl'; async function _afterEsResp(savedVis: VisSavedObject, services: any) { await _getLinkedSavedSearch(savedVis, services); @@ -72,9 +72,8 @@ async function _createVis(savedVis: VisSavedObject) { if (savedVis.visState) { savedVis.visState.title = savedVis.title; } - // the typescript compiler is wrong here, will be right when vis.js -> vis.ts - // @ts-ignore - savedVis.vis = new Vis(savedVis.searchSource!.getField('index'), savedVis.visState); + + savedVis.vis = new VisImpl(savedVis.searchSource!.getField('index')!, savedVis.visState); savedVis.vis!.savedSearchId = savedVis.savedSearchId; diff --git a/src/legacy/server/sass/build.test.js b/src/legacy/server/sass/build.test.js index 7092f6ad12921..46a898c30f84e 100644 --- a/src/legacy/server/sass/build.test.js +++ b/src/legacy/server/sass/build.test.js @@ -47,28 +47,7 @@ it('builds light themed SASS', async () => { expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2')) .toMatchInlineSnapshot(` - "/* 1 */ - /* 1 */ - /** - * 1. Extend beta badges to at least 40% of the container's width - * 2. Fix for IE to ensure badges are visible outside of a
+ } + > + xpack.monitoring.collection.enabled + - xpack.monitoring.collection.enabled - + /> @@ -214,15 +221,22 @@ exports[`ExplainCollectionEnabled should explain about xpack.monitoring.collecti paddingSize="l" transparentBackground={false} > + + -1 +
+ } + > + -1 + - -1 - + /> diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap index ac3dce3bfaef6..3cf35609acd07 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap @@ -366,15 +366,22 @@ exports[`ExplainCollectionInterval collection interval setting updates should sh paddingSize="l" transparentBackground={false} > + + xpack.monitoring.collection.interval +
+ } + > + xpack.monitoring.collection.interval + - xpack.monitoring.collection.interval - + /> @@ -387,15 +394,22 @@ exports[`ExplainCollectionInterval collection interval setting updates should sh paddingSize="l" transparentBackground={false} > + + -1 +
+ } + > + -1 + - -1 - + /> @@ -682,15 +696,22 @@ exports[`ExplainCollectionInterval should explain about xpack.monitoring.collect paddingSize="l" transparentBackground={false} > + + xpack.monitoring.collection.interval +
+ } + > + xpack.monitoring.collection.interval + - xpack.monitoring.collection.interval - + /> @@ -703,15 +724,22 @@ exports[`ExplainCollectionInterval should explain about xpack.monitoring.collect paddingSize="l" transparentBackground={false} > + + -1 +
+ } + > + -1 + - -1 - + /> diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap index 89cd3e5852f82..fb06ff2d866bb 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap @@ -26,32 +26,20 @@ Array [ >

We checked the - - + + esProd001 settings for - - + + xpack.monitoring.exporters , and found the reason: - - + + myMonitoringClusterExporter1 @@ -59,32 +47,20 @@ Array [

Using monitoring exporters to ship the monitoring data to a remote monitoring cluster is highly recommended as it keeps the integrity of the monitoring data safe no matter what the state of the production cluster. However, as this instance of Kibana could not find any monitoring data, there seems to be a problem with the - - + + xpack.monitoring.exporters configuration, or the - - + + xpack.monitoring.elasticsearch settings in - - + + kibana.yml @@ -92,22 +68,14 @@ Array [

Check that the intended exporters are enabled for sending statistics to the monitoring cluster, and that the monitoring cluster host matches the - - + + xpack.monitoring.elasticsearch setting in - - + + kibana.yml diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js index bdeb469daee46..c9147037f0022 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js @@ -8,6 +8,19 @@ import React from 'react'; import { renderWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; import { ExplainExporters, ExplainExportersCloud } from '../exporters'; +// Mocking to prevent errors with React portal. +// Temporary until https://github.com/elastic/kibana/pull/55877 provides other alternatives. +jest.mock('@elastic/eui/lib/components/code/code', () => { + const React = require.requireActual('react'); + return { + EuiCode: ({ children }) => ( + + {children} + + ), + }; +}); + describe('ExplainExporters', () => { test('should explain about xpack.monitoring.exporters setting', () => { const reason = { diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap index 8871d8caadd1c..63053c3f7c0cd 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap @@ -26,32 +26,20 @@ Array [ >

We checked the cluster settings and found that - - + + xpack.monitoring.enabled is set to - - + + false set, which disables monitoring. Removing the - - + + xpack.monitoring.enabled: false diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js index b962d136ba642..56536a8e4270b 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js @@ -8,6 +8,19 @@ import React from 'react'; import { renderWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; import { ExplainPluginEnabled } from '../plugin_enabled'; +// Mocking to prevent errors with React portal. +// Temporary until https://github.com/elastic/kibana/pull/55877 provides other alternatives. +jest.mock('@elastic/eui/lib/components/code/code', () => { + const React = require.requireActual('react'); + return { + EuiCode: ({ children }) => ( + + {children} + + ), + }; +}); + describe('ExplainPluginEnabled', () => { test('should explain about xpack.monitoring.enabled setting', () => { const reason = { diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap index fadf7c5757bf8..898be82b139d1 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap @@ -26,22 +26,14 @@ Array [ >

We checked the cluster settings and found that - - + + xpack.monitoring.collection.interval is set to - - + + -1 @@ -109,32 +101,20 @@ Array [ >

We checked the - - + + node001foo settings for - - + + xpack.monitoring.exporters , and found the reason: - - + + myMonitoringClusterExporter1 @@ -142,32 +122,20 @@ Array [

Using monitoring exporters to ship the monitoring data to a remote monitoring cluster is highly recommended as it keeps the integrity of the monitoring data safe no matter what the state of the production cluster. However, as this instance of Kibana could not find any monitoring data, there seems to be a problem with the - - + + xpack.monitoring.exporters configuration, or the - - + + xpack.monitoring.elasticsearch settings in - - + + kibana.yml @@ -175,22 +143,14 @@ Array [

Check that the intended exporters are enabled for sending statistics to the monitoring cluster, and that the monitoring cluster host matches the - - + + xpack.monitoring.elasticsearch setting in - - + + kibana.yml @@ -277,32 +237,20 @@ Array [ >

We checked the node001foo settings and found that - - + + xpack.monitoring.enabled is set to - - + + false set, which disables monitoring. Removing the - - + + xpack.monitoring.enabled: false diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js index a51817db324b7..e9b2ff11538ab 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js @@ -8,6 +8,19 @@ import React from 'react'; import { renderWithIntl } from '../../../../../../../../test_utils/enzyme_helpers'; import { ReasonFound } from '../'; +// Mocking to prevent errors with React portal. +// Temporary until https://github.com/elastic/kibana/pull/55877 provides other alternatives. +jest.mock('@elastic/eui/lib/components/code/code', () => { + const React = require.requireActual('react'); + return { + EuiCode: ({ children }) => ( + + {children} + + ), + }; +}); + const enabler = {}; describe('ReasonFound', () => { diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts index 728b3433bf06c..87b225e48c158 100644 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts +++ b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts @@ -16,10 +16,13 @@ const KEY = 'monitoring.ui.elasticsearch'; * TODO: this code can be removed when this plugin is migrated to the Kibana Platform, * at that point the ElasticsearchClient and ElasticsearchConfig should be used instead */ -export const parseElasticsearchConfig = (config: any) => { - const es = config.get(KEY); +export const parseElasticsearchConfig = (config: any, configKey: string = KEY) => { + const es = config.get(configKey); + if (!es) { + return {}; + } - const errorPrefix = `[config validation of [${KEY}].ssl]`; + const errorPrefix = `[config validation of [${configKey}].ssl]`; if (es.ssl?.key && es.ssl?.keystore?.path) { throw new Error(`${errorPrefix}: cannot use [key] when [keystore.path] is specified`); } diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js index ef7d3f1224fab..2fefdbd4f0943 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js @@ -6,8 +6,10 @@ import { noop } from 'lodash'; import sinon from 'sinon'; +import moment from 'moment'; import expect from '@kbn/expect'; import { BulkUploader } from '../bulk_uploader'; +import { MONITORING_SYSTEM_API_VERSION } from '../../../common/constants'; const FETCH_INTERVAL = 300; const CHECK_DELAY = 500; @@ -52,6 +54,9 @@ describe('BulkUploader', () => { server = { log: sinon.spy(), + config: { + get: sinon.spy(), + }, elasticsearchPlugin: { createCluster: () => cluster, getCluster: () => cluster, @@ -307,5 +312,92 @@ describe('BulkUploader', () => { done(); }, CHECK_DELAY); }); + + it('uses a direct connection to the monitoring cluster, when configured', done => { + const dateInIndex = '2020.02.10'; + const oldNow = moment.now; + moment.now = () => 1581310800000; + const prodClusterUuid = '1sdfd5'; + const prodCluster = { + callWithInternalUser: sinon + .stub() + .withArgs('monitoring.bulk') + .callsFake(arg => { + let resolution = null; + if (arg === 'info') { + resolution = { cluster_uuid: prodClusterUuid }; + } + return new Promise(resolve => resolve(resolution)); + }), + }; + const monitoringCluster = { + callWithInternalUser: sinon + .stub() + .withArgs('bulk') + .callsFake(() => { + return new Promise(resolve => setTimeout(resolve, CHECK_DELAY + 1)); + }), + }; + + const collectorFetch = sinon.stub().returns({ + type: 'kibana_stats', + result: { type: 'kibana_stats', payload: { testData: 12345 } }, + }); + + const collectors = new MockCollectorSet(server, [ + { + fetch: collectorFetch, + isReady: () => true, + formatForBulkUpload: result => result, + isUsageCollector: false, + }, + ]); + const customServer = { + ...server, + elasticsearchPlugin: { + createCluster: () => monitoringCluster, + getCluster: name => { + if (name === 'admin' || name === 'data') { + return prodCluster; + } + return monitoringCluster; + }, + }, + config: { + get: key => { + if (key === 'monitoring.elasticsearch') { + return { + hosts: ['http://localhost:9200'], + username: 'tester', + password: 'testing', + ssl: {}, + }; + } + return null; + }, + }, + }; + const kbnServerStatus = { toJSON: () => ({ overall: { state: 'green' } }) }; + const kbnServerVersion = 'master'; + const uploader = new BulkUploader({ + ...customServer, + interval: FETCH_INTERVAL, + kbnServerStatus, + kbnServerVersion, + }); + uploader.start(collectors); + setTimeout(() => { + uploader.stop(); + const firstCallArgs = monitoringCluster.callWithInternalUser.firstCall.args; + expect(firstCallArgs[0]).to.be('bulk'); + expect(firstCallArgs[1].body[0].index._index).to.be( + `.monitoring-kibana-${MONITORING_SYSTEM_API_VERSION}-${dateInIndex}` + ); + expect(firstCallArgs[1].body[1].type).to.be('kibana_stats'); + expect(firstCallArgs[1].body[1].cluster_uuid).to.be(prodClusterUuid); + moment.now = oldNow; + done(); + }, CHECK_DELAY); + }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js index cf68ec073bebc..7417e6ca804d9 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { defaultsDeep, uniq, compact } from 'lodash'; +import { defaultsDeep, uniq, compact, get } from 'lodash'; import { callClusterFactory } from '../../../xpack_main'; import { @@ -14,6 +14,8 @@ import { } from '../../common/constants'; import { sendBulkPayload, monitoringBulk, getKibanaInfoForStats } from './lib'; +import { parseElasticsearchConfig } from '../es_client/parse_elasticsearch_config'; +import { hasMonitoringCluster } from '../es_client/instantiate_client'; const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG]; @@ -39,6 +41,8 @@ export class BulkUploader { throw new Error('interval number of milliseconds is required'); } + this._hasDirectConnectionToMonitoringCluster = false; + this._productionClusterUuid = null; this._timer = null; // Hold sending and fetching usage until monitoring.bulk is successful. This means that we // send usage data on the second tick. But would save a lot of bandwidth fetching usage on @@ -60,6 +64,19 @@ export class BulkUploader { plugins: [monitoringBulk], }); + const directConfig = parseElasticsearchConfig(config, 'monitoring.elasticsearch'); + if (hasMonitoringCluster(directConfig)) { + this._log.info(`Detected direct connection to monitoring cluster`); + this._hasDirectConnectionToMonitoringCluster = true; + this._cluster = elasticsearchPlugin.createCluster('monitoring-direct', directConfig); + elasticsearchPlugin + .getCluster('admin') + .callWithInternalUser('info') + .then(data => { + this._productionClusterUuid = get(data, 'cluster_uuid'); + }); + } + this._callClusterWithInternalUser = callClusterFactory({ plugins: { elasticsearch: elasticsearchPlugin }, }).getCallClusterInternal(); @@ -151,7 +168,6 @@ export class BulkUploader { const data = await usageCollection.bulkFetch(this._callClusterWithInternalUser); const payload = this.toBulkUploadFormat(compact(data), usageCollection); - if (payload) { try { this._log.debug(`Uploading bulk stats payload to the local cluster`); @@ -182,7 +198,14 @@ export class BulkUploader { } async _onPayload(payload) { - return await sendBulkPayload(this._cluster, this._interval, payload); + return await sendBulkPayload( + this._cluster, + this._interval, + payload, + this._log, + this._hasDirectConnectionToMonitoringCluster, + this._productionClusterUuid + ); } /* diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js index 3e5c64905da0d..c378c0ad0fa08 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js @@ -3,13 +3,64 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import moment from 'moment'; +import { chunk, get } from 'lodash'; +import { + MONITORING_SYSTEM_API_VERSION, + KIBANA_SYSTEM_ID, + KIBANA_STATS_TYPE_MONITORING, + KIBANA_SETTINGS_TYPE, +} from '../../../common/constants'; -import { MONITORING_SYSTEM_API_VERSION, KIBANA_SYSTEM_ID } from '../../../common/constants'; +const SUPPORTED_TYPES = [KIBANA_STATS_TYPE_MONITORING, KIBANA_SETTINGS_TYPE]; +export function formatForNormalBulkEndpoint(payload, productionClusterUuid) { + const dateSuffix = moment.utc().format('YYYY.MM.DD'); + return chunk(payload, 2).reduce((accum, chunk) => { + const type = get(chunk[0], 'index._type'); + if (!type || !SUPPORTED_TYPES.includes(type)) { + return accum; + } + + const { timestamp } = chunk[1]; + + accum.push({ + index: { + _index: `.monitoring-kibana-${MONITORING_SYSTEM_API_VERSION}-${dateSuffix}`, + }, + }); + accum.push({ + [type]: chunk[1], + type, + timestamp, + cluster_uuid: productionClusterUuid, + }); + return accum; + }, []); +} /* * Send the Kibana usage data to the ES Monitoring Bulk endpoint */ -export function sendBulkPayload(cluster, interval, payload) { +export async function sendBulkPayload( + cluster, + interval, + payload, + log, + hasDirectConnectionToMonitoringCluster = false, + productionClusterUuid = null +) { + if (hasDirectConnectionToMonitoringCluster) { + if (productionClusterUuid === null) { + log.warn( + `Unable to determine production cluster uuid to use for shipping monitoring data. Kibana monitoring data will appear in a standalone cluster in the Stack Monitoring UI.` + ); + } + const formattedPayload = formatForNormalBulkEndpoint(payload, productionClusterUuid); + return await cluster.callWithInternalUser('bulk', { + body: formattedPayload, + }); + } + return cluster.callWithInternalUser('monitoring.bulk', { system_id: KIBANA_SYSTEM_ID, system_api_version: MONITORING_SYSTEM_API_VERSION, diff --git a/x-pack/legacy/plugins/monitoring/server/plugin.js b/x-pack/legacy/plugins/monitoring/server/plugin.js index c2aed7365f3af..304d2c08a1688 100644 --- a/x-pack/legacy/plugins/monitoring/server/plugin.js +++ b/x-pack/legacy/plugins/monitoring/server/plugin.js @@ -19,7 +19,7 @@ import { getLicenseExpiration } from './alerts/license_expiration'; import { parseElasticsearchConfig } from './es_client/parse_elasticsearch_config'; export class Plugin { - setup(_coreSetup, pluginsSetup, __LEGACY) { + async setup(_coreSetup, pluginsSetup, __LEGACY) { const { plugins, _kbnServer: kbnServer, @@ -59,6 +59,14 @@ export class Plugin { */ const elasticsearchConfig = parseElasticsearchConfig(config); + // Create the dedicated client + await instantiateClient({ + log, + events, + elasticsearchConfig, + elasticsearchPlugin: plugins.elasticsearch, + }); + xpackMainPlugin.status.once('green', async () => { // first time xpack_main turns green /* @@ -67,12 +75,6 @@ export class Plugin { const uiEnabled = config.get('monitoring.ui.enabled'); if (uiEnabled) { - await instantiateClient({ - log, - events, - elasticsearchConfig, - elasticsearchPlugin: plugins.elasticsearch, - }); // Instantiate the dedicated ES client await initMonitoringXpackInfo({ config, log, diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/fixtures/beats_stats_results.json b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/fixtures/beats_stats_results.json rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/create_query.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.test.ts similarity index 89% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/create_query.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.test.ts index 63c779ab4b520..a85d084f83d83 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/create_query.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.test.ts @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import { set } from 'lodash'; -import { createTypeFilter, createQuery } from '../create_query.js'; +import { createTypeFilter, createQuery } from './create_query'; describe('Create Type Filter', () => { it('Builds a type filter syntax', () => { const typeFilter = createTypeFilter('my_type'); - expect(typeFilter).to.eql({ + expect(typeFilter).toStrictEqual({ bool: { should: [{ term: { _type: 'my_type' } }, { term: { type: 'my_type' } }] }, }); }); @@ -36,7 +35,7 @@ describe('Create Query', () => { ], }, }; - expect(result).to.be.eql(expected); + expect(result).toStrictEqual(expected); }); it('Uses `type` option to add type filter with minimal fields', () => { @@ -47,7 +46,7 @@ describe('Create Query', () => { { term: { _type: 'test-type-yay' } }, { term: { type: 'test-type-yay' } }, ]); - expect(result).to.be.eql(expected); + expect(result).toStrictEqual(expected); }); it('Uses `type` option to add type filter with all other option fields', () => { @@ -77,6 +76,6 @@ describe('Create Query', () => { ], }, }; - expect(result).to.be.eql(expected); + expect(result).toStrictEqual(expected); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.ts similarity index 80% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.ts index 6fcbb677b307d..9a801094458bd 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { defaults } from 'lodash'; import moment from 'moment'; /* @@ -14,7 +13,7 @@ import moment from 'moment'; * TODO: this backwards compatibility helper will only be supported for 5.x-6. This * function should be removed in 7.0 */ -export const createTypeFilter = type => { +export const createTypeFilter = (type: string) => { return { bool: { should: [{ term: { _type: type } }, { term: { type } }], @@ -22,6 +21,18 @@ export const createTypeFilter = type => { }; }; +export interface QueryOptions { + type?: string; + filters?: object[]; + clusterUuid?: string; + start?: string | number; + end?: string | number; +} + +interface RangeFilter { + range: { [key: string]: { format?: string; gte?: string | number; lte?: string | number } }; +} + /* * Creates the boilerplace for querying monitoring data, including filling in * start time and end time, and injecting additional filters. @@ -36,9 +47,8 @@ export const createTypeFilter = type => { * @param {Date} options.start - numeric timestamp (optional) * @param {Date} options.end - numeric timestamp (optional) */ -export function createQuery(options) { - options = defaults(options, { filters: [] }); - const { type, clusterUuid, start, end, filters } = options; +export function createQuery(options: QueryOptions) { + const { type, clusterUuid, start, end, filters = [] } = options; let typeFilter; if (type) { @@ -50,7 +60,7 @@ export function createQuery(options) { clusterUuidFilter = { term: { cluster_uuid: clusterUuid } }; } - let timeRangeFilter; + let timeRangeFilter: RangeFilter | undefined; if (start || end) { timeRangeFilter = { range: { 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/get_all_stats.test.ts similarity index 78% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts index f27fde50242f4..470642f9dd8a3 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_all_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts @@ -4,12 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import sinon from 'sinon'; -import { addStackStats, getAllStats, handleAllStats } from '../get_all_stats'; +import { addStackStats, getAllStats, handleAllStats } from './get_all_stats'; +import { ESClusterStats } from './get_es_stats'; +import { KibanaStats } from './get_kibana_stats'; +import { ClustersHighLevelStats } from './get_high_level_stats'; -// FAILING: https://github.com/elastic/kibana/issues/51371 -describe.skip('get_all_stats', () => { +describe('get_all_stats', () => { const size = 123; const start = 0; const end = 1; @@ -100,9 +101,6 @@ describe.skip('get_all_stats', () => { describe('getAllStats', () => { it('returns clusters', async () => { - const clusterUuidsResponse = { - aggregations: { cluster_uuids: { buckets: [{ key: 'a' }] } }, - }; const esStatsResponse = { hits: { hits: [{ _id: 'a', _source: { cluster_uuid: 'a' } }], @@ -177,15 +175,25 @@ describe.skip('get_all_stats', () => { callCluster .withArgs('search') .onCall(0) - .returns(Promise.resolve(clusterUuidsResponse)) - .onCall(1) .returns(Promise.resolve(esStatsResponse)) - .onCall(2) + .onCall(1) .returns(Promise.resolve(kibanaStatsResponse)) + .onCall(2) + .returns(Promise.resolve(logstashStatsResponse)) .onCall(3) - .returns(Promise.resolve(logstashStatsResponse)); + .returns(Promise.resolve({})) // Beats stats + .onCall(4) + .returns(Promise.resolve({})); // Beats state - expect(await getAllStats({ callCluster, server, start, end })).to.eql(allClusters); + expect( + await getAllStats([{ clusterUuid: 'a' }], { + callCluster: callCluster as any, + usageCollection: {} as any, + server, + start, + end, + }) + ).toStrictEqual(allClusters); }); it('returns empty clusters', async () => { @@ -195,21 +203,33 @@ describe.skip('get_all_stats', () => { callCluster.withArgs('search').returns(Promise.resolve(clusterUuidsResponse)); - expect(await getAllStats({ callCluster, server, start, end })).to.eql([]); + expect( + await getAllStats([], { + callCluster: callCluster as any, + usageCollection: {} as any, + server, + start, + end, + }) + ).toStrictEqual([]); }); }); describe('handleAllStats', () => { it('handles response', () => { - const clusters = handleAllStats(esClusters, { kibana: kibanaStats, logstash: logstashStats }); + const clusters = handleAllStats(esClusters as ESClusterStats[], { + kibana: (kibanaStats as unknown) as KibanaStats, + logstash: (logstashStats as unknown) as ClustersHighLevelStats, + beats: {}, + }); - expect(clusters).to.eql(expectedClusters); + expect(clusters).toStrictEqual(expectedClusters); }); it('handles no clusters response', () => { - const clusters = handleAllStats([], {}); + const clusters = handleAllStats([], {} as any); - expect(clusters).to.have.length(0); + expect(clusters).toHaveLength(0); }); }); @@ -230,9 +250,9 @@ describe.skip('get_all_stats', () => { }, }; - addStackStats(cluster, stats, 'xyz'); + addStackStats(cluster as ESClusterStats, stats, 'xyz'); - expect(cluster.stack_stats.xyz).to.be(stats.a); + expect((cluster as any).stack_stats.xyz).toStrictEqual(stats.a); }); }); }); 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.ts similarity index 66% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts index 87281a19141ae..aa5e937387daf 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.ts @@ -6,22 +6,26 @@ import { get, set, merge } from 'lodash'; +import { StatsGetter } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; import { LOGSTASH_SYSTEM_ID, KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID } from '../../common/constants'; -import { getElasticsearchStats } from './get_es_stats'; -import { getKibanaStats } from './get_kibana_stats'; +import { getElasticsearchStats, ESClusterStats } from './get_es_stats'; +import { getKibanaStats, KibanaStats } from './get_kibana_stats'; import { getBeatsStats } from './get_beats_stats'; import { getHighLevelStats } from './get_high_level_stats'; +type PromiseReturnType any> = ReturnType extends Promise + ? R + : T; + /** * Get statistics for all products joined by Elasticsearch cluster. + * Returns the array of clusters joined with the Kibana and Logstash instances. * - * @param {Object} server The Kibana server instance used to call ES as the internal user - * @param {function} callCluster The callWithRequest or callWithInternalUser handler - * @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 async function getAllStats(clustersDetails, { server, callCluster, start, end }) { +export const getAllStats: StatsGetter = async ( + clustersDetails, + { server, callCluster, start, end } +) => { const clusterUuids = clustersDetails.map(clusterDetails => clusterDetails.clusterUuid); const [esClusters, kibana, logstash, beats] = await Promise.all([ @@ -32,7 +36,7 @@ export async function getAllStats(clustersDetails, { server, callCluster, start, ]); return handleAllStats(esClusters, { kibana, logstash, beats }); -} +}; /** * Combine the statistics from the stack to create "cluster" stats that associate all products together based on the cluster @@ -41,9 +45,21 @@ export async function getAllStats(clustersDetails, { server, callCluster, start, * @param {Array} clusters The Elasticsearch clusters * @param {Object} kibana The Kibana instances keyed by Cluster UUID * @param {Object} logstash The Logstash nodes keyed by Cluster UUID - * @return {Array} The clusters joined with the Kibana and Logstash instances under each cluster's {@code stack_stats}. + * + * Returns the clusters joined with the Kibana and Logstash instances under each cluster's {@code stack_stats}. */ -export function handleAllStats(clusters, { kibana, logstash, beats }) { +export function handleAllStats( + clusters: ESClusterStats[], + { + kibana, + logstash, + beats, + }: { + kibana: KibanaStats; + logstash: PromiseReturnType; + beats: PromiseReturnType; + } +) { return clusters.map(cluster => { // if they are using Kibana or Logstash, then add it to the cluster details under cluster.stack_stats addStackStats(cluster, kibana, KIBANA_SYSTEM_ID); @@ -62,8 +78,12 @@ export function handleAllStats(clusters, { kibana, logstash, beats }) { * @param {Object} allProductStats Product stats, keyed by Cluster UUID * @param {String} product The product name being added (e.g., 'kibana' or 'logstash') */ -export function addStackStats(cluster, allProductStats, product) { - const productStats = get(allProductStats, cluster.cluster_uuid); +export function addStackStats( + cluster: ESClusterStats & { stack_stats?: { [product: string]: K } }, + allProductStats: T, + product: string +) { + const productStats = allProductStats[cluster.cluster_uuid]; // Don't add it if they're not using (or configured to report stats) this product for this cluster if (productStats) { @@ -75,12 +95,20 @@ export function addStackStats(cluster, allProductStats, product) { } } -export function mergeXPackStats(cluster, allProductStats, path, product) { +export function mergeXPackStats( + cluster: ESClusterStats & { stack_stats?: { xpack?: { [product: string]: unknown } } }, + allProductStats: T, + path: string, + product: string +) { const productStats = get(allProductStats, cluster.cluster_uuid + '.' + path); if (productStats || productStats === 0) { - if (!get(cluster, 'stack_stats.xpack')) { - set(cluster, 'stack_stats.xpack', {}); + if (!cluster.stack_stats) { + cluster.stack_stats = {}; + } + if (!cluster.stack_stats.xpack) { + cluster.stack_stats.xpack = {}; } const mergeStats = {}; diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_beats_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts similarity index 75% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_beats_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts index 522be71555fba..30888e1af3f53 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_beats_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fetchBeatsStats, processResults } from '../get_beats_stats'; +import { fetchBeatsStats, processResults } from './get_beats_stats'; import sinon from 'sinon'; -import expect from '@kbn/expect'; -import beatsStatsResultSet from './fixtures/beats_stats_results'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const beatsStatsResultSet = require('./__mocks__/fixtures/beats_stats_results'); const getBaseOptions = () => ({ clusters: {}, @@ -22,8 +22,8 @@ describe('Get Beats Stats', () => { const clusterUuids = ['aCluster', 'bCluster', 'cCluster']; const start = 100; const end = 200; - let server; - let callCluster; + let server = { config: () => ({ get: sinon.stub() }) }; + let callCluster = sinon.stub(); beforeEach(() => { const getStub = { get: sinon.stub() }; @@ -32,34 +32,34 @@ describe('Get Beats Stats', () => { callCluster = sinon.stub(); }); - it('should set `from: 0, to: 10000` in the query', () => { - fetchBeatsStats(server, callCluster, clusterUuids, start, end); + it('should set `from: 0, to: 10000` in the query', async () => { + await fetchBeatsStats(server, callCluster, clusterUuids, start, end, {} as any); const { args } = callCluster.firstCall; const [api, { body }] = args; - expect(api).to.be('search'); - expect(body.from).to.be(0); - expect(body.size).to.be(10000); + expect(api).toEqual('search'); + expect(body.from).toEqual(0); + expect(body.size).toEqual(10000); }); - it('should set `from: 10000, from: 10000` in the query', () => { - fetchBeatsStats(server, callCluster, clusterUuids, start, end, { page: 1 }); + it('should set `from: 10000, from: 10000` in the query', async () => { + await fetchBeatsStats(server, callCluster, clusterUuids, start, end, { page: 1 } as any); const { args } = callCluster.firstCall; const [api, { body }] = args; - expect(api).to.be('search'); - expect(body.from).to.be(10000); - expect(body.size).to.be(10000); + expect(api).toEqual('search'); + expect(body.from).toEqual(10000); + expect(body.size).toEqual(10000); }); - it('should set `from: 20000, from: 10000` in the query', () => { - fetchBeatsStats(server, callCluster, clusterUuids, start, end, { page: 2 }); + it('should set `from: 20000, from: 10000` in the query', async () => { + await fetchBeatsStats(server, callCluster, clusterUuids, start, end, { page: 2 } as any); const { args } = callCluster.firstCall; const [api, { body }] = args; - expect(api).to.be('search'); - expect(body.from).to.be(20000); - expect(body.size).to.be(10000); + expect(api).toEqual('search'); + expect(body.from).toEqual(20000); + expect(body.size).toEqual(10000); }); }); @@ -68,9 +68,9 @@ describe('Get Beats Stats', () => { const resultsEmpty = undefined; const options = getBaseOptions(); - processResults(resultsEmpty, options); + processResults(resultsEmpty as any, options); - expect(options.clusters).to.eql({}); + expect(options.clusters).toStrictEqual({}); }); it('should summarize single result with some missing fields', () => { @@ -92,9 +92,9 @@ describe('Get Beats Stats', () => { }; const options = getBaseOptions(); - processResults(results, options); + processResults(results as any, options); - expect(options.clusters).to.eql({ + expect(options.clusters).toStrictEqual({ FlV4ckTxQ0a78hmBkzzc9A: { count: 1, versions: {}, @@ -122,11 +122,11 @@ describe('Get Beats Stats', () => { const options = getBaseOptions(); // beatsStatsResultSet is an array of many small query results - beatsStatsResultSet.forEach(results => { + beatsStatsResultSet.forEach((results: any) => { processResults(results, options); }); - expect(options.clusters).to.eql({ + expect(options.clusters).toStrictEqual({ W7hppdX7R229Oy3KQbZrTw: { count: 5, versions: { '7.0.0-alpha1': 5 }, diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts similarity index 60% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts index 5722228b60207..975a3bfee6333 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts @@ -5,6 +5,8 @@ */ import { get } from 'lodash'; +import { StatsCollectionConfig } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { SearchResponse } from 'elasticsearch'; import { createQuery } from './create_query'; import { INDEX_PATTERN_BEATS } from '../../common/constants'; @@ -33,6 +35,107 @@ const getBaseStats = () => ({ }, }); +export interface BeatsStats { + cluster_uuid: string; + beats_stats?: { + beat?: { + version?: string; + type?: string; + host?: string; + }; + metrics?: { + libbeat?: { + output?: { + type?: string; + }; + pipeline?: { + events?: { + published?: number; + }; + }; + }; + }; + }; + beats_state?: { + beat?: { + type?: string; + }; + state?: { + input?: { + names: string[]; + count: number; + }; + module?: { + names: string[]; + count: number; + }; + heartbeat?: HeartbeatBase; + functionbeat?: { + functions?: { + count?: number; + }; + }; + host?: { + architecture: string; + os: { platform: string }; + }; + }; + }; +} + +interface HeartbeatBase { + monitors: number; + endpoints: number; + // I have to add the '| number' bit because otherwise TS complains about 'monitors' and 'endpoints' not being of type HeartbeatBase + [key: string]: HeartbeatBase | number | undefined; +} + +export interface BeatsBaseStats { + // stats + versions: { [version: string]: number }; + types: { [type: string]: number }; + outputs: { [outputType: string]: number }; + count: number; + eventsPublished: number; + hosts: number; + // state + input: { + count: number; + names: string[]; + }; + module: { + count: number; + names: string[]; + }; + architecture: { + count: number; + architectures: BeatsArchitecture[]; + }; + heartbeat?: HeartbeatBase; + functionbeat?: { + functions: { + count: number; + }; + }; +} + +export interface BeatsProcessOptions { + clusters: { [clusterUuid: string]: BeatsBaseStats }; // the result object to be built up + clusterHostSets: { [clusterUuid: string]: Set }; // passed to processResults for tracking state in the results generation + clusterInputSets: { [clusterUuid: string]: Set }; // passed to processResults for tracking state in the results generation + clusterModuleSets: { [clusterUuid: string]: Set }; // passed to processResults for tracking state in the results generation + clusterArchitectureMaps: { + // passed to processResults for tracking state in the results generation + [clusterUuid: string]: Map; + }; +} + +export interface BeatsArchitecture { + name: string; + architecture: string; + count: number; +} + /* * Update a clusters object with processed beat stats * @param {Array} results - array of Beats docs from ES @@ -41,12 +144,18 @@ const getBaseStats = () => ({ * @param {Object} clusterModuleSets - the object keyed by cluster UUIDs to count the unique modules */ export function processResults( - results = [], - { clusters, clusterHostSets, clusterInputSets, clusterModuleSets, clusterArchitectureMaps } + results: SearchResponse, + { + clusters, + clusterHostSets, + clusterInputSets, + clusterModuleSets, + clusterArchitectureMaps, + }: BeatsProcessOptions ) { - const currHits = get(results, 'hits.hits', []); + const currHits = results?.hits?.hits || []; currHits.forEach(hit => { - const clusterUuid = get(hit, '_source.cluster_uuid'); + const clusterUuid = hit._source.cluster_uuid; if (clusters[clusterUuid] === undefined) { clusters[clusterUuid] = getBaseStats(); clusterHostSets[clusterUuid] = new Set(); @@ -57,30 +166,30 @@ export function processResults( const processBeatsStatsResults = () => { const { versions, types, outputs } = clusters[clusterUuid]; - const thisVersion = get(hit, '_source.beats_stats.beat.version'); + const thisVersion = hit._source.beats_stats?.beat?.version; if (thisVersion !== undefined) { const thisVersionAccum = versions[thisVersion] || 0; versions[thisVersion] = thisVersionAccum + 1; } - const thisType = get(hit, '_source.beats_stats.beat.type'); + const thisType = hit._source.beats_stats?.beat?.type; if (thisType !== undefined) { const thisTypeAccum = types[thisType] || 0; types[thisType] = thisTypeAccum + 1; } - const thisOutput = get(hit, '_source.beats_stats.metrics.libbeat.output.type'); + const thisOutput = hit._source.beats_stats?.metrics?.libbeat?.output?.type; if (thisOutput !== undefined) { const thisOutputAccum = outputs[thisOutput] || 0; outputs[thisOutput] = thisOutputAccum + 1; } - const thisEvents = get(hit, '_source.beats_stats.metrics.libbeat.pipeline.events.published'); + const thisEvents = hit._source.beats_stats?.metrics?.libbeat?.pipeline?.events?.published; if (thisEvents !== undefined) { clusters[clusterUuid].eventsPublished += thisEvents; } - const thisHost = get(hit, '_source.beats_stats.beat.host'); + const thisHost = hit._source.beats_stats?.beat?.host; if (thisHost !== undefined) { const hostsMap = clusterHostSets[clusterUuid]; hostsMap.add(thisHost); @@ -89,7 +198,7 @@ export function processResults( }; const processBeatsStateResults = () => { - const stateInput = get(hit, '_source.beats_state.state.input'); + const stateInput = hit._source.beats_state?.state?.input; if (stateInput !== undefined) { const inputSet = clusterInputSets[clusterUuid]; stateInput.names.forEach(name => inputSet.add(name)); @@ -97,8 +206,8 @@ export function processResults( clusters[clusterUuid].input.count += stateInput.count; } - const stateModule = get(hit, '_source.beats_state.state.module'); - const statsType = get(hit, '_source.beats_state.beat.type'); + const stateModule = hit._source.beats_state?.state?.module; + const statsType = hit._source.beats_state?.beat?.type; if (stateModule !== undefined) { const moduleSet = clusterModuleSets[clusterUuid]; stateModule.names.forEach(name => moduleSet.add(statsType + '.' + name)); @@ -106,7 +215,7 @@ export function processResults( clusters[clusterUuid].module.count += stateModule.count; } - const heartbeatState = get(hit, '_source.beats_state.state.heartbeat'); + const heartbeatState = hit._source.beats_state?.state?.heartbeat; if (heartbeatState !== undefined) { if (!clusters[clusterUuid].hasOwnProperty('heartbeat')) { clusters[clusterUuid].heartbeat = { @@ -114,7 +223,7 @@ export function processResults( endpoints: 0, }; } - const clusterHb = clusters[clusterUuid].heartbeat; + const clusterHb = clusters[clusterUuid].heartbeat!; clusterHb.monitors += heartbeatState.monitors; clusterHb.endpoints += heartbeatState.endpoints; @@ -133,12 +242,12 @@ export function processResults( endpoints: 0, }; } - clusterHb[proto].monitors += val.monitors; - clusterHb[proto].endpoints += val.endpoints; + (clusterHb[proto] as HeartbeatBase).monitors += val.monitors; + (clusterHb[proto] as HeartbeatBase).endpoints += val.endpoints; } } - const functionbeatState = get(hit, '_source.beats_state.state.functionbeat'); + const functionbeatState = hit._source.beats_state?.state?.functionbeat; if (functionbeatState !== undefined) { if (!clusters[clusterUuid].hasOwnProperty('functionbeat')) { clusters[clusterUuid].functionbeat = { @@ -148,14 +257,11 @@ export function processResults( }; } - clusters[clusterUuid].functionbeat.functions.count += get( - functionbeatState, - 'functions.count', - 0 - ); + clusters[clusterUuid].functionbeat!.functions.count += + functionbeatState.functions?.count || 0; } - const stateHost = get(hit, '_source.beats_state.state.host'); + const stateHost = hit._source.beats_state?.state?.host; if (stateHost !== undefined) { const hostMap = clusterArchitectureMaps[clusterUuid]; const hostKey = `${stateHost.architecture}/${stateHost.os.platform}`; @@ -198,14 +304,14 @@ export function processResults( * @return {Promise} */ async function fetchBeatsByType( - server, - callCluster, - clusterUuids, - start, - end, - { page = 0, ...options } = {}, - type -) { + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'], + { page = 0, ...options }: { page?: number } & BeatsProcessOptions, + type: string +): Promise { const params = { index: INDEX_PATTERN_BEATS, ignoreUnavailable: true, @@ -232,7 +338,7 @@ async function fetchBeatsByType( { bool: { must_not: { term: { [`${type}.beat.type`]: 'apm-server' } }, - must: { term: { type: type } }, + must: { term: { type } }, }, }, ], @@ -244,8 +350,8 @@ async function fetchBeatsByType( }, }; - const results = await callCluster('search', params); - const hitsLength = get(results, 'hits.hits.length', 0); + const results = await callCluster>('search', params); + const hitsLength = results?.hits?.hits.length || 0; if (hitsLength > 0) { // further augment the clusters object with more stats processResults(results, options); @@ -265,20 +371,40 @@ async function fetchBeatsByType( return Promise.resolve(); } -export async function fetchBeatsStats(...args) { - return fetchBeatsByType(...args, 'beats_stats'); +export async function fetchBeatsStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'], + options: { page?: number } & BeatsProcessOptions +) { + return fetchBeatsByType(server, callCluster, clusterUuids, start, end, options, 'beats_stats'); } -export async function fetchBeatsStates(...args) { - return fetchBeatsByType(...args, 'beats_state'); +export async function fetchBeatsStates( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'], + options: { page?: number } & BeatsProcessOptions +) { + return fetchBeatsByType(server, callCluster, clusterUuids, start, end, options, 'beats_state'); } /* * Call the function for fetching and summarizing beats stats * @return {Object} - Beats stats in an object keyed by the cluster UUIDs */ -export async function getBeatsStats(server, callCluster, clusterUuids, start, end) { - const options = { +export async function getBeatsStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'] +) { + const options: BeatsProcessOptions = { clusters: {}, // the result object to be built up clusterHostSets: {}, // passed to processResults for tracking state in the results generation clusterInputSets: {}, // passed to processResults for tracking state in the results generation diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_cluster_uuids.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts similarity index 77% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_cluster_uuids.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts index 1f62c677dbb21..4f952b9dec6da 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_cluster_uuids.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import sinon from 'sinon'; import { getClusterUuids, fetchClusterUuids, handleClusterUuidsResponse, -} from '../get_cluster_uuids'; +} from './get_cluster_uuids'; describe('get_cluster_uuids', () => { const callCluster = sinon.stub(); @@ -35,20 +34,24 @@ describe('get_cluster_uuids', () => { const expectedUuids = response.aggregations.cluster_uuids.buckets .map(bucket => bucket.key) .map(expectedUuid => ({ clusterUuid: expectedUuid })); - const start = new Date(); - const end = new Date(); + const start = new Date().toISOString(); + const end = new Date().toISOString(); describe('getClusterUuids', () => { it('returns cluster UUIDs', async () => { callCluster.withArgs('search').returns(Promise.resolve(response)); - expect(await getClusterUuids({ server, callCluster, start, end })).to.eql(expectedUuids); + expect( + await getClusterUuids({ server, callCluster, start, end, usageCollection: {} as any }) + ).toStrictEqual(expectedUuids); }); }); describe('fetchClusterUuids', () => { it('searches for clusters', async () => { callCluster.returns(Promise.resolve(response)); - expect(await fetchClusterUuids({ server, callCluster, start, end })).to.be(response); + expect( + await fetchClusterUuids({ server, callCluster, start, end, usageCollection: {} as any }) + ).toStrictEqual(response); }); }); @@ -56,12 +59,12 @@ describe('get_cluster_uuids', () => { // filterPath makes it easy to ignore anything unexpected because it will come back empty it('handles unexpected response', () => { const clusterUuids = handleClusterUuidsResponse({}); - expect(clusterUuids.length).to.be(0); + expect(clusterUuids.length).toStrictEqual(0); }); it('handles valid response', () => { const clusterUuids = handleClusterUuidsResponse(response); - expect(clusterUuids).to.eql(expectedUuids); + expect(clusterUuids).toStrictEqual(expectedUuids); }); it('handles no buckets response', () => { @@ -73,7 +76,7 @@ describe('get_cluster_uuids', () => { }, }); - expect(clusterUuids.length).to.be(0); + expect(clusterUuids.length).toStrictEqual(0); }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_es_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_es_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts index 536e831640fad..70ed2240b47d4 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_es_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import sinon from 'sinon'; import { fetchElasticsearchStats, getElasticsearchStats, handleElasticsearchStats, -} from '../get_es_stats'; +} from './get_es_stats'; describe('get_es_stats', () => { const callWith = sinon.stub(); @@ -41,7 +40,9 @@ describe('get_es_stats', () => { it('returns clusters', async () => { callWith.withArgs('search').returns(Promise.resolve(response)); - expect(await getElasticsearchStats(server, callWith, clusterUuids)).to.eql(expectedClusters); + expect(await getElasticsearchStats(server, callWith, clusterUuids)).toStrictEqual( + expectedClusters + ); }); }); @@ -49,28 +50,28 @@ describe('get_es_stats', () => { it('searches for clusters', async () => { callWith.returns(response); - expect(await fetchElasticsearchStats(server, callWith, clusterUuids)).to.be(response); + expect(await fetchElasticsearchStats(server, callWith, clusterUuids)).toStrictEqual(response); }); }); describe('handleElasticsearchStats', () => { // filterPath makes it easy to ignore anything unexpected because it will come back empty it('handles unexpected response', () => { - const clusters = handleElasticsearchStats({}); + const clusters = handleElasticsearchStats({} as any); - expect(clusters.length).to.be(0); + expect(clusters.length).toStrictEqual(0); }); it('handles valid response', () => { - const clusters = handleElasticsearchStats(response); + const clusters = handleElasticsearchStats(response as any); - expect(clusters).to.eql(expectedClusters); + expect(clusters).toStrictEqual(expectedClusters); }); it('handles no hits response', () => { - const clusters = handleElasticsearchStats({ hits: { hits: [] } }); + const clusters = handleElasticsearchStats({ hits: { hits: [] } } as any); - expect(clusters.length).to.be(0); + expect(clusters.length).toStrictEqual(0); }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts similarity index 71% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts index 52d34258b5fa4..f0ae1163d3f52 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; +import { StatsCollectionConfig } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { SearchResponse } from 'elasticsearch'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; /** @@ -13,10 +14,14 @@ import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; * @param {Object} server The server instance * @param {function} callCluster The callWithRequest or callWithInternalUser handler * @param {Array} clusterUuids The string Cluster UUIDs to fetch details for - * @return {Promise} Array of the Elasticsearch clusters. */ -export function getElasticsearchStats(server, callCluster, clusterUuids) { - return fetchElasticsearchStats(server, callCluster, clusterUuids).then(handleElasticsearchStats); +export async function getElasticsearchStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[] +) { + const response = await fetchElasticsearchStats(server, callCluster, clusterUuids); + return handleElasticsearchStats(response); } /** @@ -25,9 +30,14 @@ export function getElasticsearchStats(server, callCluster, clusterUuids) { * @param {Object} server The server instance * @param {function} callCluster The callWithRequest or callWithInternalUser handler * @param {Array} clusterUuids Cluster UUIDs to limit the request against - * @return {Promise} Response for the aggregations to fetch details for the product. + * + * Returns the response for the aggregations to fetch details for the product. */ -export function fetchElasticsearchStats(server, callCluster, clusterUuids) { +export function fetchElasticsearchStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[] +) { const config = server.config(); const params = { index: INDEX_PATTERN_ELASTICSEARCH, @@ -67,13 +77,16 @@ export function fetchElasticsearchStats(server, callCluster, clusterUuids) { return callCluster('search', params); } +export interface ESClusterStats { + cluster_uuid: string; + type: 'cluster_stats'; +} + /** * Extract the cluster stats for each cluster. - * - * @return {Array} The Elasticsearch clusters. */ -export function handleElasticsearchStats(response) { - const clusters = get(response, 'hits.hits', []); +export function handleElasticsearchStats(response: SearchResponse) { + const clusters = response.hits?.hits || []; return clusters.map(cluster => cluster._source); } diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_high_level_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_high_level_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts index 1c1f8dc888d01..76c80e2eb3d37 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_high_level_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import sinon from 'sinon'; import { fetchHighLevelStats, getHighLevelStats, handleHighLevelStatsResponse, -} from '../get_high_level_stats'; +} from './get_high_level_stats'; describe('get_high_level_stats', () => { const callWith = sinon.stub(); @@ -244,9 +243,9 @@ describe('get_high_level_stats', () => { it('returns clusters', async () => { callWith.withArgs('search').returns(Promise.resolve(response)); - expect(await getHighLevelStats(server, callWith, clusterUuids, start, end, product)).to.eql( - expectedClusters - ); + expect( + await getHighLevelStats(server, callWith, clusterUuids, start, end, product) + ).toStrictEqual(expectedClusters); }); }); @@ -254,30 +253,30 @@ describe('get_high_level_stats', () => { it('searches for clusters', async () => { callWith.returns(Promise.resolve(response)); - expect(await fetchHighLevelStats(server, callWith, clusterUuids, start, end, product)).to.be( - response - ); + expect( + await fetchHighLevelStats(server, callWith, clusterUuids, start, end, product) + ).toStrictEqual(response); }); }); describe('handleHighLevelStatsResponse', () => { // filterPath makes it easy to ignore anything unexpected because it will come back empty it('handles unexpected response', () => { - const clusters = handleHighLevelStatsResponse({}, product); + const clusters = handleHighLevelStatsResponse({} as any, product); - expect(clusters).to.eql({}); + expect(clusters).toStrictEqual({}); }); it('handles valid response', () => { - const clusters = handleHighLevelStatsResponse(response, product); + const clusters = handleHighLevelStatsResponse(response as any, product); - expect(clusters).to.eql(expectedClusters); + expect(clusters).toStrictEqual(expectedClusters); }); it('handles no hits response', () => { - const clusters = handleHighLevelStatsResponse({ hits: { hits: [] } }, product); + const clusters = handleHighLevelStatsResponse({ hits: { hits: [] } } as any, product); - expect(clusters).to.eql({}); + expect(clusters).toStrictEqual({}); }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts similarity index 66% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts index b87f632308e4d..f67f80940d9f4 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts @@ -5,6 +5,8 @@ */ import { get } from 'lodash'; +import { StatsCollectionConfig } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { SearchResponse } from 'elasticsearch'; import { createQuery } from './create_query'; import { INDEX_PATTERN_KIBANA, @@ -17,13 +19,40 @@ import { TELEMETRY_QUERY_SOURCE, } from '../../common/constants'; +export interface ClusterCloudStats { + name: string; + count: number; + vms: number; + regions: Array<{ region: string; count: number }>; + vm_types: Array<{ vm_type: string; count: number }>; + zones: Array<{ zone: string; count: number }>; +} + +export interface ClusterHighLevelStats { + count: number; + versions: Array<{ version: string; count: number }>; + os: { + platforms: Array<{ platform: string; count: number }>; + platformReleases: Array<{ platformRelease: string; count: number }>; + distros: Array<{ distro: string; count: number }>; + distroReleases: Array<{ distroRelease: string; count: number }>; + }; + cloud: ClusterCloudStats[] | undefined; +} + +export interface ClustersHighLevelStats { + [clusterUuid: string]: ClusterHighLevelStats; +} + +type Counter = Map; + /** * Update a counter associated with the {@code key}. * * @param {Map} map Map to update the counter for the {@code key}. * @param {String} key The key to increment a counter for. */ -function incrementByKey(map, key) { +function incrementByKey(map: Counter, key?: string) { if (!key) { return; } @@ -37,13 +66,29 @@ function incrementByKey(map, key) { map.set(key, count + 1); } +interface InternalCloudMap { + count: number; + unique: Set; + vm_type: Counter; + region: Counter; + zone: Counter; +} + +interface CloudEntry { + id: string; + name: string; + vm_type: string; + region: string; + zone: string; +} + /** * Help to reduce Cloud metrics into unidentifiable metrics (e.g., count IDs so that they can be dropped). * * @param {Map} clouds Existing cloud data by cloud name. * @param {Object} cloud Cloud object loaded from Elasticsearch data. */ -function reduceCloudForCluster(cloudMap, cloud) { +function reduceCloudForCluster(cloudMap: Map, cloud?: CloudEntry) { if (!cloud) { return; } @@ -74,22 +119,48 @@ function reduceCloudForCluster(cloudMap, cloud) { incrementByKey(cloudByName.zone, cloud.zone); } +interface InternalClusterMap { + count: number; + versions: Counter; + cloudMap: Map; + os: { + platforms: Counter; + platformReleases: Counter; + distros: Counter; + distroReleases: Counter; + }; +} + +interface OSData { + platform?: string; + platformRelease?: string; + distro?: string; + distroRelease?: string; +} + /** * Group the instances (hits) by clusters. * * @param {Array} instances Array of hits from the request containing the cluster UUID and version. * @param {String} product The product to limit too ('kibana', 'logstash', 'beats') - * @return {Map} A map of the Cluster UUID to an {@link Object} containing the {@code count} and {@code versions} {@link Map} + * + * Returns a map of the Cluster UUID to an {@link Object} containing the {@code count} and {@code versions} {@link Map} */ -function groupInstancesByCluster(instances, product) { - const clusterMap = new Map(); +function groupInstancesByCluster( + instances: Array<{ _source: T }>, + product: string +) { + const clusterMap = new Map(); // hits are sorted arbitrarily by product UUID instances.map(instance => { - const clusterUuid = get(instance, '_source.cluster_uuid'); - const version = get(instance, `_source.${product}_stats.${product}.version`); - const cloud = get(instance, `_source.${product}_stats.cloud`); - const os = get(instance, `_source.${product}_stats.os`); + const clusterUuid = instance._source.cluster_uuid; + const version: string | undefined = get( + instance, + `_source.${product}_stats.${product}.version` + ); + const cloud: CloudEntry | undefined = get(instance, `_source.${product}_stats.cloud`); + const os: OSData | undefined = get(instance, `_source.${product}_stats.os`); if (clusterUuid) { let cluster = clusterMap.get(clusterUuid); @@ -134,16 +205,12 @@ function groupInstancesByCluster(instances, product) { * { [keyName]: key1, count: value1 }, * { [keyName]: key2, count: value2 } * ] - * - * @param {Map} map [description] - * @param {String} keyName [description] - * @return {Array} [description] */ -function mapToList(map, keyName) { - const list = []; +function mapToList(map: Map, keyName: string): T[] { + const list: T[] = []; for (const [key, count] of map) { - list.push({ [keyName]: key, count }); + list.push(({ [keyName]: key, count } as unknown) as T); } return list; @@ -154,7 +221,7 @@ function mapToList(map, keyName) { * * @param {*} product The product id, which should be in the constants file */ -function getIndexPatternForStackProduct(product) { +function getIndexPatternForStackProduct(product: string) { switch (product) { case KIBANA_SYSTEM_ID: return INDEX_PATTERN_KIBANA; @@ -176,23 +243,41 @@ function getIndexPatternForStackProduct(product) { * @param {Date} start Start time to limit the stats * @param {Date} end End time to limit the stats * @param {String} product The product to limit too ('kibana', 'logstash', 'beats') - * @return {Promise} Object keyed by the cluster UUIDs to make grouping easier. + * + * Returns an object keyed by the cluster UUIDs to make grouping easier. */ -export function getHighLevelStats(server, callCluster, clusterUuids, start, end, product) { - return fetchHighLevelStats( +export async function getHighLevelStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'], + product: string +) { + const response = await fetchHighLevelStats( server, callCluster, clusterUuids, start, end, product - ).then(response => handleHighLevelStatsResponse(response, product)); + ); + return handleHighLevelStatsResponse(response, product); } -export async function fetchHighLevelStats(server, callCluster, clusterUuids, start, end, product) { +export async function fetchHighLevelStats< + T extends { cluster_uuid?: string } = { cluster_uuid?: string } +>( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'] | undefined, + end: StatsCollectionConfig['end'] | undefined, + product: string +): Promise> { const config = server.config(); const isKibanaIndex = product === KIBANA_SYSTEM_ID; - const filters = [{ terms: { cluster_uuid: clusterUuids } }]; + const filters: object[] = [{ terms: { cluster_uuid: clusterUuids } }]; // we should supply this from a parameter in the future so that this remains generic if (isKibanaIndex) { @@ -257,13 +342,17 @@ export async function fetchHighLevelStats(server, callCluster, clusterUuids, sta * * @param {Object} response The response from the aggregation * @param {String} product The product to limit too ('kibana', 'logstash', 'beats') - * @return {Object} Object keyed by the cluster UUIDs to make grouping easier. + * + * Returns an object keyed by the cluster UUIDs to make grouping easier. */ -export function handleHighLevelStatsResponse(response, product) { - const instances = get(response, 'hits.hits', []); +export function handleHighLevelStatsResponse( + response: SearchResponse<{ cluster_uuid?: string }>, + product: string +) { + const instances = response.hits?.hits || []; const clusterMap = groupInstancesByCluster(instances, product); - const clusters = {}; + const clusters: ClustersHighLevelStats = {}; for (const [clusterUuid, cluster] of clusterMap) { // it's unlikely this will be an array of more than one, but it is one just incase @@ -271,14 +360,15 @@ export function handleHighLevelStatsResponse(response, product) { // remap the clouds (most likely singular or empty) for (const [name, cloud] of cluster.cloudMap) { - clouds.push({ + const cloudStats: ClusterCloudStats = { name, count: cloud.count, vms: cloud.unique.size, regions: mapToList(cloud.region, 'region'), vm_types: mapToList(cloud.vm_type, 'vm_type'), zones: mapToList(cloud.zone, 'zone'), - }); + }; + clouds.push(cloudStats); } // map stats for product by cluster so that it can be joined with ES cluster stats diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_kibana_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts similarity index 79% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_kibana_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts index 98e0afa28fba3..0092e848c827b 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__tests__/get_kibana_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts @@ -4,19 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getUsageStats, combineStats, rollUpTotals, ensureTimeSpan } from '../get_kibana_stats'; -import expect from '@kbn/expect'; +import { + getUsageStats, + combineStats, + rollUpTotals, + ensureTimeSpan, + KibanaUsageStats, +} from './get_kibana_stats'; +import { SearchResponse } from 'elasticsearch'; describe('Get Kibana Stats', () => { describe('Make a map of usage stats for each cluster', () => { - it('passes through if there are no kibana instances', () => { - const rawStats = {}; - expect(getUsageStats(rawStats)).to.eql({}); + test('passes through if there are no kibana instances', () => { + const rawStats = {} as SearchResponse; + expect(getUsageStats(rawStats)).toStrictEqual({}); }); describe('with single cluster', () => { describe('single index', () => { - it('for a single unused instance', () => { + test('for a single unused instance', () => { const rawStats = { hits: { hits: [ @@ -39,7 +45,7 @@ describe('Get Kibana Stats', () => { }, ], }, - }; + } as any; const expected = { clusterone: { dashboard: { total: 0 }, @@ -53,10 +59,10 @@ describe('Get Kibana Stats', () => { }, }; - expect(getUsageStats(rawStats)).to.eql(expected); + expect(getUsageStats(rawStats)).toStrictEqual(expected); }); - it('for a single instance of active usage', () => { + test('for a single instance of active usage', () => { const rawStats = { hits: { hits: [ @@ -79,7 +85,7 @@ describe('Get Kibana Stats', () => { }, ], }, - }; + } as any; const expected = { clusterone: { dashboard: { total: 1 }, @@ -92,11 +98,49 @@ describe('Get Kibana Stats', () => { plugins: {}, }, }; + expect(getUsageStats(rawStats)).toStrictEqual(expected); + }); - expect(getUsageStats(rawStats)).to.eql(expected); + test('it merges the plugin stats and kibana', () => { + const rawStats = { + hits: { + hits: [ + { + _source: { + cluster_uuid: 'clusterone', + kibana_stats: { + kibana: { version: '7.0.0-alpha1-test02' }, + usage: { + dashboard: { total: 1 }, + visualization: { total: 3 }, + search: { total: 1 }, + index_pattern: { total: 1 }, + graph_workspace: { total: 1 }, + timelion_sheet: { total: 1 }, + index: '.kibana-test-01', + }, + }, + }, + }, + ], + }, + } as any; + const expected = { + clusterone: { + dashboard: { total: 1 }, + visualization: { total: 3 }, + search: { total: 1 }, + index_pattern: { total: 1 }, + graph_workspace: { total: 1 }, + timelion_sheet: { total: 1 }, + indices: 1, + plugins: {}, + }, + }; + expect(getUsageStats(rawStats)).toStrictEqual(expected); }); - it('flattens x-pack stats', () => { + test('flattens x-pack stats', () => { const rawStats = { hits: { hits: [ @@ -126,8 +170,9 @@ describe('Get Kibana Stats', () => { }, ], }, - }; - expect(getUsageStats(rawStats)).to.eql({ + } as any; + + expect(getUsageStats(rawStats)).toStrictEqual({ clusterone: { dashboard: { total: 1 }, visualization: { total: 3 }, @@ -143,7 +188,7 @@ describe('Get Kibana Stats', () => { }); describe('separate indices', () => { - it('with one unused instance', () => { + test('with one unused instance', () => { const rawStats = { hits: { hits: [ @@ -200,7 +245,7 @@ describe('Get Kibana Stats', () => { }, ], }, - }; + } as any; const expected = { clusterone: { dashboard: { total: 1 }, @@ -213,11 +258,10 @@ describe('Get Kibana Stats', () => { plugins: {}, }, }; - - expect(getUsageStats(rawStats)).to.eql(expected); + expect(getUsageStats(rawStats)).toStrictEqual(expected); }); - it('with all actively used instances', () => { + test('with all actively used instances', () => { const rawStats = { hits: { hits: [ @@ -274,7 +318,7 @@ describe('Get Kibana Stats', () => { }, ], }, - }; + } as any; const expected = { clusterone: { dashboard: { total: 4 }, @@ -287,15 +331,14 @@ describe('Get Kibana Stats', () => { plugins: {}, }, }; - - expect(getUsageStats(rawStats)).to.eql(expected); + expect(getUsageStats(rawStats)).toStrictEqual(expected); }); }); }); describe('with multiple clusters', () => { describe('separate indices', () => { - it('with all actively used instances', () => { + test('with all actively used instances', () => { const rawStats = { hits: { hits: [ @@ -369,7 +412,7 @@ describe('Get Kibana Stats', () => { }, ], }, - }; + } as any; const expected = { clusterone: { dashboard: { total: 4 }, @@ -392,29 +435,28 @@ describe('Get Kibana Stats', () => { plugins: {}, }, }; - - expect(getUsageStats(rawStats)).to.eql(expected); + expect(getUsageStats(rawStats)).toStrictEqual(expected); }); }); }); }); describe('Combines usage stats with high-level stats', () => { - it('passes through if there are no kibana instances', () => { + test('passes through if there are no kibana instances', () => { const highLevelStats = {}; const usageStats = {}; - expect(combineStats(highLevelStats, usageStats)).to.eql({}); + expect(combineStats(highLevelStats, usageStats)).toStrictEqual({}); }); describe('adds usage stats to high-level stats', () => { - it('for a single cluster', () => { + test('for a single cluster', () => { const highLevelStats = { clusterone: { count: 2, versions: [{ count: 2, version: '7.0.0-alpha1-test12' }], }, - }; + } as any; const usageStats = { clusterone: { dashboard: { total: 1 }, @@ -428,7 +470,7 @@ describe('Get Kibana Stats', () => { }, }; - expect(combineStats(highLevelStats, usageStats)).to.eql({ + expect(combineStats(highLevelStats, usageStats)).toStrictEqual({ clusterone: { count: 2, dashboard: { total: 1 }, @@ -444,7 +486,7 @@ describe('Get Kibana Stats', () => { }); }); - it('for multiple single clusters', () => { + test('for multiple single clusters', () => { const highLevelStats = { clusterone: { count: 2, @@ -454,7 +496,7 @@ describe('Get Kibana Stats', () => { count: 1, versions: [{ count: 1, version: '7.0.0-alpha1-test14' }], }, - }; + } as any; const usageStats = { clusterone: { dashboard: { total: 1 }, @@ -478,7 +520,7 @@ describe('Get Kibana Stats', () => { }, }; - expect(combineStats(highLevelStats, usageStats)).to.eql({ + expect(combineStats(highLevelStats, usageStats)).toStrictEqual({ clusterone: { count: 2, dashboard: { total: 1 }, @@ -508,16 +550,16 @@ describe('Get Kibana Stats', () => { }); describe('if usage stats are empty', () => { - it('returns just high-level stats', () => { + test('returns just high-level stats', () => { const highLevelStats = { clusterone: { count: 2, versions: [{ count: 2, version: '7.0.0-alpha1-test12' }], }, - }; + } as any; const usageStats = undefined; - expect(combineStats(highLevelStats, usageStats)).to.eql({ + expect(combineStats(highLevelStats, usageStats)).toStrictEqual({ clusterone: { count: 2, versions: [{ count: 2, version: '7.0.0-alpha1-test12' }], @@ -528,64 +570,64 @@ describe('Get Kibana Stats', () => { }); describe('Rolls up stats when there are multiple Kibana indices for a cluster', () => { - it('by combining the `total` fields where previous was 0', () => { - const rollUp = { my_field: { total: 0 } }; + test('by combining the `total` fields where previous was 0', () => { + const rollUp = { my_field: { total: 0 } } as any; const addOn = { my_field: { total: 1 } }; - expect(rollUpTotals(rollUp, addOn, 'my_field')).to.eql({ total: 1 }); + expect(rollUpTotals(rollUp, addOn, 'my_field' as any)).toStrictEqual({ total: 1 }); }); - it('by combining the `total` fields with > 1 for previous and addOn', () => { - const rollUp = { my_field: { total: 1 } }; + test('by combining the `total` fields with > 1 for previous and addOn', () => { + const rollUp = { my_field: { total: 1 } } as any; const addOn = { my_field: { total: 3 } }; - expect(rollUpTotals(rollUp, addOn, 'my_field')).to.eql({ total: 4 }); + expect(rollUpTotals(rollUp, addOn, 'my_field' as any)).toStrictEqual({ total: 4 }); }); }); describe('Ensure minimum time difference', () => { - it('should return start and end as is when none are provided', () => { + test('should return start and end as is when none are provided', () => { const { start, end } = ensureTimeSpan(undefined, undefined); - expect(start).to.be.undefined; - expect(end).to.be.undefined; + expect(start).toBe(undefined); + expect(end).toBe(undefined); }); - it('should return start and end as is when only end is provided', () => { + test('should return start and end as is when only end is provided', () => { const initialEnd = '2020-01-01T00:00:00Z'; const { start, end } = ensureTimeSpan(undefined, initialEnd); - expect(start).to.be.undefined; - expect(end).to.be.equal(initialEnd); + expect(start).toBe(undefined); + expect(end).toEqual(initialEnd); }); - it('should return start and end as is because they are already 24h away', () => { + test('should return start and end as is because they are already 24h away', () => { const initialStart = '2019-12-31T00:00:00Z'; const initialEnd = '2020-01-01T00:00:00Z'; const { start, end } = ensureTimeSpan(initialStart, initialEnd); - expect(start).to.be.equal(initialStart); - expect(end).to.be.equal(initialEnd); + expect(start).toEqual(initialStart); + expect(end).toEqual(initialEnd); }); - it('should return start and end as is because they are already 24h+ away', () => { + test('should return start and end as is because they are already 24h+ away', () => { const initialStart = '2019-12-31T00:00:00Z'; const initialEnd = '2020-01-01T01:00:00Z'; const { start, end } = ensureTimeSpan(initialStart, initialEnd); - expect(start).to.be.equal(initialStart); - expect(end).to.be.equal(initialEnd); + expect(start).toEqual(initialStart); + expect(end).toEqual(initialEnd); }); - it('should modify start to a date 24h before end', () => { + test('should modify start to a date 24h before end', () => { const initialStart = '2020-01-01T00:00:00.000Z'; const initialEnd = '2020-01-01T01:00:00.000Z'; const { start, end } = ensureTimeSpan(initialStart, initialEnd); - expect(start).to.be.equal('2019-12-31T01:00:00.000Z'); - expect(end).to.be.equal(initialEnd); + expect(start).toEqual('2019-12-31T01:00:00.000Z'); + expect(end).toEqual(initialEnd); }); - it('should modify start to a date 24h before now', () => { + test('should modify start to a date 24h before now', () => { const initialStart = new Date().toISOString(); const { start, end } = ensureTimeSpan(initialStart, undefined); - expect(start).to.not.be.equal(initialStart); - expect(end).to.be.undefined; + expect(start).not.toBe(initialStart); + expect(end).toBe(undefined); }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts similarity index 58% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.js rename to x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts index 1e22507c5baf4..e2ad64ce04c6b 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts @@ -5,30 +5,78 @@ */ import moment from 'moment'; -import { get, isEmpty, omit } from 'lodash'; +import { isEmpty } from 'lodash'; +import { StatsCollectionConfig } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { SearchResponse } from 'elasticsearch'; import { KIBANA_SYSTEM_ID, TELEMETRY_COLLECTION_INTERVAL } from '../../common/constants'; -import { fetchHighLevelStats, handleHighLevelStatsResponse } from './get_high_level_stats'; +import { + fetchHighLevelStats, + handleHighLevelStatsResponse, + ClustersHighLevelStats, + ClusterHighLevelStats, +} from './get_high_level_stats'; -export function rollUpTotals(rolledUp, addOn, field) { - const rolledUpTotal = get(rolledUp, [field, 'total'], 0); - const addOnTotal = get(addOn, [field, 'total'], 0); +export function rollUpTotals( + rolledUp: ClusterUsageStats, + addOn: { [key: string]: { total?: number } | undefined }, + field: Exclude +) { + const rolledUpTotal = rolledUp[field]?.total || 0; + const addOnTotal = addOn[field]?.total || 0; return { total: rolledUpTotal + addOnTotal }; } -export function rollUpIndices(rolledUp) { +export function rollUpIndices(rolledUp: ClusterUsageStats) { return rolledUp.indices + 1; } +export interface KibanaUsageStats { + cluster_uuid: string; + kibana_stats?: { + usage?: { + index?: string; + } & { + [plugin: string]: { + total: number; + }; + }; + }; +} + +export interface ClusterUsageStats { + dashboard?: { total: number }; + visualization?: { total: number }; + search?: { total: number }; + index_pattern?: { total: number }; + graph_workspace?: { total: number }; + timelion_sheet?: { total: number }; + indices: number; + plugins?: { + xpack?: unknown; + [plugin: string]: unknown; + }; +} + +export interface ClustersUsageStats { + [clusterUuid: string]: ClusterUsageStats | undefined; +} + +export interface KibanaClusterStat extends Partial, ClusterHighLevelStats {} + +export interface KibanaStats { + [clusterUuid: string]: KibanaClusterStat; +} + /* * @param {Object} rawStats */ -export function getUsageStats(rawStats) { +export function getUsageStats(rawStats: SearchResponse) { const clusterIndexCache = new Set(); - const rawStatsHits = get(rawStats, 'hits.hits', []); + const rawStatsHits = rawStats.hits?.hits || []; // get usage stats per cluster / .kibana index return rawStatsHits.reduce((accum, currInstance) => { - const clusterUuid = get(currInstance, '_source.cluster_uuid'); - const currUsage = get(currInstance, '_source.kibana_stats.usage', {}); + const clusterUuid = currInstance._source.cluster_uuid; + const currUsage = currInstance._source.kibana_stats?.usage || {}; const clusterIndexCombination = clusterUuid + currUsage.index; // return early if usage data is empty or if this cluster/index has already been processed @@ -39,7 +87,7 @@ export function getUsageStats(rawStats) { // Get the stats that were read from any number of different .kibana indices in the cluster, // roll them up into cluster-wide totals - const rolledUpStats = get(accum, clusterUuid, { indices: 0 }); + const rolledUpStats = accum[clusterUuid] || { indices: 0 }; const stats = { dashboard: rollUpTotals(rolledUpStats, currUsage, 'dashboard'), visualization: rollUpTotals(rolledUpStats, currUsage, 'visualization'), @@ -51,21 +99,22 @@ export function getUsageStats(rawStats) { }; // Get the stats provided by telemetry collectors. - const pluginsNested = omit(currUsage, [ - 'index', - 'dashboard', - 'visualization', - 'search', - 'index_pattern', - 'graph_workspace', - 'timelion_sheet', - ]); + const { + index, + dashboard, + visualization, + search, + index_pattern, + graph_workspace, + timelion_sheet, + xpack, + ...pluginsTop + } = currUsage; // Stats filtered by telemetry collectors need to be flattened since they're pulled in a generic way. // A plugin might not provide flat stats if it implements formatForBulkUpload in its collector. // e.g: we want `xpack.reporting` to just be `reporting` - const top = omit(pluginsNested, 'xpack'); - const plugins = { ...top, ...pluginsNested.xpack }; + const plugins = { ...pluginsTop, ...xpack }; return { ...accum, @@ -74,10 +123,13 @@ export function getUsageStats(rawStats) { plugins, }, }; - }, {}); + }, {} as ClustersUsageStats); } -export function combineStats(highLevelStats, usageStats = {}) { +export function combineStats( + highLevelStats: ClustersHighLevelStats, + usageStats: ClustersUsageStats = {} +) { return Object.keys(highLevelStats).reduce((accum, currClusterUuid) => { return { ...accum, @@ -86,7 +138,7 @@ export function combineStats(highLevelStats, usageStats = {}) { ...usageStats[currClusterUuid], }, }; - }, {}); + }, {} as KibanaStats); } /** @@ -96,7 +148,10 @@ export function combineStats(highLevelStats, usageStats = {}) { * @param {date} [start] The start time from which to get the telemetry data * @param {date} [end] The end time from which to get the telemetry data */ -export function ensureTimeSpan(start, end) { +export function ensureTimeSpan( + start?: StatsCollectionConfig['start'], + end?: StatsCollectionConfig['end'] +) { // We only care if we have a start date, because that's the limit that might make us lose the document if (start) { const duration = moment.duration(TELEMETRY_COLLECTION_INTERVAL, 'milliseconds'); @@ -117,9 +172,15 @@ export function ensureTimeSpan(start, end) { * Monkey-patch the modules from get_high_level_stats and add in the * specialized usage data that comes with kibana stats (kibana_stats.usage). */ -export async function getKibanaStats(server, callCluster, clusterUuids, start, end) { +export async function getKibanaStats( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[], + start: StatsCollectionConfig['start'], + end: StatsCollectionConfig['end'] +) { const { start: safeStart, end: safeEnd } = ensureTimeSpan(start, end); - const rawStats = await fetchHighLevelStats( + const rawStats = await fetchHighLevelStats( server, callCluster, clusterUuids, diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts index 49a925d1dad0b..f0fda5229cb5c 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts @@ -5,7 +5,6 @@ */ import { telemetryCollectionManager } from '../../../../../../src/legacy/core_plugins/telemetry/server'; -// @ts-ignore import { getAllStats } from './get_all_stats'; import { getClusterUuids } from './get_cluster_uuids'; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js deleted file mode 100644 index d2385dc900bb2..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import axios from 'axios'; -import axiosXhrAdapter from 'axios/lib/adapters/xhr'; -import chrome from 'ui/chrome'; // eslint-disable-line import/no-unresolved -import { MANAGEMENT_BREADCRUMB } from 'ui/management'; // eslint-disable-line import/no-unresolved -import { fatalError, toastNotifications } from 'ui/notify'; // eslint-disable-line import/no-unresolved - -import { init as initBreadcrumb } from '../../../public/app/services/breadcrumb'; -import { init as initHttp } from '../../../public/app/services/http'; -import { init as initNotification } from '../../../public/app/services/notification'; -import { init as initUiMetric } from '../../../public/app/services/ui_metric'; -import { init as initHttpRequests } from './http_requests'; - -export const setupEnvironment = () => { - chrome.breadcrumbs = { - set: () => {}, - }; - // axios has a $http like interface so using it to simulate $http - initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path); - initBreadcrumb(() => {}, MANAGEMENT_BREADCRUMB); - initNotification(toastNotifications, fatalError); - initUiMetric(() => () => {}); - - const { server, httpRequestsMockHelpers } = initHttpRequests(); - - return { - server, - httpRequestsMockHelpers, - }; -}; diff --git a/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.test.ts b/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.test.ts deleted file mode 100644 index 476fbee7fb6a0..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { deserializeCluster, serializeCluster } from './cluster_serialization'; - -describe('cluster_serialization', () => { - describe('deserializeCluster()', () => { - it('should throw an error for invalid arguments', () => { - expect(() => deserializeCluster('foo', 'bar')).toThrowError(); - }); - - it('should deserialize a complete cluster object', () => { - expect( - deserializeCluster('test_cluster', { - seeds: ['localhost:9300'], - connected: true, - num_nodes_connected: 1, - max_connections_per_cluster: 3, - initial_connect_timeout: '30s', - skip_unavailable: false, - transport: { - ping_schedule: '-1', - compress: false, - }, - }) - ).toEqual({ - name: 'test_cluster', - seeds: ['localhost:9300'], - isConnected: true, - connectedNodesCount: 1, - maxConnectionsPerCluster: 3, - initialConnectTimeout: '30s', - skipUnavailable: false, - transportPingSchedule: '-1', - transportCompress: false, - }); - }); - - it('should deserialize a cluster object without transport information', () => { - expect( - deserializeCluster('test_cluster', { - seeds: ['localhost:9300'], - connected: true, - num_nodes_connected: 1, - max_connections_per_cluster: 3, - initial_connect_timeout: '30s', - skip_unavailable: false, - }) - ).toEqual({ - name: 'test_cluster', - seeds: ['localhost:9300'], - isConnected: true, - connectedNodesCount: 1, - maxConnectionsPerCluster: 3, - initialConnectTimeout: '30s', - skipUnavailable: false, - }); - }); - - it('should deserialize a cluster object with arbitrary missing properties', () => { - expect( - deserializeCluster('test_cluster', { - seeds: ['localhost:9300'], - connected: true, - num_nodes_connected: 1, - initial_connect_timeout: '30s', - transport: { - compress: false, - }, - }) - ).toEqual({ - name: 'test_cluster', - seeds: ['localhost:9300'], - isConnected: true, - connectedNodesCount: 1, - initialConnectTimeout: '30s', - transportCompress: false, - }); - }); - }); - - describe('serializeCluster()', () => { - it('should throw an error for invalid arguments', () => { - expect(() => serializeCluster('foo')).toThrowError(); - }); - - it('should serialize a complete cluster object to only dynamic properties', () => { - expect( - serializeCluster({ - name: 'test_cluster', - seeds: ['localhost:9300'], - isConnected: true, - connectedNodesCount: 1, - maxConnectionsPerCluster: 3, - initialConnectTimeout: '30s', - skipUnavailable: false, - transportPingSchedule: '-1', - transportCompress: false, - }) - ).toEqual({ - persistent: { - cluster: { - remote: { - test_cluster: { - seeds: ['localhost:9300'], - skip_unavailable: false, - }, - }, - }, - }, - }); - }); - - it('should serialize a cluster object with missing properties', () => { - expect( - serializeCluster({ - name: 'test_cluster', - seeds: ['localhost:9300'], - }) - ).toEqual({ - persistent: { - cluster: { - remote: { - test_cluster: { - seeds: ['localhost:9300'], - skip_unavailable: null, - }, - }, - }, - }, - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.ts b/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.ts deleted file mode 100644 index 07ea79d42b800..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/common/cluster_serialization.ts +++ /dev/null @@ -1,71 +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 deserializeCluster(name: string, esClusterObject: any): any { - if (!name || !esClusterObject || typeof esClusterObject !== 'object') { - throw new Error('Unable to deserialize cluster'); - } - - const { - seeds, - connected: isConnected, - num_nodes_connected: connectedNodesCount, - max_connections_per_cluster: maxConnectionsPerCluster, - initial_connect_timeout: initialConnectTimeout, - skip_unavailable: skipUnavailable, - transport, - } = esClusterObject; - - let deserializedClusterObject: any = { - name, - seeds, - isConnected, - connectedNodesCount, - maxConnectionsPerCluster, - initialConnectTimeout, - skipUnavailable, - }; - - if (transport) { - const { ping_schedule: transportPingSchedule, compress: transportCompress } = transport; - - deserializedClusterObject = { - ...deserializedClusterObject, - transportPingSchedule, - transportCompress, - }; - } - - // It's unnecessary to send undefined values back to the client, so we can remove them. - Object.keys(deserializedClusterObject).forEach(key => { - if (deserializedClusterObject[key] === undefined) { - delete deserializedClusterObject[key]; - } - }); - - return deserializedClusterObject; -} - -export function serializeCluster(deserializedClusterObject: any): any { - if (!deserializedClusterObject || typeof deserializedClusterObject !== 'object') { - throw new Error('Unable to serialize cluster'); - } - - const { name, seeds, skipUnavailable } = deserializedClusterObject; - - return { - persistent: { - cluster: { - remote: { - [name]: { - seeds: seeds ? seeds : null, - skip_unavailable: skipUnavailable !== undefined ? skipUnavailable : null, - }, - }, - }, - }, - }; -} diff --git a/x-pack/legacy/plugins/remote_clusters/common/index.ts b/x-pack/legacy/plugins/remote_clusters/common/index.ts index 8f80b3b7dc6a3..c643f549cbfe1 100644 --- a/x-pack/legacy/plugins/remote_clusters/common/index.ts +++ b/x-pack/legacy/plugins/remote_clusters/common/index.ts @@ -4,20 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; -import { LICENSE_TYPE_BASIC, LicenseType } from '../../../common/constants'; - export const PLUGIN = { ID: 'remote_clusters', - // Remote Clusters are used in both CCS and CCR, and CCS is available for all licenses. - MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC as LicenseType, - getI18nName: (): string => { - return i18n.translate('xpack.remoteClusters.appName', { - defaultMessage: 'Remote Clusters', - }); - }, }; - -export const API_BASE_PATH = '/api/remote_clusters'; - -export { deserializeCluster, serializeCluster } from './cluster_serialization'; diff --git a/x-pack/legacy/plugins/remote_clusters/index.ts b/x-pack/legacy/plugins/remote_clusters/index.ts index 5dd823e09eb8b..37b2224f8d7c2 100644 --- a/x-pack/legacy/plugins/remote_clusters/index.ts +++ b/x-pack/legacy/plugins/remote_clusters/index.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; import { resolve } from 'path'; import { PLUGIN } from './common'; @@ -13,18 +12,11 @@ export function remoteClusters(kibana: any) { id: PLUGIN.ID, configPrefix: 'xpack.remote_clusters', publicDir: resolve(__dirname, 'public'), - // xpack_main is required for license checking. - require: ['kibana', 'elasticsearch', 'xpack_main', 'index_management'], + require: ['kibana'], uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), - managementSections: ['plugins/remote_clusters'], - injectDefaultVars(server: Legacy.Server) { - const config = server.config(); - return { - remoteClustersUiEnabled: config.get('xpack.remote_clusters.ui.enabled'), - }; - }, }, + // TODO: Remove once CCR has migrated to NP config(Joi: any) { return Joi.object({ // display menu item @@ -41,6 +33,6 @@ export function remoteClusters(kibana: any) { config.get('xpack.remote_clusters.enabled') && config.get('xpack.index_management.enabled') ); }, - init(server: any) {}, + init() {}, }); } diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/_index.scss b/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/_index.scss deleted file mode 100644 index c85cb36c5dc5a..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/_index.scss +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 1. Prevent inherited flexbox layout from compressing this element on IE. - */ - .remoteClustersConnectionStatus__message { - flex-basis: auto !important; /* 1 */ -} diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/http.ts b/x-pack/legacy/plugins/remote_clusters/public/app/services/http.ts deleted file mode 100644 index 54dadf0ae3cb1..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/http.ts +++ /dev/null @@ -1,39 +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. - */ - -let _httpClient: any; -let _prependBasePath: any; - -export function init(httpClient: any, prependBasePath: any): void { - _httpClient = httpClient; - _prependBasePath = prependBasePath; -} - -export function getFullPath(path: string): string { - const apiPrefix = _prependBasePath('/api/remote_clusters'); - - if (path) { - return `${apiPrefix}/${path}`; - } - - return apiPrefix; -} - -export function sendPost(path: string, payload: any): any { - return _httpClient.post(getFullPath(path), payload); -} - -export function sendGet(path: string): any { - return _httpClient.get(getFullPath(path)); -} - -export function sendPut(path: string, payload: any): any { - return _httpClient.put(getFullPath(path), payload); -} - -export function sendDelete(path: string): any { - return _httpClient.delete(getFullPath(path)); -} diff --git a/x-pack/legacy/plugins/remote_clusters/public/index.html b/x-pack/legacy/plugins/remote_clusters/public/index.html deleted file mode 100644 index 4de600769fb40..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -

- diff --git a/x-pack/legacy/plugins/remote_clusters/public/index.js b/x-pack/legacy/plugins/remote_clusters/public/index.js deleted file mode 100644 index 0a08011dd71a0..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Plugin as RemoteClustersPlugin } from './plugin'; -import { createShim } from './shim'; - -const { coreStart, pluginsStart } = createShim(); -const remoteClustersPlugin = new RemoteClustersPlugin(); -remoteClustersPlugin.start(coreStart, pluginsStart); diff --git a/x-pack/legacy/plugins/remote_clusters/public/index.scss b/x-pack/legacy/plugins/remote_clusters/public/index.scss index 4618b005312a5..4ae11323642d8 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/index.scss +++ b/x-pack/legacy/plugins/remote_clusters/public/index.scss @@ -1,8 +1,7 @@ // Import the EUI global scope so we can use EUI constants @import 'src/legacy/ui/public/styles/_styling_constants'; -@import './app/sections/remote_cluster_list/components/connection_status/index'; -// Index management plugin styles +// Remote clusters plugin styles // Prefix all styles with "remoteClusters" to avoid conflicts. // Examples @@ -16,8 +15,14 @@ * as the 'Reset to defaults' link is added to and removed from the DOM. * 2. Fix the positioning. */ - .remoteClusterSkipIfUnavailableSwitch { justify-content: flex-start !important; /* 1 */ padding-top: $euiSizeS !important; } + +/** + * 1. Prevent inherited flexbox layout from compressing this element on IE. + */ + .remoteClustersConnectionStatus__message { + flex-basis: auto !important; /* 1 */ +} diff --git a/x-pack/legacy/plugins/remote_clusters/public/plugin.js b/x-pack/legacy/plugins/remote_clusters/public/plugin.js deleted file mode 100644 index 8dbcfb98859cd..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/plugin.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { unmountComponentAtNode } from 'react-dom'; -import { i18n } from '@kbn/i18n'; -import routes from 'ui/routes'; - -import template from './index.html'; -import { renderReact } from './app'; -import { CRUD_APP_BASE_PATH } from './app/constants'; -import { setUserHasLeftApp, setRedirect } from './app/services'; -import { init as initBreadcrumbs } from './app/services/breadcrumb'; -import { init as initDocumentation } from './app/services/documentation'; -import { init as initHttp } from './app/services/http'; -import { init as initUiMetric } from './app/services/ui_metric'; -import { init as initNotification } from './app/services/notification'; - -const REACT_ROOT_ID = 'remoteClustersReactRoot'; - -export class Plugin { - start(coreStart, pluginsStart) { - const { - i18n: { Context }, - chrome: { setBreadcrumbs }, - notifications: { toasts }, - fatalError, - http: { - basePath: { prepend: prependBasePath }, - }, - injectedMetadata: { getInjectedVar }, - documentation: { elasticWebsiteUrl, docLinkVersion }, - } = coreStart; - - if (getInjectedVar('remoteClustersUiEnabled')) { - const { - management: { getSection, breadcrumb: managementBreadcrumb }, - uiMetric: { createUiStatsReporter }, - } = pluginsStart; - - const esSection = getSection('elasticsearch'); - esSection.register('remote_clusters', { - visible: true, - display: i18n.translate('xpack.remoteClusters.appTitle', { - defaultMessage: 'Remote Clusters', - }), - order: 5, - url: `#${CRUD_APP_BASE_PATH}/list`, - }); - - // Initialize services - initBreadcrumbs(setBreadcrumbs, managementBreadcrumb); - initDocumentation(`${elasticWebsiteUrl}guide/en/elasticsearch/reference/${docLinkVersion}/`); - initUiMetric(createUiStatsReporter); - initNotification(toasts, fatalError); - - const unmountReactApp = () => { - const appElement = document.getElementById(REACT_ROOT_ID); - if (appElement) { - unmountComponentAtNode(appElement); - } - }; - - // NOTE: The New Platform will implicitly handle much of this logic by mounting the app at - // the base route. - routes.when(`${CRUD_APP_BASE_PATH}/:view?/:id?`, { - template, - controllerAs: 'remoteClusters', - controller: class RemoteClustersController { - constructor($scope, $route, $http, kbnUrl) { - // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, - // e.g. to check license status per request. - initHttp($http, prependBasePath); - - setRedirect(path => { - $scope.$evalAsync(() => { - kbnUrl.redirect(path); - }); - }); - - // If returning to the app, we'll need to reset this state. - setUserHasLeftApp(false); - - // React-router's will cause this controller to re-execute without the $destroy - // handler being called. This means the app will re-mount, so we need to unmount it first - // here. - unmountReactApp(); - - $scope.$$postDigest(() => { - const appElement = document.getElementById(REACT_ROOT_ID); - if (appElement) { - renderReact(appElement, Context); - } - - const appRoute = $route.current; - const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - const isNavigationInApp = - currentRoute.$$route.template === appRoute.$$route.template; - - // When we navigate within the app, prevent Angular from re-matching the route and - // rebuilding the app. - if (isNavigationInApp) { - $route.current = appRoute; - } else { - // Set internal flag so we can prevent reacting to the route change internally. - setUserHasLeftApp(true); - } - }); - - $scope.$on('$destroy', () => { - stopListeningForLocationChange(); - unmountReactApp(); - }); - }); - } - }, - }); - } - } -} diff --git a/x-pack/legacy/plugins/remote_clusters/public/shim.ts b/x-pack/legacy/plugins/remote_clusters/public/shim.ts deleted file mode 100644 index 83975fa4bd0fe..0000000000000 --- a/x-pack/legacy/plugins/remote_clusters/public/shim.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npStart } from 'ui/new_platform'; -import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; -import { fatalError } from 'ui/notify'; -import { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL } from 'ui/documentation_links'; - -import { createUiStatsReporter } from '../../../../../src/legacy/core_plugins/ui_metric/public'; - -export function createShim() { - const { - core: { chrome, i18n, notifications, http, injectedMetadata }, - } = npStart; - - return { - coreStart: { - chrome, - i18n, - notifications, - fatalError, - injectedMetadata, - http, - documentation: { - elasticWebsiteUrl: ELASTIC_WEBSITE_URL, - docLinkVersion: DOC_LINK_VERSION, - }, - }, - pluginsStart: { - management: { - getSection: management.getSection.bind(management), - breadcrumb: MANAGEMENT_BREADCRUMB, - }, - uiMetric: { - createUiStatsReporter, - }, - }, - }; -} diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts index 1b7ba3c90bab1..468caf93ec5dd 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts @@ -5,7 +5,7 @@ */ import { cryptoFactory } from '../../../server/lib/crypto'; -import { createMockServer } from '../../../test_helpers/create_mock_server'; +import { createMockServer } from '../../../test_helpers'; import { Logger } from '../../../types'; import { decryptJobHeaders } from './decrypt_job_headers'; diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts index 070bdb4314af9..eedb742ad7597 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts @@ -4,13 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createMockServer } from '../../../test_helpers/create_mock_server'; -import { getConditionalHeaders, getCustomLogo } from './index'; +import { createMockReportingCore, createMockServer } from '../../../test_helpers'; +import { ReportingCore } from '../../../server'; import { JobDocPayload } from '../../../types'; import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { getConditionalHeaders, getCustomLogo } from './index'; +let mockReportingPlugin: ReportingCore; let mockServer: any; -beforeEach(() => { +beforeEach(async () => { + mockReportingPlugin = await createMockReportingCore(); mockServer = createMockServer(''); }); @@ -148,56 +151,76 @@ describe('conditions', () => { }); test('uses basePath from job when creating saved object service', async () => { + const mockGetSavedObjectsClient = jest.fn(); + mockReportingPlugin.getSavedObjectsClient = mockGetSavedObjectsClient; + const permittedHeaders = { foo: 'bar', baz: 'quix', }; - const conditionalHeaders = await getConditionalHeaders({ job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); - - const logo = 'custom-logo'; - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - const jobBasePath = '/sbp/s/marketing'; await getCustomLogo({ + reporting: mockReportingPlugin, job: { basePath: jobBasePath } as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe( - jobBasePath - ); + const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath; + expect(getBasePath()).toBe(jobBasePath); }); test(`uses basePath from server if job doesn't have a basePath when creating saved object service`, async () => { + const mockGetSavedObjectsClient = jest.fn(); + mockReportingPlugin.getSavedObjectsClient = mockGetSavedObjectsClient; + const permittedHeaders = { foo: 'bar', baz: 'quix', }; - const conditionalHeaders = await getConditionalHeaders({ job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); - const logo = 'custom-logo'; - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - await getCustomLogo({ + reporting: mockReportingPlugin, job: {} as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe( - '/sbp' - ); + const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath; + expect(getBasePath()).toBe(`/sbp`); + expect(mockGetSavedObjectsClient.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "getBasePath": [Function], + "headers": Object { + "baz": "quix", + "foo": "bar", + }, + "path": "/", + "raw": Object { + "req": Object { + "url": "/", + }, + }, + "route": Object { + "settings": Object {}, + }, + "url": Object { + "href": "/", + }, + }, + ] + `); }); describe('config formatting', () => { diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts index ff2c44026315d..fa53f474dfba7 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts @@ -4,12 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createMockServer } from '../../../test_helpers/create_mock_server'; -import { getConditionalHeaders, getCustomLogo } from './index'; +import { ReportingCore } from '../../../server'; +import { createMockReportingCore, createMockServer } from '../../../test_helpers'; +import { ServerFacade } from '../../../types'; import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { getConditionalHeaders, getCustomLogo } from './index'; -let mockServer: any; -beforeEach(() => { +let mockReportingPlugin: ReportingCore; +let mockServer: ServerFacade; +beforeEach(async () => { + mockReportingPlugin = await createMockReportingCore(); mockServer = createMockServer(''); }); @@ -19,6 +23,17 @@ test(`gets logo from uiSettings`, async () => { baz: 'quix', }; + const mockGet = jest.fn(); + mockGet.mockImplementationOnce((...args: any[]) => { + if (args[0] === 'xpackReporting:customPdfLogo') { + return 'purple pony'; + } + throw new Error('wrong caller args!'); + }); + mockReportingPlugin.getUiSettingsServiceFactory = jest.fn().mockResolvedValue({ + get: mockGet, + }); + const conditionalHeaders = await getConditionalHeaders({ job: {} as JobDocPayloadPDF, filteredHeaders: permittedHeaders, @@ -26,12 +41,12 @@ test(`gets logo from uiSettings`, async () => { }); const { logo } = await getCustomLogo({ + reporting: mockReportingPlugin, job: {} as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - - expect(mockServer.uiSettingsServiceFactory().get).toBeCalledWith('xpackReporting:customPdfLogo'); + expect(mockGet).toBeCalledWith('xpackReporting:customPdfLogo'); + expect(logo).toBe('purple pony'); }); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts index 0059276f6df71..7af5edab41ab7 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts @@ -5,14 +5,17 @@ */ import { UI_SETTINGS_CUSTOM_PDF_LOGO } from '../../../common/constants'; +import { ReportingCore } from '../../../server'; import { ConditionalHeaders, ServerFacade } from '../../../types'; import { JobDocPayloadPDF } from '../../printable_pdf/types'; // Logo is PDF only export const getCustomLogo = async ({ + reporting, server, job, conditionalHeaders, }: { + reporting: ReportingCore; server: ServerFacade; job: JobDocPayloadPDF; conditionalHeaders: ConditionalHeaders; @@ -27,19 +30,12 @@ export const getCustomLogo = async ({ getBasePath: () => job.basePath || serverBasePath, path: '/', route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, + url: { href: '/' }, + raw: { req: { url: '/' } }, }; - const savedObjects = server.savedObjects; - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient(fakeRequest); - const uiSettings = server.uiSettingsServiceFactory({ savedObjectsClient }); + const savedObjectsClient = await reporting.getSavedObjectsClient(fakeRequest); + const uiSettings = await reporting.getUiSettingsServiceFactory(savedObjectsClient); const logo: string = await uiSettings.get(UI_SETTINGS_CUSTOM_PDF_LOGO); return { conditionalHeaders, logo }; }; diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts index 9b2a065427f70..27e772195f726 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createMockServer } from '../../../test_helpers/create_mock_server'; +import { createMockServer } from '../../../test_helpers'; import { ServerFacade } from '../../../types'; import { JobDocPayloadPNG } from '../../png/types'; import { JobDocPayloadPDF } from '../../printable_pdf/types'; diff --git a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts index 9fd3ee391ddbb..62b5e29e88ecf 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts @@ -5,19 +5,19 @@ */ import * as Rx from 'rxjs'; -import { first, concatMap, take, toArray, mergeMap } from 'rxjs/operators'; -import { ServerFacade, CaptureConfig, HeadlessChromiumDriverFactory } from '../../../../types'; -import { ScreenshotResults, ScreenshotObservableOpts } from './types'; -import { injectCustomCss } from './inject_css'; -import { openUrl } from './open_url'; -import { waitForRenderComplete } from './wait_for_render'; -import { getNumberOfItems } from './get_number_of_items'; -import { waitForElementsToBeInDOM } from './wait_for_dom_elements'; -import { getTimeRange } from './get_time_range'; +import { concatMap, first, mergeMap, take, toArray } from 'rxjs/operators'; +import { CaptureConfig, HeadlessChromiumDriverFactory, ServerFacade } from '../../../../types'; import { getElementPositionAndAttributes } from './get_element_position_data'; +import { getNumberOfItems } from './get_number_of_items'; import { getScreenshots } from './get_screenshots'; +import { getTimeRange } from './get_time_range'; +import { injectCustomCss } from './inject_css'; +import { openUrl } from './open_url'; import { scanPage } from './scan_page'; import { skipTelemetry } from './skip_telemetry'; +import { ScreenshotObservableOpts, ScreenshotResults } from './types'; +import { waitForElementsToBeInDOM } from './wait_for_dom_elements'; +import { waitForRenderComplete } from './wait_for_render'; export function screenshotsObservableFactory( server: ServerFacade, 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 063ac7f77704c..7ea67277015ab 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 @@ -4,19 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ReportingCore } from '../../../server'; import { cryptoFactory } from '../../../server/lib/crypto'; import { - CreateJobFactory, ConditionalHeaders, - ServerFacade, - RequestFacade, + CreateJobFactory, ESQueueCreateJobFn, + RequestFacade, + ServerFacade, } from '../../../types'; import { JobParamsDiscoverCsv } from '../types'; export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(server: ServerFacade) { +>> = function createJobFactoryFn(reporting: ReportingCore, server: ServerFacade) { const crypto = cryptoFactory(server); return async function createJob( diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js index b21d628332027..f12916b734dbf 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.js @@ -9,6 +9,7 @@ import sinon from 'sinon'; import nodeCrypto from '@elastic/node-crypto'; import { CancellationToken } from '../../../common/cancellation_token'; import { fieldFormats } from '../../../../../../../src/plugins/data/server'; +import { createMockReportingCore } from '../../../test_helpers'; import { LevelLogger } from '../../../server/lib/level_logger'; import { executeJobFactory } from './execute_job'; import { setFieldFormats } from '../../../server/services'; @@ -36,16 +37,19 @@ describe('CSV Execute Job', function() { let encryptedHeaders; let cancellationToken; + let mockReportingPlugin; let mockServer; let clusterStub; let callAsCurrentUserStub; - let uiSettingsGetStub; const mockElasticsearch = { dataClient: { asScoped: () => clusterStub, }, }; + const mockUiSettingsClient = { + get: sinon.stub(), + }; beforeAll(async function() { const crypto = nodeCrypto({ encryptionKey }); @@ -53,6 +57,8 @@ describe('CSV Execute Job', function() { }); beforeEach(async function() { + mockReportingPlugin = await createMockReportingCore(); + mockReportingPlugin.getUiSettingsServiceFactory = () => mockUiSettingsClient; cancellationToken = new CancellationToken(); defaultElasticsearchResponse = { @@ -70,9 +76,8 @@ describe('CSV Execute Job', function() { .resolves(defaultElasticsearchResponse); const configGetStub = sinon.stub(); - uiSettingsGetStub = sinon.stub(); - uiSettingsGetStub.withArgs('csv:separator').returns(','); - uiSettingsGetStub.withArgs('csv:quoteValues').returns(true); + mockUiSettingsClient.get.withArgs('csv:separator').returns(','); + mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(true); setFieldFormats({ fieldFormatServiceFactory: function() { @@ -90,26 +95,11 @@ describe('CSV Execute Job', function() { }); mockServer = { - expose: function() {}, - plugins: { - elasticsearch: { - getCluster: function() { - return clusterStub; - }, - }, - }, config: function() { return { get: configGetStub, }; }, - savedObjects: { - getScopedSavedObjectsClient: sinon.stub(), - }, - uiSettingsServiceFactory: sinon.stub().returns({ - get: uiSettingsGetStub, - }), - log: function() {}, }; mockServer .config() @@ -125,83 +115,14 @@ describe('CSV Execute Job', function() { .returns({}); }); - describe('calls getScopedSavedObjectsClient with request', function() { - it('containing decrypted headers', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); - await executeJob( - 'job456', - { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, - cancellationToken - ); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.calledOnce).toBe(true); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.firstCall.args[0].headers).toEqual( - headers - ); - }); - - it(`containing getBasePath() returning server's basePath if the job doesn't have one`, async function() { - const serverBasePath = '/foo-server/basePath/'; - mockServer - .config() - .get.withArgs('server.basePath') - .returns(serverBasePath); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); - await executeJob( - 'job456', - { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, - cancellationToken - ); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.calledOnce).toBe(true); - expect( - mockServer.savedObjects.getScopedSavedObjectsClient.firstCall.args[0].getBasePath() - ).toEqual(serverBasePath); - }); - - it(`containing getBasePath() returning job's basePath if the job has one`, async function() { - const serverBasePath = '/foo-server/basePath/'; - mockServer - .config() - .get.withArgs('server.basePath') - .returns(serverBasePath); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); - const jobBasePath = 'foo-job/basePath/'; - await executeJob( - 'job789', - { - headers: encryptedHeaders, - fields: [], - searchRequest: { index: null, body: null }, - basePath: jobBasePath, - }, - cancellationToken - ); - expect(mockServer.savedObjects.getScopedSavedObjectsClient.calledOnce).toBe(true); - expect( - mockServer.savedObjects.getScopedSavedObjectsClient.firstCall.args[0].getBasePath() - ).toEqual(jobBasePath); - }); - }); - - describe('uiSettings', function() { - it('passed scoped SavedObjectsClient to uiSettingsServiceFactory', async function() { - const returnValue = Symbol(); - mockServer.savedObjects.getScopedSavedObjectsClient.returns(returnValue); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); - await executeJob( - 'job456', - { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, - cancellationToken - ); - expect(mockServer.uiSettingsServiceFactory.calledOnce).toBe(true); - expect(mockServer.uiSettingsServiceFactory.firstCall.args[0].savedObjectsClient).toBe( - returnValue - ); - }); - }); - describe('basic Elasticsearch call behavior', function() { it('should decrypt encrypted headers and pass to callAsCurrentUser', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); await executeJob( 'job456', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -217,7 +138,12 @@ describe('CSV Execute Job', function() { testBody: true, }; - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const job = { headers: encryptedHeaders, fields: [], @@ -244,7 +170,12 @@ describe('CSV Execute Job', function() { _scroll_id: scrollId, }); callAsCurrentUserStub.onSecondCall().resolves(defaultElasticsearchResponse); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); await executeJob( 'job456', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -258,7 +189,12 @@ describe('CSV Execute Job', function() { }); it('should not execute scroll if there are no hits from the search', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); await executeJob( 'job456', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -288,7 +224,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); await executeJob( 'job456', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -323,7 +264,12 @@ describe('CSV Execute Job', function() { _scroll_id: lastScrollId, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); await executeJob( 'job456', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -351,7 +297,12 @@ describe('CSV Execute Job', function() { _scroll_id: lastScrollId, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -381,7 +332,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -409,7 +365,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['=SUM(A1:A2)', 'two'], @@ -437,7 +398,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -465,7 +431,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -485,7 +456,12 @@ describe('CSV Execute Job', function() { describe('Elasticsearch call errors', function() { it('should reject Promise if search call errors out', async function() { callAsCurrentUserStub.rejects(new Error()); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -504,7 +480,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); callAsCurrentUserStub.onSecondCall().rejects(new Error()); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -525,7 +506,12 @@ describe('CSV Execute Job', function() { _scroll_id: undefined, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -546,7 +532,12 @@ describe('CSV Execute Job', function() { _scroll_id: undefined, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -574,7 +565,12 @@ describe('CSV Execute Job', function() { _scroll_id: undefined, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -602,7 +598,12 @@ describe('CSV Execute Job', function() { _scroll_id: undefined, }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: [], @@ -638,7 +639,12 @@ describe('CSV Execute Job', function() { }); it('should stop calling Elasticsearch when cancellationToken.cancel is called', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); executeJob( 'job345', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -653,7 +659,12 @@ describe('CSV Execute Job', function() { }); it(`shouldn't call clearScroll if it never got a scrollId`, async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); executeJob( 'job345', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -667,7 +678,12 @@ describe('CSV Execute Job', function() { }); it('should call clearScroll if it got a scrollId', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); executeJob( 'job345', { headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null } }, @@ -685,7 +701,12 @@ describe('CSV Execute Job', function() { describe('csv content', function() { it('should write column headers to output, even if there are no results', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -696,8 +717,13 @@ describe('CSV Execute Job', function() { }); it('should use custom uiSettings csv:separator for header', async function() { - uiSettingsGetStub.withArgs('csv:separator').returns(';'); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + mockUiSettingsClient.get.withArgs('csv:separator').returns(';'); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -708,8 +734,13 @@ describe('CSV Execute Job', function() { }); it('should escape column headers if uiSettings csv:quoteValues is true', async function() { - uiSettingsGetStub.withArgs('csv:quoteValues').returns(true); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(true); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], @@ -720,8 +751,13 @@ describe('CSV Execute Job', function() { }); it(`shouldn't escape column headers if uiSettings csv:quoteValues is false`, async function() { - uiSettingsGetStub.withArgs('csv:quoteValues').returns(false); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + mockUiSettingsClient.get.withArgs('csv:quoteValues').returns(false); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], @@ -732,7 +768,12 @@ describe('CSV Execute Job', function() { }); it('should write column headers to output, when there are results', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ one: '1', two: '2' }], @@ -752,7 +793,12 @@ describe('CSV Execute Job', function() { }); it('should use comma separated values of non-nested fields from _source', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -773,7 +819,12 @@ describe('CSV Execute Job', function() { }); it('should concatenate the hits from multiple responses', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -801,7 +852,12 @@ describe('CSV Execute Job', function() { }); it('should use field formatters to format fields', async function() { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -846,7 +902,12 @@ describe('CSV Execute Job', function() { .get.withArgs('xpack.reporting.csv.maxSizeBytes') .returns(1); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -879,7 +940,12 @@ describe('CSV Execute Job', function() { .get.withArgs('xpack.reporting.csv.maxSizeBytes') .returns(9); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -919,7 +985,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -948,6 +1019,7 @@ describe('CSV Execute Job', function() { let maxSizeReached; beforeEach(async function() { + mockReportingPlugin.getUiSettingsServiceFactory = () => mockUiSettingsClient; mockServer .config() .get.withArgs('xpack.reporting.csv.maxSizeBytes') @@ -960,7 +1032,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -1000,7 +1077,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -1029,7 +1111,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], @@ -1058,7 +1145,12 @@ describe('CSV Execute Job', function() { _scroll_id: 'scrollId', }); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, mockLogger); + const executeJob = await executeJobFactory( + mockReportingPlugin, + mockServer, + mockElasticsearch, + mockLogger + ); const jobParams = { headers: encryptedHeaders, fields: ['one', 'two'], diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts index 9f94a755cf655..1579985891053 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts @@ -4,20 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import Hapi from 'hapi'; import { i18n } from '@kbn/i18n'; -import { ElasticsearchServiceSetup, KibanaRequest } from '../../../../../../../src/core/server'; +import Hapi from 'hapi'; +import { + ElasticsearchServiceSetup, + IUiSettingsClient, + KibanaRequest, +} from '../../../../../../../src/core/server'; import { CSV_JOB_TYPE } from '../../../common/constants'; +import { ReportingCore } from '../../../server'; import { cryptoFactory } from '../../../server/lib'; +import { getFieldFormats } from '../../../server/services'; import { ESQueueWorkerExecuteFn, ExecuteJobFactory, Logger, ServerFacade } from '../../../types'; import { JobDocPayloadDiscoverCsv } from '../types'; import { fieldFormatMapFactory } from './lib/field_format_map'; import { createGenerateCsv } from './lib/generate_csv'; -import { getFieldFormats } from '../../../server/services'; export const executeJobFactory: ExecuteJobFactory> = function executeJobFactoryFn( +>> = async function executeJobFactoryFn( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, parentLogger: Logger @@ -40,83 +46,78 @@ export const executeJobFactory: ExecuteJobFactory { + let decryptedHeaders; + try { + decryptedHeaders = await crypto.decrypt(headers); + } catch (err) { + logger.error(err); + throw new Error( + i18n.translate( + 'xpack.reporting.exportTypes.csv.executeJob.failedToDecryptReportJobDataErrorMessage', + { + defaultMessage: 'Failed to decrypt report job data. Please ensure that {encryptionKey} is set and re-generate this report. {err}', + values: { encryptionKey: 'xpack.reporting.encryptionKey', err: err.toString() }, + } + ) + ); // prettier-ignore + } + return decryptedHeaders; + }; - const fakeRequest = { - headers: decryptedHeaders, + const fakeRequest = KibanaRequest.from({ + headers: await decryptHeaders(), // This is used by the spaces SavedObjectClientWrapper to determine the existing space. // We use the basePath from the saved job, which we'll have post spaces being implemented; // or we use the server base path, which uses the default space getBasePath: () => basePath || serverBasePath, path: '/', route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - }; + url: { href: '/' }, + raw: { req: { url: '/' } }, + } as Hapi.Request); + + const { callAsCurrentUser } = elasticsearch.dataClient.asScoped(fakeRequest); + const callEndpoint = (endpoint: string, clientParams = {}, options = {}) => + callAsCurrentUser(endpoint, clientParams, options); - const { callAsCurrentUser } = elasticsearch.dataClient.asScoped( - KibanaRequest.from(fakeRequest as Hapi.Request) - ); - const callEndpoint = (endpoint: string, clientParams = {}, options = {}) => { - return callAsCurrentUser(endpoint, clientParams, options); + const savedObjectsClient = await reporting.getSavedObjectsClient(fakeRequest); + const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); + + const getFormatsMap = async (client: IUiSettingsClient) => { + const fieldFormats = await getFieldFormats().fieldFormatServiceFactory(client); + return fieldFormatMapFactory(indexPatternSavedObject, fieldFormats); }; - const savedObjects = server.savedObjects; - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient( - (fakeRequest as unknown) as KibanaRequest - ); - const uiConfig = server.uiSettingsServiceFactory({ - savedObjectsClient, - }); + const getUiSettings = async (client: IUiSettingsClient) => { + const [separator, quoteValues, timezone] = await Promise.all([ + client.get('csv:separator'), + client.get('csv:quoteValues'), + client.get('dateFormat:tz'), + ]); - const [formatsMap, uiSettings] = await Promise.all([ - (async () => { - const fieldFormats = await getFieldFormats().fieldFormatServiceFactory(uiConfig); - return fieldFormatMapFactory(indexPatternSavedObject, fieldFormats); - })(), - (async () => { - const [separator, quoteValues, timezone] = await Promise.all([ - uiConfig.get('csv:separator'), - uiConfig.get('csv:quoteValues'), - uiConfig.get('dateFormat:tz'), - ]); + if (timezone === 'Browser') { + logger.warn( + i18n.translate('xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting', { + defaultMessage: 'Kibana Advanced Setting "{dateFormatTimezone}" is set to "Browser". Dates will be formatted as UTC to avoid ambiguity.', + values: { dateFormatTimezone: 'dateFormat:tz' } + }) + ); // prettier-ignore + } - if (timezone === 'Browser') { - jobLogger.warn( - `Kibana Advanced Setting "dateFormat:tz" is set to "Browser". Dates will be formatted as UTC to avoid ambiguity.` - ); - } + return { + separator, + quoteValues, + timezone, + }; + }; - return { - separator, - quoteValues, - timezone, - }; - })(), + const [formatsMap, uiSettings] = await Promise.all([ + getFormatsMap(uiSettingsClient), + getUiSettings(uiSettingsClient), ]); const generateCsv = createGenerateCsv(jobLogger); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/field_format_map.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/field_format_map.ts index e1459e195d9f6..dac963635c469 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/field_format_map.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/field_format_map.ts @@ -9,15 +9,7 @@ import { FieldFormatConfig, IFieldFormatsRegistry, } from '../../../../../../../../src/plugins/data/server'; - -interface IndexPatternSavedObject { - attributes: { - fieldFormatMap: string; - }; - id: string; - type: string; - version: string; -} +import { IndexPatternSavedObject } from '../../../../types'; /** * Create a map of FieldFormat instances for index pattern fields diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts index ddef2aa0a6268..17072d311b35f 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts @@ -5,9 +5,10 @@ */ import { notFound, notImplemented } from 'boom'; -import { get } from 'lodash'; import { ElasticsearchServiceSetup } from 'kibana/server'; +import { get } from 'lodash'; import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../../common/constants'; +import { ReportingCore } from '../../../../server'; import { cryptoFactory } from '../../../../server/lib'; import { CreateJobFactory, @@ -37,6 +38,7 @@ interface VisData { export const createJobFactory: CreateJobFactory> = function createJobFactoryFn( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, parentLogger: Logger diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts index b1b7b7d818200..6bb3e73fcfe84 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchServiceSetup } from 'kibana/server'; import { CONTENT_TYPE_CSV, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; +import { ReportingCore } from '../../../server'; import { cryptoFactory } from '../../../server/lib'; import { ExecuteJobFactory, @@ -22,13 +23,15 @@ import { createGenerateCsv } from './lib'; export const executeJobFactory: ExecuteJobFactory> = function executeJobFactoryFn( +>> = async function executeJobFactoryFn( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, parentLogger: Logger ) { const crypto = cryptoFactory(server); const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'execute-job']); + const generateCsv = createGenerateCsv(reporting, server, elasticsearch, parentLogger); return async function executeJob( jobId: string | null, @@ -86,11 +89,8 @@ export const executeJobFactory: ExecuteJobFactory { +const getEsQueryConfig = async (config: IUiSettingsClient) => { const configs = await Promise.all([ config.get('query:allowLeadingWildcards'), config.get('query:queryString:options'), @@ -49,7 +53,7 @@ const getEsQueryConfig = async (config: any) => { } as EsQueryConfig; }; -const getUiSettings = async (config: any) => { +const getUiSettings = async (config: IUiSettingsClient) => { const configs = await Promise.all([config.get('csv:separator'), config.get('csv:quoteValues')]); const [separator, quoteValues] = configs; return { separator, quoteValues }; @@ -57,14 +61,14 @@ const getUiSettings = async (config: any) => { export async function generateCsvSearch( req: RequestFacade, + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, logger: Logger, searchPanel: SearchPanel, jobParams: JobParamsDiscoverCsv ): Promise { - const { savedObjects, uiSettingsServiceFactory } = server; - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient( + const savedObjectsClient = await reporting.getSavedObjectsClient( KibanaRequest.from(req.getRawRequest()) ); const { indexPatternSavedObjectId, timerange } = searchPanel; @@ -73,7 +77,8 @@ export async function generateCsvSearch( savedObjectsClient, indexPatternSavedObjectId ); - const uiConfig = uiSettingsServiceFactory({ savedObjectsClient }); + + const uiConfig = await reporting.getUiSettingsServiceFactory(savedObjectsClient); const esQueryConfig = await getEsQueryConfig(uiConfig); const { 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 3f03246106d3e..a6911e1f14704 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 @@ -4,20 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validateUrls } from '../../../../common/validate_urls'; +import { ReportingCore } from '../../../../server'; +import { cryptoFactory } from '../../../../server/lib/crypto'; import { + ConditionalHeaders, CreateJobFactory, - ServerFacade, - RequestFacade, ESQueueCreateJobFn, - ConditionalHeaders, + RequestFacade, + ServerFacade, } from '../../../../types'; -import { validateUrls } from '../../../../common/validate_urls'; -import { cryptoFactory } from '../../../../server/lib/crypto'; import { JobParamsPNG } from '../../types'; export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(server: ServerFacade) { +>> = function createJobFactoryFn(reporting: ReportingCore, server: ServerFacade) { const crypto = cryptoFactory(server); return async function createJob( diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js index bb33ef9c19a1d..c0c21119e1d53 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js @@ -6,6 +6,7 @@ import * as Rx from 'rxjs'; import { memoize } from 'lodash'; +import { createMockReportingCore } from '../../../../test_helpers'; import { cryptoFactory } from '../../../../server/lib/crypto'; import { executeJobFactory } from './index'; import { generatePngObservableFactory } from '../lib/generate_png'; @@ -19,7 +20,11 @@ const cancellationToken = { let config; let mockServer; -beforeEach(() => { +let mockReporting; + +beforeEach(async () => { + mockReporting = await createMockReportingCore(); + config = { 'xpack.reporting.encryptionKey': 'testencryptionkey', 'server.basePath': '/sbp', @@ -27,18 +32,11 @@ beforeEach(() => { 'server.port': 5601, }; mockServer = { - expose: () => {}, // NOTE: this is for oncePerServer config: memoize(() => ({ get: jest.fn() })), info: { protocol: 'http', }, - savedObjects: { - getScopedSavedObjectsClient: jest.fn(), - }, - uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), - log: jest.fn(), }; - mockServer.config().get.mockImplementation(key => { return config[key]; }); @@ -67,9 +65,12 @@ test(`passes browserTimezone to generatePng`, async () => { const generatePngObservable = generatePngObservableFactory(); generatePngObservable.mockReturnValue(Rx.of(Buffer.from(''))); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); + const executeJob = await executeJobFactory( + mockReporting, + mockServer, + mockElasticsearch, + getMockLogger() + ); const browserTimezone = 'UTC'; await executeJob( 'pngJobId', @@ -87,9 +88,15 @@ test(`passes browserTimezone to generatePng`, async () => { }); test(`returns content_type of application/png`, async () => { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); + const executeJob = await executeJobFactory( + mockReporting, + mockServer, + mockElasticsearch, + getMockLogger(), + { + browserDriverFactory: {}, + } + ); const encryptedHeaders = await encryptHeaders({}); const generatePngObservable = generatePngObservableFactory(); @@ -109,9 +116,15 @@ test(`returns content of generatePng getBuffer base64 encoded`, async () => { const generatePngObservable = generatePngObservableFactory(); generatePngObservable.mockReturnValue(Rx.of(Buffer.from(testContent))); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); + const executeJob = await executeJobFactory( + mockReporting, + mockServer, + mockElasticsearch, + getMockLogger(), + { + browserDriverFactory: {}, + } + ); const encryptedHeaders = await encryptHeaders({}); const { content } = await executeJob( 'pngJobId', diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts index c9f370197da66..5cde245080914 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts @@ -7,14 +7,9 @@ import * as Rx from 'rxjs'; import { ElasticsearchServiceSetup } from 'kibana/server'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; +import { ReportingCore } from '../../../../server'; import { PNG_JOB_TYPE } from '../../../../common/constants'; -import { - ServerFacade, - ExecuteJobFactory, - ESQueueWorkerExecuteFn, - HeadlessChromiumDriverFactory, - Logger, -} from '../../../../types'; +import { ServerFacade, ExecuteJobFactory, ESQueueWorkerExecuteFn, Logger } from '../../../../types'; import { decryptJobHeaders, omitBlacklistedHeaders, @@ -26,12 +21,13 @@ import { generatePngObservableFactory } from '../lib/generate_png'; type QueuedPngExecutorFactory = ExecuteJobFactory>; -export const executeJobFactory: QueuedPngExecutorFactory = function executeJobFactoryFn( +export const executeJobFactory: QueuedPngExecutorFactory = async function executeJobFactoryFn( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - parentLogger: Logger, - { browserDriverFactory }: { browserDriverFactory: HeadlessChromiumDriverFactory } + parentLogger: Logger ) { + const browserDriverFactory = await reporting.getBrowserDriverFactory(); const generatePngObservable = generatePngObservableFactory(server, browserDriverFactory); const logger = parentLogger.clone([PNG_JOB_TYPE, 'execute']); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/create_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/create_job/index.ts index a8cc71175cffe..656c99991e1f6 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/create_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/create_job/index.ts @@ -4,20 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validateUrls } from '../../../../common/validate_urls'; +import { ReportingCore } from '../../../../server'; +import { cryptoFactory } from '../../../../server/lib/crypto'; import { + ConditionalHeaders, CreateJobFactory, ESQueueCreateJobFn, - ServerFacade, RequestFacade, - ConditionalHeaders, + ServerFacade, } from '../../../../types'; -import { validateUrls } from '../../../../common/validate_urls'; -import { cryptoFactory } from '../../../../server/lib/crypto'; import { JobParamsPDF } from '../../types'; export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(server: ServerFacade) { +>> = function createJobFactoryFn(reporting: ReportingCore, server: ServerFacade) { const crypto = cryptoFactory(server); return async function createJobFn( diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js index c21d39f4922cb..cc6b298bebdc5 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js @@ -6,6 +6,7 @@ import * as Rx from 'rxjs'; import { memoize } from 'lodash'; +import { createMockReportingCore } from '../../../../test_helpers'; import { cryptoFactory } from '../../../../server/lib/crypto'; import { executeJobFactory } from './index'; import { generatePdfObservableFactory } from '../lib/generate_pdf'; @@ -19,7 +20,11 @@ const cancellationToken = { let config; let mockServer; -beforeEach(() => { +let mockReporting; + +beforeEach(async () => { + mockReporting = await createMockReportingCore(); + config = { 'xpack.reporting.encryptionKey': 'testencryptionkey', 'server.basePath': '/sbp', @@ -27,18 +32,11 @@ beforeEach(() => { 'server.port': 5601, }; mockServer = { - expose: jest.fn(), - log: jest.fn(), config: memoize(() => ({ get: jest.fn() })), info: { protocol: 'http', }, - savedObjects: { - getScopedSavedObjectsClient: jest.fn(), - }, - uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), }; - mockServer.config().get.mockImplementation(key => { return config[key]; }); @@ -60,38 +58,13 @@ const encryptHeaders = async headers => { return await crypto.encrypt(headers); }; -test(`passes browserTimezone to generatePdf`, async () => { - const encryptedHeaders = await encryptHeaders({}); - - const generatePdfObservable = generatePdfObservableFactory(); - generatePdfObservable.mockReturnValue(Rx.of(Buffer.from(''))); - - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); - const browserTimezone = 'UTC'; - await executeJob( - 'pdfJobId', - { relativeUrls: [], browserTimezone, headers: encryptedHeaders }, - cancellationToken - ); - - expect(mockServer.uiSettingsServiceFactory().get).toBeCalledWith('xpackReporting:customPdfLogo'); - expect(generatePdfObservable).toBeCalledWith( - expect.any(LevelLogger), - undefined, - [], - browserTimezone, - expect.anything(), - undefined, - undefined - ); -}); - test(`returns content_type of application/pdf`, async () => { - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); + const executeJob = await executeJobFactory( + mockReporting, + mockServer, + mockElasticsearch, + getMockLogger() + ); const encryptedHeaders = await encryptHeaders({}); const generatePdfObservable = generatePdfObservableFactory(); @@ -111,9 +84,12 @@ test(`returns content of generatePdf getBuffer base64 encoded`, async () => { const generatePdfObservable = generatePdfObservableFactory(); generatePdfObservable.mockReturnValue(Rx.of(Buffer.from(testContent))); - const executeJob = executeJobFactory(mockServer, mockElasticsearch, getMockLogger(), { - browserDriverFactory: {}, - }); + const executeJob = await executeJobFactory( + mockReporting, + mockServer, + mockElasticsearch, + getMockLogger() + ); const encryptedHeaders = await encryptHeaders({}); const { content } = await executeJob( 'pdfJobId', diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts index 162376e31216e..e8461862bee82 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts @@ -7,13 +7,8 @@ import * as Rx from 'rxjs'; import { ElasticsearchServiceSetup } from 'kibana/server'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; -import { - ServerFacade, - ExecuteJobFactory, - ESQueueWorkerExecuteFn, - HeadlessChromiumDriverFactory, - Logger, -} from '../../../../types'; +import { ReportingCore } from '../../../../server'; +import { ServerFacade, ExecuteJobFactory, ESQueueWorkerExecuteFn, Logger } from '../../../../types'; import { JobDocPayloadPDF } from '../../types'; import { PDF_JOB_TYPE } from '../../../../common/constants'; import { generatePdfObservableFactory } from '../lib/generate_pdf'; @@ -27,12 +22,13 @@ import { type QueuedPdfExecutorFactory = ExecuteJobFactory>; -export const executeJobFactory: QueuedPdfExecutorFactory = function executeJobFactoryFn( +export const executeJobFactory: QueuedPdfExecutorFactory = async function executeJobFactoryFn( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - parentLogger: Logger, - { browserDriverFactory }: { browserDriverFactory: HeadlessChromiumDriverFactory } + parentLogger: Logger ) { + const browserDriverFactory = await reporting.getBrowserDriverFactory(); const generatePdfObservable = generatePdfObservableFactory(server, browserDriverFactory); const logger = parentLogger.clone([PDF_JOB_TYPE, 'execute']); @@ -43,7 +39,7 @@ export const executeJobFactory: QueuedPdfExecutorFactory = function executeJobFa mergeMap(() => decryptJobHeaders({ server, job, logger })), map(decryptedHeaders => omitBlacklistedHeaders({ job, decryptedHeaders })), map(filteredHeaders => getConditionalHeaders({ server, job, filteredHeaders })), - mergeMap(conditionalHeaders => getCustomLogo({ server, job, conditionalHeaders })), + mergeMap(conditionalHeaders => getCustomLogo({ reporting, server, job, conditionalHeaders })), mergeMap(({ logo, conditionalHeaders }) => { const urls = getFullUrls({ server, job }); diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts index cbafc4b1ecc4b..9ce4e807f8ef8 100644 --- a/x-pack/legacy/plugins/reporting/index.ts +++ b/x-pack/legacy/plugins/reporting/index.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants'; import { config as reportingConfig } from './config'; import { legacyInit } from './server/legacy'; -import { ReportingConfigOptions, ReportingPluginSpecOptions } from './types.d'; +import { ReportingConfigOptions, ReportingPluginSpecOptions } from './types'; const kbToBase64Length = (kb: number) => { return Math.floor((kb * 1024 * 8) / 6); diff --git a/x-pack/legacy/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap b/x-pack/legacy/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap index 3b6d7a0b5f003..b5304c6020c43 100644 --- a/x-pack/legacy/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap +++ b/x-pack/legacy/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap @@ -91,10 +91,7 @@ Array [ > (); + private readonly pluginStart$ = new Rx.ReplaySubject(); + private exportTypesRegistry = getExportTypesRegistry(); + + constructor(private logger: LevelLogger) {} + + legacySetup( + xpackMainPlugin: XPackMainPlugin, + reporting: ReportingPluginSpecOptions, + __LEGACY: ServerFacade, + plugins: ReportingSetupDeps + ) { + mirrorPluginStatus(xpackMainPlugin, reporting); + const checkLicense = checkLicenseFactory(this.exportTypesRegistry); + (xpackMainPlugin as any).status.once('green', () => { + // Register a function that is called whenever the xpack info changes, + // to re-compute the license check results for this plugin + xpackMainPlugin.info.feature(PLUGIN_ID).registerLicenseCheckResultsGenerator(checkLicense); + }); + // Reporting routes + registerRoutes(this, __LEGACY, plugins, this.logger); + } + + public pluginSetup(reportingSetupDeps: ReportingInternalSetup) { + this.pluginSetup$.next(reportingSetupDeps); + } + + public pluginStart(reportingStartDeps: ReportingInternalStart) { + this.pluginStart$.next(reportingStartDeps); + } + + public pluginHasStarted(): Promise { + return this.pluginStart$.pipe(first(), mapTo(true)).toPromise(); + } + + /* + * Internal module dependencies + */ + public getExportTypesRegistry() { + return this.exportTypesRegistry; + } + + public async getEsqueue(): Promise { + return (await this.getPluginStartDeps()).esqueue; + } + + public async getEnqueueJob(): Promise { + return (await this.getPluginStartDeps()).enqueueJob; + } + + public async getBrowserDriverFactory(): Promise { + return (await this.getPluginSetupDeps()).browserDriverFactory; + } + + /* + * Kibana core module dependencies + */ + private async getPluginSetupDeps() { + if (this.pluginSetupDeps) { + return this.pluginSetupDeps; + } + return await this.pluginSetup$.pipe(first()).toPromise(); + } + + private async getPluginStartDeps() { + if (this.pluginStartDeps) { + return this.pluginStartDeps; + } + return await this.pluginStart$.pipe(first()).toPromise(); + } + + public async getSavedObjectsClient(fakeRequest: KibanaRequest): Promise { + const { savedObjects } = await this.getPluginStartDeps(); + return savedObjects.getScopedClient(fakeRequest) as SavedObjectsClient; + } + + public async getUiSettingsServiceFactory( + savedObjectsClient: SavedObjectsClient + ): Promise { + const { uiSettings: uiSettingsService } = await this.getPluginStartDeps(); + const scopedUiSettingsService = uiSettingsService.asScopedToClient(savedObjectsClient); + return scopedUiSettingsService; + } +} diff --git a/x-pack/legacy/plugins/reporting/server/index.ts b/x-pack/legacy/plugins/reporting/server/index.ts index 438a3fd595a10..24e2a954415d9 100644 --- a/x-pack/legacy/plugins/reporting/server/index.ts +++ b/x-pack/legacy/plugins/reporting/server/index.ts @@ -10,3 +10,6 @@ import { ReportingPlugin as Plugin } from './plugin'; export const plugin = (context: PluginInitializerContext) => { return new Plugin(context); }; + +export { ReportingCore } from './core'; +export { ReportingPlugin } from './plugin'; diff --git a/x-pack/legacy/plugins/reporting/server/legacy.ts b/x-pack/legacy/plugins/reporting/server/legacy.ts index c80aef06cf270..336ff5f4d2ee7 100644 --- a/x-pack/legacy/plugins/reporting/server/legacy.ts +++ b/x-pack/legacy/plugins/reporting/server/legacy.ts @@ -8,7 +8,7 @@ import { PluginInitializerContext } from 'src/core/server'; import { SecurityPluginSetup } from '../../../../plugins/security/server'; import { ReportingPluginSpecOptions } from '../types'; import { plugin } from './index'; -import { LegacySetup, ReportingStartDeps } from './plugin'; +import { LegacySetup, ReportingStartDeps } from './types'; const buildLegacyDependencies = ( server: Legacy.Server, @@ -22,8 +22,6 @@ const buildLegacyDependencies = ( xpack_main: server.plugins.xpack_main, reporting: reportingPlugin, }, - savedObjects: server.savedObjects, - uiSettingsServiceFactory: server.uiSettingsServiceFactory, }); export const legacyInit = async ( @@ -33,17 +31,20 @@ export const legacyInit = async ( const coreSetup = server.newPlatform.setup.core; const pluginInstance = plugin(server.newPlatform.coreContext as PluginInitializerContext); + const __LEGACY = buildLegacyDependencies(server, reportingPlugin); await pluginInstance.setup(coreSetup, { elasticsearch: coreSetup.elasticsearch, security: server.newPlatform.setup.plugins.security as SecurityPluginSetup, usageCollection: server.newPlatform.setup.plugins.usageCollection, - __LEGACY: buildLegacyDependencies(server, reportingPlugin), + __LEGACY, }); // Schedule to call the "start" hook only after start dependencies are ready coreSetup.getStartServices().then(([core, plugins]) => pluginInstance.start(core, { + elasticsearch: coreSetup.elasticsearch, data: (plugins as ReportingStartDeps).data, + __LEGACY, }) ); }; diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts b/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts index c4e32b3ebcd99..d593e4625cdf4 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts @@ -5,29 +5,19 @@ */ import { ElasticsearchServiceSetup } from 'kibana/server'; -import { - ServerFacade, - ExportTypesRegistry, - HeadlessChromiumDriverFactory, - QueueConfig, - Logger, -} from '../../types'; +import { ESQueueInstance, ServerFacade, QueueConfig, Logger } from '../../types'; +import { ReportingCore } from '../core'; // @ts-ignore import { Esqueue } from './esqueue'; import { createWorkerFactory } from './create_worker'; import { createTaggedLogger } from './create_tagged_logger'; // TODO remove createTaggedLogger once esqueue is removed -interface CreateQueueFactoryOpts { - exportTypesRegistry: ExportTypesRegistry; - browserDriverFactory: HeadlessChromiumDriverFactory; -} - -export function createQueueFactory( +export async function createQueueFactory( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - logger: Logger, - { exportTypesRegistry, browserDriverFactory }: CreateQueueFactoryOpts -): Esqueue { + logger: Logger +): Promise { const queueConfig: QueueConfig = server.config().get('xpack.reporting.queue'); const index = server.config().get('xpack.reporting.index'); @@ -39,15 +29,12 @@ export function createQueueFactory( logger: createTaggedLogger(logger, ['esqueue', 'queue-worker']), }; - const queue: Esqueue = new Esqueue(index, queueOptions); + const queue: ESQueueInstance = new Esqueue(index, queueOptions); if (queueConfig.pollEnabled) { // create workers to poll the index for idle jobs waiting to be claimed and executed - const createWorker = createWorkerFactory(server, elasticsearch, logger, { - exportTypesRegistry, - browserDriverFactory, - }); - createWorker(queue); + const createWorker = createWorkerFactory(reporting, server, elasticsearch, logger); + await createWorker(queue); } else { logger.info( 'xpack.reporting.queue.pollEnabled is set to false. This Kibana instance ' + diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts b/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts index f5c42e5505cd1..d4d913243e18d 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts @@ -4,9 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as sinon from 'sinon'; import { ElasticsearchServiceSetup } from 'kibana/server'; -import { HeadlessChromiumDriverFactory, ServerFacade } from '../../types'; +import * as sinon from 'sinon'; +import { ReportingCore } from '../../server'; +import { createMockReportingCore } from '../../test_helpers'; +import { ServerFacade } from '../../types'; import { createWorkerFactory } from './create_worker'; // @ts-ignore import { Esqueue } from './esqueue'; @@ -33,34 +35,34 @@ const getMockLogger = jest.fn(); const getMockExportTypesRegistry = ( exportTypes: any[] = [{ executeJobFactory: executeJobFactoryStub }] -) => ({ - getAll: () => exportTypes, -}); +) => + ({ + getAll: () => exportTypes, + } as ExportTypesRegistry); describe('Create Worker', () => { let queue: Esqueue; let client: ClientMock; + let mockReporting: ReportingCore; - beforeEach(() => { + beforeEach(async () => { + mockReporting = await createMockReportingCore(); client = new ClientMock(); queue = new Esqueue('reporting-queue', { client }); executeJobFactoryStub.reset(); }); test('Creates a single Esqueue worker for Reporting', async () => { - const exportTypesRegistry = getMockExportTypesRegistry(); + mockReporting.getExportTypesRegistry = () => getMockExportTypesRegistry(); const createWorker = createWorkerFactory( + mockReporting, getMockServer(), {} as ElasticsearchServiceSetup, - getMockLogger(), - { - exportTypesRegistry: exportTypesRegistry as ExportTypesRegistry, - browserDriverFactory: {} as HeadlessChromiumDriverFactory, - } + getMockLogger() ); const registerWorkerSpy = sinon.spy(queue, 'registerWorker'); - createWorker(queue); + await createWorker(queue); sinon.assert.callCount(executeJobFactoryStub, 1); sinon.assert.callCount(registerWorkerSpy, 1); @@ -88,18 +90,16 @@ Object { { executeJobFactory: executeJobFactoryStub }, { executeJobFactory: executeJobFactoryStub }, ]); + mockReporting.getExportTypesRegistry = () => exportTypesRegistry; const createWorker = createWorkerFactory( + mockReporting, getMockServer(), {} as ElasticsearchServiceSetup, - getMockLogger(), - { - exportTypesRegistry: exportTypesRegistry as ExportTypesRegistry, - browserDriverFactory: {} as HeadlessChromiumDriverFactory, - } + getMockLogger() ); const registerWorkerSpy = sinon.spy(queue, 'registerWorker'); - createWorker(queue); + await createWorker(queue); sinon.assert.callCount(executeJobFactoryStub, 5); sinon.assert.callCount(registerWorkerSpy, 1); diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts b/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts index 2ca638f641291..3567712367608 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts @@ -5,34 +5,29 @@ */ import { ElasticsearchServiceSetup } from 'kibana/server'; -import { PLUGIN_ID } from '../../common/constants'; -import { ExportTypesRegistry, HeadlessChromiumDriverFactory } from '../../types'; import { CancellationToken } from '../../common/cancellation_token'; +import { PLUGIN_ID } from '../../common/constants'; import { ESQueueInstance, - QueueConfig, - ExportTypeDefinition, ESQueueWorkerExecuteFn, - JobDocPayload, + ExportTypeDefinition, ImmediateExecuteFn, + JobDocPayload, JobSource, + Logger, + QueueConfig, RequestFacade, ServerFacade, - Logger, } from '../../types'; +import { ReportingCore } from '../core'; // @ts-ignore untyped dependency import { events as esqueueEvents } from './esqueue'; -interface CreateWorkerFactoryOpts { - exportTypesRegistry: ExportTypesRegistry; - browserDriverFactory: HeadlessChromiumDriverFactory; -} - export function createWorkerFactory( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - logger: Logger, - { exportTypesRegistry, browserDriverFactory }: CreateWorkerFactoryOpts + logger: Logger ) { type JobDocPayloadType = JobDocPayload; const config = server.config(); @@ -41,20 +36,23 @@ export function createWorkerFactory( const kibanaId: string = config.get('server.uuid'); // Once more document types are added, this will need to be passed in - return function createWorker(queue: ESQueueInstance) { + return async function createWorker(queue: ESQueueInstance) { // export type / execute job map const jobExecutors: Map< string, ImmediateExecuteFn | ESQueueWorkerExecuteFn > = new Map(); - for (const exportType of exportTypesRegistry.getAll() as Array< - ExportTypeDefinition + for (const exportType of reporting.getExportTypesRegistry().getAll() as Array< + ExportTypeDefinition >) { // TODO: the executeJobFn should be unwrapped in the register method of the export types registry - const jobExecutor = exportType.executeJobFactory(server, elasticsearch, logger, { - browserDriverFactory, - }); + const jobExecutor = await exportType.executeJobFactory( + reporting, + server, + elasticsearch, + logger + ); jobExecutors.set(exportType.jobType, jobExecutor); } diff --git a/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts index 1da8a3795aacc..c215bdc398904 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts @@ -16,11 +16,11 @@ import { ServerFacade, RequestFacade, Logger, - ExportTypesRegistry, CaptureConfig, QueueConfig, ConditionalHeaders, } from '../../types'; +import { ReportingCore } from '../core'; interface ConfirmedJob { id: string; @@ -29,16 +29,11 @@ interface ConfirmedJob { _primary_term: number; } -interface EnqueueJobFactoryOpts { - exportTypesRegistry: ExportTypesRegistry; - esqueue: any; -} - export function enqueueJobFactory( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - parentLogger: Logger, - { exportTypesRegistry, esqueue }: EnqueueJobFactoryOpts + parentLogger: Logger ): EnqueueJobFn { const logger = parentLogger.clone(['queue-job']); const config = server.config(); @@ -56,14 +51,20 @@ export function enqueueJobFactory( ): Promise { type CreateJobFn = ESQueueCreateJobFn | ImmediateCreateJobFn; - const exportType = exportTypesRegistry.getById(exportTypeId); + const esqueue = await reporting.getEsqueue(); + const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); if (exportType == null) { throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); } // TODO: the createJobFn should be unwrapped in the register method of the export types registry - const createJob = exportType.createJobFactory(server, elasticsearch, logger) as CreateJobFn; + const createJob = exportType.createJobFactory( + reporting, + server, + elasticsearch, + logger + ) as CreateJobFn; const payload = await createJob(jobParams, headers, request); const options = { diff --git a/x-pack/legacy/plugins/reporting/server/lib/get_user.ts b/x-pack/legacy/plugins/reporting/server/lib/get_user.ts index ab02dfe0743f0..49d5c568c3981 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/get_user.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/get_user.ts @@ -7,7 +7,7 @@ import { Legacy } from 'kibana'; import { KibanaRequest } from '../../../../../../src/core/server'; import { ServerFacade } from '../../types'; -import { ReportingSetupDeps } from '../plugin'; +import { ReportingSetupDeps } from '../types'; export function getUserFactory(server: ServerFacade, security: ReportingSetupDeps['security']) { /* diff --git a/x-pack/legacy/plugins/reporting/server/lib/validate/index.ts b/x-pack/legacy/plugins/reporting/server/lib/validate/index.ts index 028d8fa143487..0fdbd858b8e3c 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/validate/index.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/validate/index.ts @@ -16,8 +16,8 @@ import { validateServerHost } from './validate_server_host'; export async function runValidations( server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - logger: Logger, - browserFactory: HeadlessChromiumDriverFactory + browserFactory: HeadlessChromiumDriverFactory, + logger: Logger ) { try { await Promise.all([ @@ -32,6 +32,7 @@ export async function runValidations( }) ); } catch (err) { + logger.error(err); logger.warning( i18n.translate('xpack.reporting.selfCheck.warning', { defaultMessage: `Reporting plugin self-check generated a warning: {err}`, diff --git a/x-pack/legacy/plugins/reporting/server/plugin.ts b/x-pack/legacy/plugins/reporting/server/plugin.ts index ef7b01f8e9c15..4f24cc16b2277 100644 --- a/x-pack/legacy/plugins/reporting/server/plugin.ts +++ b/x-pack/legacy/plugins/reporting/server/plugin.ts @@ -4,97 +4,66 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; -import { - CoreSetup, - CoreStart, - ElasticsearchServiceSetup, - Plugin, - PluginInitializerContext, -} from 'src/core/server'; -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server'; -import { SecurityPluginSetup } from '../../../../plugins/security/server'; -// @ts-ignore -import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status'; -import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; -import { PLUGIN_ID } from '../common/constants'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/server'; import { logConfiguration } from '../log_configuration'; -import { ReportingPluginSpecOptions } from '../types.d'; import { createBrowserDriverFactory } from './browsers'; -import { checkLicenseFactory, getExportTypesRegistry, LevelLogger, runValidations } from './lib'; -import { registerRoutes } from './routes'; +import { ReportingCore } from './core'; +import { createQueueFactory, enqueueJobFactory, LevelLogger, runValidations } from './lib'; import { setFieldFormats } from './services'; +import { ReportingSetup, ReportingSetupDeps, ReportingStart, ReportingStartDeps } from './types'; import { registerReportingUsageCollector } from './usage'; +// @ts-ignore no module definition +import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status'; -export interface ReportingSetupDeps { - elasticsearch: ElasticsearchServiceSetup; - usageCollection: UsageCollectionSetup; - security: SecurityPluginSetup; - __LEGACY: LegacySetup; -} - -export interface ReportingStartDeps { - data: DataPluginStart; -} - -export interface LegacySetup { - config: Legacy.Server['config']; - info: Legacy.Server['info']; - plugins: { - elasticsearch: Legacy.Server['plugins']['elasticsearch']; - xpack_main: XPackMainPlugin & { - status?: any; - }; - reporting: ReportingPluginSpecOptions; - }; - route: Legacy.Server['route']; - savedObjects: Legacy.Server['savedObjects']; - uiSettingsServiceFactory: Legacy.Server['uiSettingsServiceFactory']; -} +export class ReportingPlugin + implements Plugin { + private logger: LevelLogger; + private reportingCore: ReportingCore; -export class ReportingPlugin implements Plugin { - constructor(private context: PluginInitializerContext) {} + constructor(context: PluginInitializerContext) { + this.logger = new LevelLogger(context.logger.get('reporting')); + this.reportingCore = new ReportingCore(this.logger); + } public async setup(core: CoreSetup, plugins: ReportingSetupDeps) { const { elasticsearch, usageCollection, __LEGACY } = plugins; - const exportTypesRegistry = getExportTypesRegistry(); - let isCollectorReady = false; + const browserDriverFactory = await createBrowserDriverFactory(__LEGACY, this.logger); // required for validations :( + runValidations(__LEGACY, elasticsearch, browserDriverFactory, this.logger); // this must run early, as it sets up config defaults + + const { xpack_main: xpackMainLegacy, reporting: reportingLegacy } = __LEGACY.plugins; + this.reportingCore.legacySetup(xpackMainLegacy, reportingLegacy, __LEGACY, plugins); // Register a function with server to manage the collection of usage stats - registerReportingUsageCollector( - usageCollection, - __LEGACY, - () => isCollectorReady, - exportTypesRegistry - ); + registerReportingUsageCollector(this.reportingCore, __LEGACY, usageCollection); - const logger = new LevelLogger(this.context.logger.get('reporting')); - const browserDriverFactory = await createBrowserDriverFactory(__LEGACY, logger); + // regsister setup internals + this.reportingCore.pluginSetup({ browserDriverFactory }); - logConfiguration(__LEGACY, logger); - runValidations(__LEGACY, elasticsearch, logger, browserDriverFactory); + return {}; + } - const { xpack_main: xpackMainPlugin, reporting } = __LEGACY.plugins; - mirrorPluginStatus(xpackMainPlugin, reporting); + public async start(core: CoreStart, plugins: ReportingStartDeps) { + const { reportingCore, logger } = this; + const { elasticsearch, __LEGACY } = plugins; - const checkLicense = checkLicenseFactory(exportTypesRegistry); + const esqueue = await createQueueFactory(reportingCore, __LEGACY, elasticsearch, logger); + const enqueueJob = enqueueJobFactory(reportingCore, __LEGACY, elasticsearch, logger); - (xpackMainPlugin as any).status.once('green', () => { - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin - xpackMainPlugin.info.feature(PLUGIN_ID).registerLicenseCheckResultsGenerator(checkLicense); + this.reportingCore.pluginStart({ + savedObjects: core.savedObjects, + uiSettings: core.uiSettings, + esqueue, + enqueueJob, }); - // Post initialization of the above code, the collector is now ready to fetch its data - isCollectorReady = true; + setFieldFormats(plugins.data.fieldFormats); + logConfiguration(__LEGACY, this.logger); - // Reporting routes - registerRoutes(__LEGACY, plugins, exportTypesRegistry, browserDriverFactory, logger); + return {}; } - public start(core: CoreStart, plugins: ReportingStartDeps) { - setFieldFormats(plugins.data.fieldFormats); + public getReportingCore() { + return this.reportingCore; } } diff --git a/x-pack/legacy/plugins/reporting/server/routes/generate_from_jobparams.ts b/x-pack/legacy/plugins/reporting/server/routes/generate_from_jobparams.ts index ed761b1e684ae..49868bb7ad5d5 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/generate_from_jobparams.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/generate_from_jobparams.ts @@ -10,7 +10,7 @@ import { Legacy } from 'kibana'; import rison from 'rison-node'; import { API_BASE_URL } from '../../common/constants'; import { Logger, ReportingResponseToolkit, ServerFacade } from '../../types'; -import { ReportingSetupDeps } from '../plugin'; +import { ReportingSetupDeps } from '../types'; import { makeRequestFacade } from './lib/make_request_facade'; import { GetRouteConfigFactoryFn, diff --git a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject.ts b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject.ts index 8696f36a45c62..415b6b7d64366 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject.ts @@ -9,7 +9,7 @@ import { get } from 'lodash'; import { API_BASE_GENERATE_V1, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../common/constants'; import { getJobParamsFromRequest } from '../../export_types/csv_from_savedobject/server/lib/get_job_params_from_request'; import { Logger, ReportingResponseToolkit, ServerFacade } from '../../types'; -import { ReportingSetupDeps } from '../plugin'; +import { ReportingSetupDeps } from '../types'; import { makeRequestFacade } from './lib/make_request_facade'; import { getRouteOptionsCsv } from './lib/route_config_factories'; import { HandlerErrorFunction, HandlerFunction, QueuedJobPayload } from './types'; diff --git a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts index fd1d85fef0f21..5d17fa2e82b8c 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts @@ -10,14 +10,13 @@ import { createJobFactory, executeJobFactory } from '../../export_types/csv_from import { getJobParamsFromRequest } from '../../export_types/csv_from_savedobject/server/lib/get_job_params_from_request'; import { JobDocPayloadPanelCsv } from '../../export_types/csv_from_savedobject/types'; import { - HeadlessChromiumDriverFactory, JobDocOutput, Logger, ReportingResponseToolkit, ResponseFacade, ServerFacade, } from '../../types'; -import { ReportingSetupDeps } from '../plugin'; +import { ReportingSetupDeps, ReportingCore } from '../types'; import { makeRequestFacade } from './lib/make_request_facade'; import { getRouteOptionsCsv } from './lib/route_config_factories'; @@ -31,6 +30,7 @@ import { getRouteOptionsCsv } from './lib/route_config_factories'; * - local (transient) changes the user made to the saved object */ export function registerGenerateCsvFromSavedObjectImmediate( + reporting: ReportingCore, server: ServerFacade, plugins: ReportingSetupDeps, parentLogger: Logger @@ -58,10 +58,8 @@ export function registerGenerateCsvFromSavedObjectImmediate( * * Calling an execute job factory requires passing a browserDriverFactory option, so we should not call the factory from here */ - const createJobFn = createJobFactory(server, elasticsearch, logger); - const executeJobFn = executeJobFactory(server, elasticsearch, logger, { - browserDriverFactory: {} as HeadlessChromiumDriverFactory, - }); + const createJobFn = createJobFactory(reporting, server, elasticsearch, logger); + const executeJobFn = await executeJobFactory(reporting, server, elasticsearch, logger); const jobDocPayload: JobDocPayloadPanelCsv = await createJobFn( jobParams, request.headers, diff --git a/x-pack/legacy/plugins/reporting/server/routes/generation.ts b/x-pack/legacy/plugins/reporting/server/routes/generation.ts index 02a9541484bc6..096ba84b63d1a 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/generation.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/generation.ts @@ -8,15 +8,8 @@ import boom from 'boom'; import { errors as elasticsearchErrors } from 'elasticsearch'; import { Legacy } from 'kibana'; import { API_BASE_URL } from '../../common/constants'; -import { - ExportTypesRegistry, - HeadlessChromiumDriverFactory, - Logger, - ReportingResponseToolkit, - ServerFacade, -} from '../../types'; -import { createQueueFactory, enqueueJobFactory } from '../lib'; -import { ReportingSetupDeps } from '../plugin'; +import { Logger, ReportingResponseToolkit, ServerFacade } from '../../types'; +import { ReportingSetupDeps, ReportingCore } from '../types'; import { registerGenerateFromJobParams } from './generate_from_jobparams'; import { registerGenerateCsvFromSavedObject } from './generate_from_savedobject'; import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; @@ -25,23 +18,13 @@ import { makeRequestFacade } from './lib/make_request_facade'; const esErrors = elasticsearchErrors as Record; export function registerJobGenerationRoutes( + reporting: ReportingCore, server: ServerFacade, plugins: ReportingSetupDeps, - exportTypesRegistry: ExportTypesRegistry, - browserDriverFactory: HeadlessChromiumDriverFactory, logger: Logger ) { const config = server.config(); const DOWNLOAD_BASE_URL = config.get('server.basePath') + `${API_BASE_URL}/jobs/download`; - const { elasticsearch } = plugins; - const esqueue = createQueueFactory(server, elasticsearch, logger, { - exportTypesRegistry, - browserDriverFactory, - }); - const enqueueJob = enqueueJobFactory(server, elasticsearch, logger, { - exportTypesRegistry, - esqueue, - }); /* * Generates enqueued job details to use in responses @@ -56,6 +39,7 @@ export function registerJobGenerationRoutes( const user = request.pre.user; const headers = request.headers; + const enqueueJob = await reporting.getEnqueueJob(); const job = await enqueueJob(exportTypeId, jobParams, user, headers, request); // return the queue's job information @@ -87,6 +71,6 @@ export function registerJobGenerationRoutes( // Register beta panel-action download-related API's if (config.get('xpack.reporting.csv.enablePanelActionDownload')) { registerGenerateCsvFromSavedObject(server, plugins, handler, handleError, logger); - registerGenerateCsvFromSavedObjectImmediate(server, plugins, logger); + registerGenerateCsvFromSavedObjectImmediate(reporting, server, plugins, logger); } } diff --git a/x-pack/legacy/plugins/reporting/server/routes/index.ts b/x-pack/legacy/plugins/reporting/server/routes/index.ts index 4cfa9dd465eab..610ab4907d369 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/index.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/index.ts @@ -4,23 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - ExportTypesRegistry, - HeadlessChromiumDriverFactory, - Logger, - ServerFacade, -} from '../../types'; -import { ReportingSetupDeps } from '../plugin'; +import { Logger, ServerFacade } from '../../types'; +import { ReportingCore, ReportingSetupDeps } from '../types'; import { registerJobGenerationRoutes } from './generation'; import { registerJobInfoRoutes } from './jobs'; export function registerRoutes( + reporting: ReportingCore, server: ServerFacade, plugins: ReportingSetupDeps, - exportTypesRegistry: ExportTypesRegistry, - browserDriverFactory: HeadlessChromiumDriverFactory, logger: Logger ) { - registerJobGenerationRoutes(server, plugins, exportTypesRegistry, browserDriverFactory, logger); - registerJobInfoRoutes(server, plugins, exportTypesRegistry, logger); + registerJobGenerationRoutes(reporting, server, plugins, logger); + registerJobInfoRoutes(reporting, server, plugins, logger); } diff --git a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js index 811c81c502b81..071b401d2321b 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js +++ b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js @@ -5,30 +5,30 @@ */ import Hapi from 'hapi'; -import { difference, memoize } from 'lodash'; -import { registerJobInfoRoutes } from './jobs'; +import { memoize } from 'lodash'; +import { createMockReportingCore } from '../../test_helpers'; import { ExportTypesRegistry } from '../lib/export_types_registry'; -jest.mock('./lib/authorized_user_pre_routing', () => { - return { - authorizedUserPreRoutingFactory: () => () => ({}), - }; -}); -jest.mock('./lib/reporting_feature_pre_routing', () => { - return { - reportingFeaturePreRoutingFactory: () => () => () => ({ - jobTypes: ['unencodedJobType', 'base64EncodedJobType'], - }), - }; -}); + +jest.mock('./lib/authorized_user_pre_routing', () => ({ + authorizedUserPreRoutingFactory: () => () => ({}), +})); +jest.mock('./lib/reporting_feature_pre_routing', () => ({ + reportingFeaturePreRoutingFactory: () => () => () => ({ + jobTypes: ['unencodedJobType', 'base64EncodedJobType'], + }), +})); + +import { registerJobInfoRoutes } from './jobs'; let mockServer; let exportTypesRegistry; +let mockReportingPlugin; const mockLogger = { error: jest.fn(), debug: jest.fn(), }; -beforeEach(() => { +beforeEach(async () => { mockServer = new Hapi.Server({ debug: false, port: 8080, routes: { log: { collect: true } } }); mockServer.config = memoize(() => ({ get: jest.fn() })); exportTypesRegistry = new ExportTypesRegistry(); @@ -43,6 +43,8 @@ beforeEach(() => { jobContentEncoding: 'base64', jobContentExtension: 'pdf', }); + mockReportingPlugin = await createMockReportingCore(); + mockReportingPlugin.getExportTypesRegistry = () => exportTypesRegistry; }); const mockPlugins = { @@ -60,12 +62,15 @@ const getHits = (...sources) => { }; }; +const getErrorsFromRequest = request => + request.logs.filter(log => log.tags.includes('error')).map(log => log.error); + test(`returns 404 if job not found`, async () => { mockPlugins.elasticsearch.adminClient = { callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(getHits())), }; - registerJobInfoRoutes(mockServer, mockPlugins, exportTypesRegistry, mockLogger); + registerJobInfoRoutes(mockReportingPlugin, mockServer, mockPlugins, mockLogger); const request = { method: 'GET', @@ -84,7 +89,7 @@ test(`returns 401 if not valid job type`, async () => { .mockReturnValue(Promise.resolve(getHits({ jobtype: 'invalidJobType' }))), }; - registerJobInfoRoutes(mockServer, mockPlugins, exportTypesRegistry, mockLogger); + registerJobInfoRoutes(mockReportingPlugin, mockServer, mockPlugins, mockLogger); const request = { method: 'GET', @@ -105,7 +110,7 @@ describe(`when job is incomplete`, () => { ), }; - registerJobInfoRoutes(mockServer, mockPlugins, exportTypesRegistry, mockLogger); + registerJobInfoRoutes(mockReportingPlugin, mockServer, mockPlugins, mockLogger); const request = { method: 'GET', @@ -147,7 +152,7 @@ describe(`when job is failed`, () => { callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(hits)), }; - registerJobInfoRoutes(mockServer, mockPlugins, exportTypesRegistry, mockLogger); + registerJobInfoRoutes(mockReportingPlugin, mockServer, mockPlugins, mockLogger); const request = { method: 'GET', @@ -192,7 +197,7 @@ describe(`when job is completed`, () => { callAsInternalUser: jest.fn().mockReturnValue(Promise.resolve(hits)), }; - registerJobInfoRoutes(mockServer, mockPlugins, exportTypesRegistry, mockLogger); + registerJobInfoRoutes(mockReportingPlugin, mockServer, mockPlugins, mockLogger); const request = { method: 'GET', @@ -203,72 +208,115 @@ describe(`when job is completed`, () => { }; test(`sets statusCode to 200`, async () => { - const { statusCode } = await getCompletedResponse(); + const { statusCode, request } = await getCompletedResponse(); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); expect(statusCode).toBe(200); }); test(`doesn't encode output content for not-specified jobTypes`, async () => { - const { payload } = await getCompletedResponse({ + const { payload, request } = await getCompletedResponse({ jobType: 'unencodedJobType', outputContent: 'test', }); + + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); + expect(payload).toBe('test'); }); test(`base64 encodes output content for configured jobTypes`, async () => { - const { payload } = await getCompletedResponse({ + const { payload, request } = await getCompletedResponse({ jobType: 'base64EncodedJobType', outputContent: 'test', }); + + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); + expect(payload).toBe(Buffer.from('test', 'base64').toString()); }); test(`specifies text/csv; charset=utf-8 contentType header from the job output`, async () => { - const { headers } = await getCompletedResponse({ outputContentType: 'text/csv' }); + const { headers, request } = await getCompletedResponse({ outputContentType: 'text/csv' }); + + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); + expect(headers['content-type']).toBe('text/csv; charset=utf-8'); }); test(`specifies default filename in content-disposition header if no title`, async () => { - const { headers } = await getCompletedResponse({}); + const { headers, request } = await getCompletedResponse({}); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); expect(headers['content-disposition']).toBe('inline; filename="report.csv"'); }); test(`specifies payload title in content-disposition header`, async () => { - const { headers } = await getCompletedResponse({ title: 'something' }); + const { headers, request } = await getCompletedResponse({ title: 'something' }); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); expect(headers['content-disposition']).toBe('inline; filename="something.csv"'); }); test(`specifies jobContentExtension in content-disposition header`, async () => { - const { headers } = await getCompletedResponse({ jobType: 'base64EncodedJobType' }); + const { headers, request } = await getCompletedResponse({ jobType: 'base64EncodedJobType' }); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); expect(headers['content-disposition']).toBe('inline; filename="report.pdf"'); }); test(`specifies application/pdf contentType header from the job output`, async () => { - const { headers } = await getCompletedResponse({ outputContentType: 'application/pdf' }); + const { headers, request } = await getCompletedResponse({ + outputContentType: 'application/pdf', + }); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toEqual([]); expect(headers['content-type']).toBe('application/pdf'); }); describe(`when non-whitelisted contentType specified in job output`, () => { test(`sets statusCode to 500`, async () => { - const { statusCode } = await getCompletedResponse({ outputContentType: 'application/html' }); + const { statusCode, request } = await getCompletedResponse({ + outputContentType: 'application/html', + }); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toMatchInlineSnapshot(` + Array [ + [Error: Unsupported content-type of application/html specified by job output], + [Error: Unsupported content-type of application/html specified by job output], + ] + `); expect(statusCode).toBe(500); }); test(`doesn't include job output content in payload`, async () => { - const { payload } = await getCompletedResponse({ outputContentType: 'application/html' }); - expect(payload).not.toMatch(/job output content/); + const { payload, request } = await getCompletedResponse({ + outputContentType: 'application/html', + }); + expect(payload).toMatchInlineSnapshot( + `"{\\"statusCode\\":500,\\"error\\":\\"Internal Server Error\\",\\"message\\":\\"An internal server error occurred\\"}"` + ); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toMatchInlineSnapshot(` + Array [ + [Error: Unsupported content-type of application/html specified by job output], + [Error: Unsupported content-type of application/html specified by job output], + ] + `); }); test(`logs error message about invalid content type`, async () => { - const { - request: { logs }, - } = await getCompletedResponse({ outputContentType: 'application/html' }); - const errorLogs = logs.filter( - log => difference(['internal', 'implementation', 'error'], log.tags).length === 0 - ); - expect(errorLogs).toHaveLength(1); - expect(errorLogs[0].error).toBeInstanceOf(Error); - expect(errorLogs[0].error.message).toMatch(/Unsupported content-type of application\/html/); + const { request } = await getCompletedResponse({ outputContentType: 'application/html' }); + const errorLogs = getErrorsFromRequest(request); + expect(errorLogs).toMatchInlineSnapshot(` + Array [ + [Error: Unsupported content-type of application/html specified by job output], + [Error: Unsupported content-type of application/html specified by job output], + ] + `); }); }); }); diff --git a/x-pack/legacy/plugins/reporting/server/routes/jobs.ts b/x-pack/legacy/plugins/reporting/server/routes/jobs.ts index daabc2cf22f4e..2de420e6577c3 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/jobs.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/jobs.ts @@ -9,7 +9,6 @@ import { ResponseObject } from 'hapi'; import { Legacy } from 'kibana'; import { API_BASE_URL } from '../../common/constants'; import { - ExportTypesRegistry, JobDocOutput, JobSource, ListQuery, @@ -18,7 +17,7 @@ import { ServerFacade, } from '../../types'; import { jobsQueryFactory } from '../lib/jobs_query'; -import { ReportingSetupDeps } from '../plugin'; +import { ReportingSetupDeps, ReportingCore } from '../types'; import { jobResponseHandlerFactory } from './lib/job_response_handler'; import { makeRequestFacade } from './lib/make_request_facade'; import { @@ -33,9 +32,9 @@ function isResponse(response: Boom | ResponseObject): response is Response } export function registerJobInfoRoutes( + reporting: ReportingCore, server: ServerFacade, plugins: ReportingSetupDeps, - exportTypesRegistry: ExportTypesRegistry, logger: Logger ) { const { elasticsearch } = plugins; @@ -138,6 +137,7 @@ export function registerJobInfoRoutes( }); // trigger a download of the output from a job + const exportTypesRegistry = reporting.getExportTypesRegistry(); const jobResponseHandler = jobResponseHandlerFactory(server, elasticsearch, exportTypesRegistry); server.route({ path: `${MAIN_ENTRY}/download/{docId}`, diff --git a/x-pack/legacy/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts b/x-pack/legacy/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts index 57c3fcee222da..c5f8c78016f61 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts @@ -9,7 +9,7 @@ import { Legacy } from 'kibana'; import { AuthenticatedUser } from '../../../../../../plugins/security/server'; import { Logger, ServerFacade } from '../../../types'; import { getUserFactory } from '../../lib/get_user'; -import { ReportingSetupDeps } from '../../plugin'; +import { ReportingSetupDeps } from '../../types'; const superuserRole = 'superuser'; diff --git a/x-pack/legacy/plugins/reporting/server/routes/lib/reporting_feature_pre_routing.ts b/x-pack/legacy/plugins/reporting/server/routes/lib/reporting_feature_pre_routing.ts index 7367fceb50857..9e618ff1fe40a 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/lib/reporting_feature_pre_routing.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/lib/reporting_feature_pre_routing.ts @@ -7,7 +7,7 @@ import Boom from 'boom'; import { Legacy } from 'kibana'; import { Logger, ServerFacade } from '../../../types'; -import { ReportingSetupDeps } from '../../plugin'; +import { ReportingSetupDeps } from '../../types'; export type GetReportingFeatureIdFn = (request: Legacy.Request) => string; diff --git a/x-pack/legacy/plugins/reporting/server/routes/lib/route_config_factories.ts b/x-pack/legacy/plugins/reporting/server/routes/lib/route_config_factories.ts index 931f642397bf8..82ba9ba22c706 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/lib/route_config_factories.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/lib/route_config_factories.ts @@ -7,7 +7,7 @@ import Joi from 'joi'; import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; import { Logger, ServerFacade } from '../../../types'; -import { ReportingSetupDeps } from '../../plugin'; +import { ReportingSetupDeps } from '../../types'; import { authorizedUserPreRoutingFactory } from './authorized_user_pre_routing'; import { GetReportingFeatureIdFn, diff --git a/x-pack/legacy/plugins/reporting/server/types.d.ts b/x-pack/legacy/plugins/reporting/server/types.d.ts new file mode 100644 index 0000000000000..20673423aa448 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/server/types.d.ts @@ -0,0 +1,50 @@ +/* + * 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 { Legacy } from 'kibana'; +import { + ElasticsearchServiceSetup, + SavedObjectsServiceStart, + UiSettingsServiceStart, +} from 'src/core/server'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server'; +import { SecurityPluginSetup } from '../../../../plugins/security/server'; +import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; +import { EnqueueJobFn, ESQueueInstance, ReportingPluginSpecOptions } from '../types'; +import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factory'; + +export interface ReportingSetupDeps { + elasticsearch: ElasticsearchServiceSetup; + security: SecurityPluginSetup; + usageCollection: UsageCollectionSetup; + __LEGACY: LegacySetup; +} + +export interface ReportingStartDeps { + elasticsearch: ElasticsearchServiceSetup; + data: DataPluginStart; + __LEGACY: LegacySetup; +} + +export type ReportingSetup = object; + +export type ReportingStart = object; + +export interface LegacySetup { + config: Legacy.Server['config']; + info: Legacy.Server['info']; + plugins: { + elasticsearch: Legacy.Server['plugins']['elasticsearch']; + xpack_main: XPackMainPlugin & { + status?: any; + }; + reporting: ReportingPluginSpecOptions; + }; + route: Legacy.Server['route']; +} + +export { ReportingCore } from './core'; diff --git a/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts b/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts index 0118dea38d985..359bcc45230c3 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts @@ -6,7 +6,7 @@ import { uniq } from 'lodash'; import { CSV_JOB_TYPE, PDF_JOB_TYPE, PNG_JOB_TYPE } from '../../common/constants'; -import { AvailableTotal, FeatureAvailabilityMap, RangeStats, ExportType } from './types.d'; +import { AvailableTotal, FeatureAvailabilityMap, RangeStats, ExportType } from './types'; function getForFeature( range: Partial, diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js index f761f0d2d270b..a6d753f9b107a 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js +++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js @@ -3,9 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import sinon from 'sinon'; +import { createMockReportingCore } from '../../test_helpers'; import { getExportTypesRegistry } from '../lib/export_types_registry'; -import { getReportingUsageCollector } from './reporting_usage_collector'; +import { + registerReportingUsageCollector, + getReportingUsageCollector, +} from './reporting_usage_collector'; const exportTypesRegistry = getExportTypesRegistry(); @@ -70,9 +75,8 @@ describe('license checks', () => { const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock())); const usageCollection = getMockUsageCollection(); const { fetch: getReportingUsage } = getReportingUsageCollector( - usageCollection, serverWithBasicLicenseMock, - () => {}, + usageCollection, exportTypesRegistry ); usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); @@ -101,9 +105,8 @@ describe('license checks', () => { const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock())); const usageCollection = getMockUsageCollection(); const { fetch: getReportingUsage } = getReportingUsageCollector( - usageCollection, serverWithNoLicenseMock, - () => {}, + usageCollection, exportTypesRegistry ); usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); @@ -132,9 +135,8 @@ describe('license checks', () => { const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock())); const usageCollection = getMockUsageCollection(); const { fetch: getReportingUsage } = getReportingUsageCollector( - usageCollection, serverWithPlatinumLicenseMock, - () => {}, + usageCollection, exportTypesRegistry ); usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); @@ -163,9 +165,8 @@ describe('license checks', () => { const callClusterMock = jest.fn(() => Promise.resolve({})); const usageCollection = getMockUsageCollection(); const { fetch: getReportingUsage } = getReportingUsageCollector( - usageCollection, serverWithBasicLicenseMock, - () => {}, + usageCollection, exportTypesRegistry ); usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); @@ -190,9 +191,8 @@ describe('data modeling', () => { .stub() .returns('platinum'); ({ fetch: getReportingUsage } = getReportingUsageCollector( - usageCollection, serverWithPlatinumLicenseMock, - () => {}, + usageCollection, exportTypesRegistry )); }); @@ -322,94 +322,124 @@ describe('data modeling', () => { const usageStats = await getReportingUsage(callClusterMock); expect(usageStats).toMatchInlineSnapshot(` -Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 54, - "available": true, - "browser_type": undefined, - "csv": Object { - "available": true, - "total": 27, - }, - "enabled": true, - "last7Days": Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 27, - "csv": Object { - "available": true, - "total": 10, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 13, - "visualization": 0, - }, - "available": true, - "layout": Object { - "preserve_layout": 3, - "print": 10, - }, - "total": 13, - }, - "status": Object { - "completed": 0, - "failed": 0, - "pending": 27, - }, - }, - "lastDay": Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 11, - "csv": Object { - "available": true, - "total": 5, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 2, - "visualization": 0, - }, - "available": true, - "layout": Object { - "preserve_layout": 0, - "print": 2, - }, - "total": 2, - }, - "status": Object { - "completed": 0, - "failed": 0, - "pending": 11, - }, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 23, - "visualization": 0, - }, - "available": true, - "layout": Object { - "preserve_layout": 13, - "print": 10, - }, - "total": 23, - }, - "status": Object { - "completed": 20, - "failed": 0, - "pending": 33, - "processing": 1, - }, -} -`); + Object { + "PNG": Object { + "available": true, + "total": 4, + }, + "_all": 54, + "available": true, + "browser_type": undefined, + "csv": Object { + "available": true, + "total": 27, + }, + "enabled": true, + "last7Days": Object { + "PNG": Object { + "available": true, + "total": 4, + }, + "_all": 27, + "csv": Object { + "available": true, + "total": 10, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 13, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 3, + "print": 10, + }, + "total": 13, + }, + "status": Object { + "completed": 0, + "failed": 0, + "pending": 27, + }, + }, + "lastDay": Object { + "PNG": Object { + "available": true, + "total": 4, + }, + "_all": 11, + "csv": Object { + "available": true, + "total": 5, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 2, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 2, + }, + "total": 2, + }, + "status": Object { + "completed": 0, + "failed": 0, + "pending": 11, + }, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 23, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 13, + "print": 10, + }, + "total": 23, + }, + "status": Object { + "completed": 20, + "failed": 0, + "pending": 33, + "processing": 1, + }, + } + `); + }); +}); + +describe('Ready for collection observable', () => { + let mockReporting; + + beforeEach(async () => { + mockReporting = await createMockReportingCore(); + }); + + test('converts observable to promise', async () => { + const serverWithBasicLicenseMock = getServerMock(); + const makeCollectorSpy = sinon.spy(); + const usageCollection = { + makeUsageCollector: makeCollectorSpy, + registerCollector: sinon.stub(), + }; + registerReportingUsageCollector(mockReporting, serverWithBasicLicenseMock, usageCollection); + + const [args] = makeCollectorSpy.firstCall.args; + expect(args).toMatchInlineSnapshot(` + Object { + "fetch": [Function], + "formatForBulkUpload": [Function], + "isReady": [Function], + "type": "reporting", + } + `); + + await expect(args.isReady()).resolves.toBe(true); }); }); diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts index 567838391d2e7..14202530fb6c7 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts @@ -5,8 +5,9 @@ */ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { ServerFacade, ExportTypesRegistry, ESCallCluster } from '../../types'; import { KIBANA_REPORTING_TYPE } from '../../common/constants'; +import { ReportingCore } from '../../server'; +import { ESCallCluster, ExportTypesRegistry, ServerFacade } from '../../types'; import { getReportingUsage } from './get_reporting_usage'; import { RangeStats } from './types'; @@ -18,16 +19,16 @@ const METATYPE = 'kibana_stats'; * @return {Object} kibana usage stats type collection object */ export function getReportingUsageCollector( - usageCollection: UsageCollectionSetup, server: ServerFacade, - isReady: () => boolean, - exportTypesRegistry: ExportTypesRegistry + usageCollection: UsageCollectionSetup, + exportTypesRegistry: ExportTypesRegistry, + isReady: () => Promise ) { return usageCollection.makeUsageCollector({ type: KIBANA_REPORTING_TYPE, - isReady, fetch: (callCluster: ESCallCluster) => getReportingUsage(server, callCluster, exportTypesRegistry), + isReady, /* * Format the response data into a model for internal upload @@ -50,16 +51,18 @@ export function getReportingUsageCollector( } export function registerReportingUsageCollector( - usageCollection: UsageCollectionSetup, + reporting: ReportingCore, server: ServerFacade, - isReady: () => boolean, - exportTypesRegistry: ExportTypesRegistry + usageCollection: UsageCollectionSetup ) { + const exportTypesRegistry = reporting.getExportTypesRegistry(); + const collectionIsReady = reporting.pluginHasStarted.bind(reporting); + const collector = getReportingUsageCollector( - usageCollection, server, - isReady, - exportTypesRegistry + usageCollection, + exportTypesRegistry, + collectionIsReady ); usageCollection.registerCollector(collector); } diff --git a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts new file mode 100644 index 0000000000000..2cd129d47b3f9 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts @@ -0,0 +1,53 @@ +/* + * 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. + */ + +jest.mock('../server/routes'); +jest.mock('../server/usage'); +jest.mock('../server/browsers'); +jest.mock('../server/browsers'); +jest.mock('../server/lib/create_queue'); +jest.mock('../server/lib/enqueue_job'); +jest.mock('../server/lib/validate'); +jest.mock('../log_configuration'); + +import { EventEmitter } from 'events'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { coreMock } from 'src/core/server/mocks'; +import { ReportingPlugin, ReportingCore } from '../server'; +import { ReportingSetupDeps, ReportingStartDeps } from '../server/types'; + +export const createMockSetupDeps = (setupMock?: any): ReportingSetupDeps => ({ + elasticsearch: setupMock.elasticsearch, + security: setupMock.security, + usageCollection: {} as any, + __LEGACY: { plugins: { xpack_main: { status: new EventEmitter() } } } as any, +}); + +export const createMockStartDeps = (startMock?: any): ReportingStartDeps => ({ + data: startMock.data, + elasticsearch: startMock.elasticsearch, + __LEGACY: {} as any, +}); + +const createMockReportingPlugin = async (config = {}): Promise => { + const plugin = new ReportingPlugin(coreMock.createPluginInitializerContext(config)); + const setupMock = coreMock.createSetup(); + const coreStartMock = coreMock.createStart(); + const startMock = { + ...coreStartMock, + data: { fieldFormats: {} }, + }; + + await plugin.setup(setupMock, createMockSetupDeps(setupMock)); + await plugin.start(startMock, createMockStartDeps(startMock)); + + return plugin; +}; + +export const createMockReportingCore = async (config = {}): Promise => { + const plugin = await createMockReportingPlugin(config); + return plugin.getReportingCore(); +}; diff --git a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_server.ts b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_server.ts index 226355f5edc61..bb7851ba036a9 100644 --- a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_server.ts +++ b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_server.ts @@ -8,9 +8,6 @@ import { ServerFacade } from '../types'; export const createMockServer = ({ settings = {} }: any): ServerFacade => { const mockServer = { - expose: () => { - ' '; - }, config: memoize(() => ({ get: jest.fn() })), info: { protocol: 'http', @@ -24,10 +21,6 @@ export const createMockServer = ({ settings = {} }: any): ServerFacade => { }), }, }, - savedObjects: { - getScopedSavedObjectsClient: jest.fn(), - }, - uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), }; const defaultSettings: any = { diff --git a/x-pack/legacy/plugins/reporting/test_helpers/index.ts b/x-pack/legacy/plugins/reporting/test_helpers/index.ts new file mode 100644 index 0000000000000..7fbc5661d5211 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/test_helpers/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { createMockServer } from './create_mock_server'; +export { createMockReportingCore } from './create_mock_reportingplugin'; diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts index a4ff39b23747d..1549c173b3d6e 100644 --- a/x-pack/legacy/plugins/reporting/types.d.ts +++ b/x-pack/legacy/plugins/reporting/types.d.ts @@ -6,16 +6,15 @@ import { EventEmitter } from 'events'; import { ResponseObject } from 'hapi'; -import { ElasticsearchServiceSetup } from 'kibana/server'; import { Legacy } from 'kibana'; +import { ElasticsearchServiceSetup } from 'kibana/server'; import { CallCluster } from '../../../../src/legacy/core_plugins/elasticsearch'; import { CancellationToken } from './common/cancellation_token'; import { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory'; import { BrowserType } from './server/browsers/types'; import { LevelLogger } from './server/lib/level_logger'; -import { LegacySetup, ReportingSetupDeps } from './server/plugin'; - -export type ReportingPlugin = object; // For Plugin contract +import { ReportingCore } from './server/core'; +import { LegacySetup, ReportingStartDeps, ReportingSetup, ReportingStart } from './server/types'; export type Job = EventEmitter & { id: string; @@ -65,6 +64,7 @@ interface GenerateExportTypePayload { /* * Legacy System + * TODO: move to server/types */ export type ServerFacade = LegacySetup; @@ -179,6 +179,15 @@ export interface CryptoFactory { decrypt: (headers?: string) => any; } +export interface IndexPatternSavedObject { + attributes: { + fieldFormatMap: string; + }; + id: string; + type: string; + version: string; +} + export interface TimeRangeParams { timezone: string; min: Date | string | number; @@ -214,10 +223,6 @@ export interface JobDocOutput { size: number; } -export interface ESQueue { - addJob: (type: string, payload: object, options: object) => Job; -} - export interface ESQueueWorker { on: (event: string, handler: any) => void; } @@ -267,8 +272,9 @@ type GenericWorkerFn = ( ...workerRestArgs: any[] ) => void | Promise; -export interface ESQueueInstance { - registerWorker: ( +export interface ESQueueInstance { + addJob: (type: string, payload: unknown, options: object) => Job; + registerWorker: ( pluginId: string, workerFn: GenericWorkerFn, workerOptions: ESQueueWorkerOptions @@ -276,18 +282,17 @@ export interface ESQueueInstance { } export type CreateJobFactory = ( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, logger: LevelLogger ) => CreateJobFnType; export type ExecuteJobFactory = ( + reporting: ReportingCore, server: ServerFacade, elasticsearch: ElasticsearchServiceSetup, - logger: LevelLogger, - opts: { - browserDriverFactory: HeadlessChromiumDriverFactory; - } -) => ExecuteJobFnType; + logger: LevelLogger +) => Promise; export interface ExportTypeDefinition< JobParamsType, @@ -309,7 +314,6 @@ export { CancellationToken } from './common/cancellation_token'; export { HeadlessChromiumDriver } from './server/browsers/chromium/driver'; export { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory'; export { ExportTypesRegistry } from './server/lib/export_types_registry'; - // Prefer to import this type using: `import { LevelLogger } from 'relative/path/server/lib';` export { LevelLogger as Logger }; diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts index 17597672a898e..64eb1f6436389 100644 --- a/x-pack/legacy/plugins/rollup/public/legacy.ts +++ b/x-pack/legacy/plugins/rollup/public/legacy.ts @@ -10,7 +10,7 @@ import { aggTypeFieldFilters } from 'ui/agg_types'; import { addSearchStrategy } from '../../../../../src/plugins/data/public'; import { RollupPlugin } from './plugin'; import { setup as management } from '../../../../../src/legacy/core_plugins/management/public/legacy'; -import { addBadgeExtension, addToggleExtension } from '../../index_management/public'; +import { extensionsService } from '../../index_management/public'; const plugin = new RollupPlugin(); @@ -20,8 +20,7 @@ export const setup = plugin.setup(npSetup.core, { aggTypeFilters, aggTypeFieldFilters, addSearchStrategy, - addBadgeExtension, - addToggleExtension, + indexManagementExtensions: extensionsService, managementLegacy: management, }, }); diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/legacy/plugins/rollup/public/plugin.ts index 4dae078c90f57..90d7e2d9d0191 100644 --- a/x-pack/legacy/plugins/rollup/public/plugin.ts +++ b/x-pack/legacy/plugins/rollup/public/plugin.ts @@ -27,6 +27,7 @@ import { // @ts-ignore import { CRUD_APP_BASE_PATH } from './crud_app/constants'; import { ManagementSetup } from '../../../../../src/plugins/management/public'; +import { IndexMgmtSetup } from '../../index_management/public'; // @ts-ignore import { setEsBaseAndXPackBase, setHttp } from './crud_app/services'; import { setNotifications, setFatalErrors } from './kibana_services'; @@ -38,8 +39,7 @@ export interface RollupPluginSetupDependencies { aggTypeFieldFilters: AggTypeFieldFilters; addSearchStrategy: (searchStrategy: SearchStrategyProvider) => void; managementLegacy: ManagementSetupLegacy; - addBadgeExtension: (badgeExtension: any) => void; - addToggleExtension: (toggleExtension: any) => void; + indexManagementExtensions: IndexMgmtSetup['extensionsService']; }; home?: HomePublicPluginSetup; management: ManagementSetup; @@ -54,16 +54,15 @@ export class RollupPlugin implements Plugin { aggTypeFieldFilters, addSearchStrategy, managementLegacy, - addBadgeExtension, - addToggleExtension, + indexManagementExtensions, }, home, management, }: RollupPluginSetupDependencies ) { setFatalErrors(core.fatalErrors); - addBadgeExtension(rollupBadgeExtension); - addToggleExtension(rollupToggleExtension); + indexManagementExtensions.addBadge(rollupBadgeExtension); + indexManagementExtensions.addToggle(rollupToggleExtension); const isRollupIndexPatternsEnabled = core.uiSettings.get(CONFIG_ROLLUPS); diff --git a/x-pack/legacy/plugins/security/public/services/auto_logout.js b/x-pack/legacy/plugins/security/public/services/auto_logout.js index eb00d62d0266c..fa4d149d1f2e6 100644 --- a/x-pack/legacy/plugins/security/public/services/auto_logout.js +++ b/x-pack/legacy/plugins/security/public/services/auto_logout.js @@ -8,12 +8,26 @@ import { uiModules } from 'ui/modules'; import chrome from 'ui/chrome'; const module = uiModules.get('security'); + +const getNextParameter = () => { + const { location } = window; + const next = encodeURIComponent(`${location.pathname}${location.search}${location.hash}`); + return `&next=${next}`; +}; + +const getProviderParameter = tenant => { + const key = `${tenant}/session_provider`; + const providerName = sessionStorage.getItem(key); + return providerName ? `&provider=${encodeURIComponent(providerName)}` : ''; +}; + module.service('autoLogout', ($window, Promise) => { return () => { - const next = chrome.removeBasePath(`${window.location.pathname}${window.location.hash}`); - $window.location.href = chrome.addBasePath( - `/logout?next=${encodeURIComponent(next)}&msg=SESSION_EXPIRED` - ); + const logoutUrl = chrome.getInjected('logoutUrl'); + const tenant = `${chrome.getInjected('session.tenant', '')}`; + const next = getNextParameter(); + const provider = getProviderParameter(tenant); + $window.location.href = `${logoutUrl}?msg=SESSION_EXPIRED${next}${provider}`; return Promise.halt(); }; }); diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/fields_browser/fields_browser.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/fields_browser/fields_browser.spec.ts index 2889d78891a06..6e8ef93a54016 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/fields_browser/fields_browser.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/fields_browser/fields_browser.spec.ts @@ -22,11 +22,9 @@ import { FIELDS_BROWSER_HEADER_HOST_GEO_CONTINENT_NAME_HEADER, } from '../../../screens/timeline/fields_browser'; -import { - openTimeline, - populateTimeline, - openTimelineFieldsBrowser, -} from '../../../tasks/timeline/main'; +import { populateTimeline, openTimelineFieldsBrowser } from '../../../tasks/timeline/main'; + +import { openTimeline } from '../../../tasks/siem_main'; import { clearFieldsBrowser, diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/inspect/inspect.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/inspect/inspect.spec.ts index e7411aba11af5..1555470f5eee7 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/inspect/inspect.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/inspect/inspect.spec.ts @@ -12,10 +12,10 @@ import { } from '../../../screens/inspect'; import { executeTimelineKQL, - openTimeline, openTimelineSettings, openTimelineInspectButton, } from '../../../tasks/timeline/main'; +import { openTimeline } from '../../../tasks/siem_main'; import { DEFAULT_TIMEOUT, loginAndWaitForPage } from '../../../tasks/login'; import { closesModal, openStatsAndTables } from '../../../tasks/inspect'; diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/data_providers.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/data_providers.spec.ts index 3d251c1c6bcac..c3fedfb06939b 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/data_providers.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/data_providers.spec.ts @@ -13,7 +13,8 @@ import { } from '../../../tasks/hosts/all_hosts'; import { HOSTS_NAMES } from '../../../screens/hosts/all_hosts'; import { DEFAULT_TIMEOUT, loginAndWaitForPage } from '../../../tasks/login'; -import { openTimeline, createNewTimeline } from '../../../tasks/timeline/main'; +import { createNewTimeline } from '../../../tasks/timeline/main'; +import { openTimeline } from '../../../tasks/siem_main'; import { TIMELINE_DATA_PROVIDERS_EMPTY, TIMELINE_DATA_PROVIDERS, diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/flyout_button.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/flyout_button.spec.ts index 63fe56371a4cd..b7faaaac1c06c 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/flyout_button.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/timeline/flyout_button.spec.ts @@ -4,44 +4,34 @@ * you may not use this file except in compliance with the Elastic License. */ +import { HOSTS_PAGE } from '../../../urls/navigation'; +import { waitForAllHostsToBeLoaded, dragFirstHostToTimeline } from '../../../tasks/hosts/all_hosts'; +import { loginAndWaitForPage } from '../../../tasks/login'; +import { openTimelineIfClosed, openTimeline } from '../../../tasks/siem_main'; import { TIMELINE_FLYOUT_BODY, TIMELINE_NOT_READY_TO_DROP_BUTTON, -} from '../../lib/timeline/selectors'; -import { ALL_HOSTS_WIDGET_DRAGGABLE_HOSTS } from '../../lib/hosts/selectors'; -import { HOSTS_PAGE } from '../../lib/urls'; -import { waitForAllHostsWidget } from '../../lib/hosts/helpers'; -import { loginAndWaitForPage } from '../../lib/util/helpers'; -import { drag } from '../../lib/drag_n_drop/helpers'; -import { createNewTimeline, toggleTimelineVisibility } from '../../lib/timeline/helpers'; +} from '../../../screens/timeline/main'; +import { createNewTimeline } from '../../../tasks/timeline/main'; describe('timeline flyout button', () => { before(() => { loginAndWaitForPage(HOSTS_PAGE); + waitForAllHostsToBeLoaded(); }); afterEach(() => { - cy.get('[data-test-subj="kibanaChrome"]').then($page => { - if ($page.find('[data-test-subj="flyoutOverlay"]').length === 1) { - toggleTimelineVisibility(); - } - }); - + openTimelineIfClosed(); createNewTimeline(); }); it('toggles open the timeline', () => { - toggleTimelineVisibility(); - + openTimeline(); cy.get(TIMELINE_FLYOUT_BODY).should('have.css', 'visibility', 'visible'); }); it('sets the flyout button background to euiColorSuccess with a 10% alpha channel when the user starts dragging a host, but is not hovering over the flyout button', () => { - waitForAllHostsWidget(); - - cy.get(ALL_HOSTS_WIDGET_DRAGGABLE_HOSTS) - .first() - .then(host => drag(host)); + dragFirstHostToTimeline(); cy.get(TIMELINE_NOT_READY_TO_DROP_BUTTON).should( 'have.css', diff --git a/x-pack/legacy/plugins/siem/cypress/screens/siem_main.ts b/x-pack/legacy/plugins/siem/cypress/screens/siem_main.ts new file mode 100644 index 0000000000000..d4eeeb036ee95 --- /dev/null +++ b/x-pack/legacy/plugins/siem/cypress/screens/siem_main.ts @@ -0,0 +1,9 @@ +/* + * 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 const MAIN_PAGE = '[data-test-subj="kibanaChrome"]'; + +export const TIMELINE_TOGGLE_BUTTON = '[data-test-subj="flyoutOverlay"]'; diff --git a/x-pack/legacy/plugins/siem/cypress/screens/timeline/main.ts b/x-pack/legacy/plugins/siem/cypress/screens/timeline/main.ts index 60c9c2ab44372..4c722ffa5f215 100644 --- a/x-pack/legacy/plugins/siem/cypress/screens/timeline/main.ts +++ b/x-pack/legacy/plugins/siem/cypress/screens/timeline/main.ts @@ -32,3 +32,8 @@ export const TIMELINE_DATA_PROVIDERS_EMPTY = export const TIMELINE_DROPPED_DATA_PROVIDERS = '[data-test-subj="dataProviders"] [data-test-subj="providerContainer"]'; + +export const TIMELINE_FLYOUT_BODY = '[data-test-subj="eui-flyout-body"]'; + +export const TIMELINE_NOT_READY_TO_DROP_BUTTON = + '[data-test-subj="flyout-button-not-ready-to-drop"]'; diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/siem_main.ts b/x-pack/legacy/plugins/siem/cypress/tasks/siem_main.ts new file mode 100644 index 0000000000000..8501bb3d94e26 --- /dev/null +++ b/x-pack/legacy/plugins/siem/cypress/tasks/siem_main.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MAIN_PAGE, TIMELINE_TOGGLE_BUTTON } from '../screens/siem_main'; +import { DEFAULT_TIMEOUT } from '../tasks/login'; + +export const openTimelineIfClosed = () => { + cy.get(MAIN_PAGE).then($page => { + if ($page.find(TIMELINE_TOGGLE_BUTTON).length === 1) { + openTimeline(); + } + }); +}; + +export const openTimeline = () => { + cy.get(TIMELINE_TOGGLE_BUTTON, { timeout: DEFAULT_TIMEOUT }).click(); +}; diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/timeline/main.ts b/x-pack/legacy/plugins/siem/cypress/tasks/timeline/main.ts index 068b6dd9f8bd4..f347c072a3584 100644 --- a/x-pack/legacy/plugins/siem/cypress/tasks/timeline/main.ts +++ b/x-pack/legacy/plugins/siem/cypress/tasks/timeline/main.ts @@ -7,7 +7,6 @@ import { DEFAULT_TIMEOUT } from '../../integration/lib/util/helpers'; import { - TIMELINE_TOGGLE_BUTTON, SEARCH_OR_FILTER_CONTAINER, TIMELINE_FIELDS_BUTTON, SERVER_SIDE_EVENT_COUNT, @@ -19,10 +18,6 @@ import { export const hostExistsQuery = 'host.name: *'; -export const openTimeline = () => { - cy.get(TIMELINE_TOGGLE_BUTTON, { timeout: DEFAULT_TIMEOUT }).click(); -}; - export const populateTimeline = () => { cy.get(`${SEARCH_OR_FILTER_CONTAINER} input`).type(`${hostExistsQuery} {enter}`); cy.get(SERVER_SIDE_EVENT_COUNT, { timeout: DEFAULT_TIMEOUT }) diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts index b0bc38bd3ebdc..79466251fc57b 100644 --- a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts @@ -19,7 +19,7 @@ export const ALERTS_TABLE_TITLE = i18n.translate('xpack.siem.alertsView.alertsTa }); export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.alertsView.alertsGraphTitle', { - defaultMessage: 'External alerts count', + defaultMessage: 'External alert count', }); export const ALERTS_STACK_BY_MODULE = i18n.translate( diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx index f9e6bfcf7c236..72f5a62d0af97 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx @@ -7,7 +7,7 @@ import { defaultTo, noop } from 'lodash/fp'; import React, { useCallback } from 'react'; import { DropResult, DragDropContext } from 'react-beautiful-dnd'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { BeforeCapture } from './drag_drop_context'; @@ -30,7 +30,6 @@ import { interface Props { browserFields: BrowserFields; children: React.ReactNode; - dataProviders?: dragAndDropModel.IdToDataProvider; dispatch: Dispatch; } @@ -59,7 +58,7 @@ const onDragEndHandler = ({ /** * DragDropContextWrapperComponent handles all drag end events */ -export const DragDropContextWrapperComponent = React.memo( +export const DragDropContextWrapperComponent = React.memo( ({ browserFields, children, dataProviders, dispatch }) => { const onDragEnd = useCallback( (result: DropResult) => { @@ -112,7 +111,11 @@ const mapStateToProps = (state: State) => { return { dataProviders }; }; -export const DragDropContextWrapper = connect(mapStateToProps)(DragDropContextWrapperComponent); +const connector = connect(mapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const DragDropContextWrapper = connector(DragDropContextWrapperComponent); DragDropContextWrapper.displayName = 'DragDropContextWrapper'; 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 9672097713a9b..cf958bfd75d3b 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 @@ -12,9 +12,8 @@ import { DraggableStateSnapshot, Droppable, } from 'react-beautiful-dnd'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; -import { ActionCreator } from 'typescript-fsa'; import { EuiPortal } from '@elastic/eui'; import { dragAndDropActions } from '../../store/drag_and_drop'; @@ -59,16 +58,7 @@ interface OwnProps { truncate?: boolean; } -interface DispatchProps { - registerProvider?: ActionCreator<{ - provider: DataProvider; - }>; - unRegisterProvider?: ActionCreator<{ - id: string; - }>; -} - -type Props = OwnProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; /** * Wraps a draggable component to handle registration / unregistration of the @@ -141,10 +131,16 @@ const DraggableWrapperComponent = React.memo( DraggableWrapperComponent.displayName = 'DraggableWrapperComponent'; -export const DraggableWrapper = connect(null, { +const mapDispatchToProps = { registerProvider: dragAndDropActions.registerProvider, unRegisterProvider: dragAndDropActions.unRegisterProvider, -})(DraggableWrapperComponent); +}; + +const connector = connect(null, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const DraggableWrapper = connector(DraggableWrapperComponent); DraggableWrapper.displayName = 'DraggableWrapper'; 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 3628330fbd459..ab9170ce1dd6a 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 @@ -5,10 +5,9 @@ */ import { useEffect } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; -import { appModel, appSelectors, State } from '../../store'; +import { appSelectors, State } from '../../store'; import { appActions } from '../../store/app'; import { useStateToaster } from '../toasters'; @@ -16,15 +15,7 @@ interface OwnProps { toastLifeTimeMs?: number; } -interface ReduxProps { - errors?: appModel.Error[]; -} - -interface DispatchProps { - removeError: ActionCreator<{ id: string }>; -} - -type Props = OwnProps & ReduxProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const ErrorToastDispatcherComponent = ({ toastLifeTimeMs = 5000, @@ -58,6 +49,12 @@ const makeMapStateToProps = () => { return (state: State) => getErrorSelector(state); }; -export const ErrorToastDispatcher = connect(makeMapStateToProps, { +const mapDispatchToProps = { removeError: appActions.removeError, -})(ErrorToastDispatcherComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const ErrorToastDispatcher = connector(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 c7ccff5bdfcff..1e7c7fc2411bb 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 @@ -6,20 +6,16 @@ import { isEqual } from 'lodash/fp'; import React, { useCallback, useMemo, useEffect } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store'; import { inputsActions, timelineActions } from '../../store/actions'; -import { KqlMode, SubsetTimelineModel, TimelineModel } from '../../store/timeline/model'; +import { SubsetTimelineModel, TimelineModel } from '../../store/timeline/model'; import { ColumnHeader } from '../timeline/body/column_headers/column_header'; -import { DataProvider } from '../timeline/data_providers/data_provider'; -import { Sort } from '../timeline/body/sort'; import { OnChangeItemsPerPage } from '../timeline/events'; -import { Filter, Query } from '../../../../../../../src/plugins/data/public'; +import { Filter } from '../../../../../../../src/plugins/data/public'; import { useUiSetting } from '../../lib/kibana'; import { EventsViewer } from './events_viewer'; -import { InputsModelId } from '../../store/inputs/constants'; import { useFetchIndexPatterns } from '../../containers/detection_engine/rules/fetch_index_patterns'; import { TimelineTypeContextProps } from '../timeline/timeline_context'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; @@ -38,51 +34,7 @@ export interface OwnProps { utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode; } -interface StateReduxProps { - columns: ColumnHeader[]; - dataProviders?: DataProvider[]; - filters: Filter[]; - isLive: boolean; - itemsPerPage?: number; - itemsPerPageOptions?: number[]; - kqlMode: KqlMode; - deletedEventIds: Readonly; - query: Query; - pageCount?: number; - sort?: Sort; - showCheckboxes: boolean; - showRowRenderers: boolean; -} - -interface DispatchProps { - createTimeline: ActionCreator<{ - id: string; - columns: ColumnHeader[]; - itemsPerPage?: number; - sort?: Sort; - showCheckboxes?: boolean; - showRowRenderers?: boolean; - }>; - deleteEventQuery: ActionCreator<{ - id: string; - inputId: InputsModelId; - }>; - removeColumn: ActionCreator<{ - id: string; - columnId: string; - }>; - updateItemsPerPage: ActionCreator<{ - id: string; - itemsPerPage: number; - }>; - upsertColumn: ActionCreator<{ - column: ColumnHeader; - id: string; - index: number; - }>; -} - -type Props = OwnProps & StateReduxProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const defaultTimelineTypeContext = { loadingText: i18n.LOADING_EVENTS, @@ -224,13 +176,19 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulEventsViewer = connect(makeMapStateToProps, { +const mapDispatchToProps = { createTimeline: timelineActions.createTimeline, deleteEventQuery: inputsActions.deleteOneQuery, updateItemsPerPage: timelineActions.updateItemsPerPage, removeColumn: timelineActions.removeColumn, upsertColumn: timelineActions.upsertColumn, -})( +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulEventsViewer = connector( React.memo( StatefulEventsViewerComponent, (prevProps, nextProps) => @@ -245,7 +203,6 @@ export const StatefulEventsViewer = connect(makeMapStateToProps, { isEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && prevProps.kqlMode === nextProps.kqlMode && isEqual(prevProps.query, nextProps.query) && - prevProps.pageCount === nextProps.pageCount && isEqual(prevProps.sort, nextProps.sort) && prevProps.start === nextProps.start && isEqual(prevProps.pageFilters, nextProps.pageFilters) && diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/index.test.tsx index 24e4cd77b20d3..cf9e4f57d67b7 100644 --- a/x-pack/legacy/plugins/siem/public/components/fields_browser/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/index.test.tsx @@ -6,6 +6,7 @@ import { mount } from 'enzyme'; import React from 'react'; +import { ActionCreator } from 'typescript-fsa'; import { mockBrowserFields } from '../../containers/source/mock'; import { TestProviders } from '../../mock'; @@ -13,6 +14,7 @@ import { TestProviders } from '../../mock'; import { FIELD_BROWSER_HEIGHT, FIELD_BROWSER_WIDTH } from './helpers'; import { StatefulFieldsBrowserComponent } from '.'; +import { ColumnHeader } from '../timeline/body/column_headers/column_header'; // Suppress warnings about "react-beautiful-dnd" until we migrate to @testing-library/react /* eslint-disable no-console */ @@ -27,6 +29,17 @@ afterAll(() => { console.warn = originalWarn; }); +const removeColumnMock = (jest.fn() as unknown) as ActionCreator<{ + id: string; + columnId: string; +}>; + +const upsertColumnMock = (jest.fn() as unknown) as ActionCreator<{ + column: ColumnHeader; + id: string; + index: number; +}>; + describe('StatefulFieldsBrowser', () => { const timelineId = 'test'; @@ -41,6 +54,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -65,6 +80,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -83,6 +100,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -111,6 +130,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -142,6 +163,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -180,6 +203,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -206,6 +231,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); @@ -232,6 +259,8 @@ describe('StatefulFieldsBrowser', () => { timelineId={timelineId} toggleColumn={jest.fn()} width={FIELD_BROWSER_WIDTH} + removeColumn={removeColumnMock} + upsertColumn={upsertColumnMock} /> ); 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 c8cde5fa02a51..b545c6890bd41 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 @@ -7,9 +7,8 @@ import { EuiButtonEmpty, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { noop } from 'lodash/fp'; import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; -import { ActionCreator } from 'typescript-fsa'; import { BrowserFields } from '../../containers/source'; import { timelineActions } from '../../store/actions'; @@ -31,22 +30,10 @@ const FieldsBrowserButtonContainer = styled.div` FieldsBrowserButtonContainer.displayName = 'FieldsBrowserButtonContainer'; -interface DispatchProps { - removeColumn?: ActionCreator<{ - id: string; - columnId: string; - }>; - upsertColumn?: ActionCreator<{ - column: ColumnHeader; - id: string; - index: number; - }>; -} - /** * Manages the state of the field browser */ -export const StatefulFieldsBrowserComponent = React.memo( +export const StatefulFieldsBrowserComponent = React.memo( ({ columnHeaders, browserFields, @@ -212,7 +199,13 @@ export const StatefulFieldsBrowserComponent = React.memo; + +export const StatefulFieldsBrowser = connector(React.memo(StatefulFieldsBrowserComponent)); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/header/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/header/index.tsx index e1075c89ca350..901f7afd1ed48 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/header/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/header/index.tsx @@ -5,9 +5,8 @@ */ import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; import { isEmpty, get } from 'lodash/fp'; import { History } from '../../../lib/history'; @@ -19,10 +18,9 @@ import { State, timelineSelectors, } from '../../../store'; -import { UpdateNote } from '../../notes/helpers'; import { defaultHeaders } from '../../timeline/body/column_headers/default_headers'; import { Properties } from '../../timeline/properties'; -import { appActions, appModel } from '../../../store/app'; +import { appActions } from '../../../store/app'; import { inputsActions } from '../../../store/inputs'; import { timelineActions } from '../../../store/actions'; import { timelineDefaults, TimelineModel } from '../../../store/timeline/model'; @@ -34,41 +32,7 @@ interface OwnProps { usersViewing: string[]; } -interface StateReduxProps { - description: string; - notesById: appModel.NotesById; - isDataInTimeline: boolean; - isDatepickerLocked: boolean; - isFavorite: boolean; - noteIds: string[]; - title: string; - width: number; -} - -interface DispatchProps { - associateNote: (noteId: string) => void; - applyDeltaToWidth?: ({ - id, - delta, - bodyClientWidthPixels, - maxWidthPercent, - minWidthPixels, - }: { - id: string; - delta: number; - bodyClientWidthPixels: number; - maxWidthPercent: number; - minWidthPixels: number; - }) => void; - createTimeline: ActionCreator<{ id: string; show?: boolean }>; - toggleLock: ActionCreator<{ linkToId: InputsModelId }>; - updateDescription: ActionCreator<{ id: string; description: string }>; - updateIsFavorite: ActionCreator<{ id: string; isFavorite: boolean }>; - updateNote: UpdateNote; - updateTitle: ActionCreator<{ id: string; title: string }>; -} - -type Props = OwnProps & StateReduxProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const StatefulFlyoutHeader = React.memo( ({ @@ -160,9 +124,7 @@ const makeMapStateToProps = () => { }; const mapDispatchToProps = (dispatch: Dispatch, { timelineId }: OwnProps) => ({ - associateNote: (noteId: string) => { - dispatch(timelineActions.addNote({ id: timelineId, noteId })); - }, + associateNote: (noteId: string) => dispatch(timelineActions.addNote({ id: timelineId, noteId })), applyDeltaToWidth: ({ id, delta, @@ -175,7 +137,7 @@ const mapDispatchToProps = (dispatch: Dispatch, { timelineId }: OwnProps) => ({ bodyClientWidthPixels: number; maxWidthPercent: number; minWidthPixels: number; - }) => { + }) => dispatch( timelineActions.applyDeltaToWidth({ id, @@ -184,35 +146,30 @@ const mapDispatchToProps = (dispatch: Dispatch, { timelineId }: OwnProps) => ({ maxWidthPercent, minWidthPixels, }) - ); - }, - createTimeline: ({ id, show }: { id: string; show?: boolean }) => { + ), + createTimeline: ({ id, show }: { id: string; show?: boolean }) => dispatch( timelineActions.createTimeline({ id, columns: defaultHeaders, show, }) - ); - }, - updateDescription: ({ id, description }: { id: string; description: string }) => { - dispatch(timelineActions.updateDescription({ id, description })); - }, - updateIsFavorite: ({ id, isFavorite }: { id: string; isFavorite: boolean }) => { - dispatch(timelineActions.updateIsFavorite({ id, isFavorite })); - }, - updateIsLive: ({ id, isLive }: { id: string; isLive: boolean }) => { - dispatch(timelineActions.updateIsLive({ id, isLive })); - }, - updateNote: (note: Note) => { - dispatch(appActions.updateNote({ note })); - }, - updateTitle: ({ id, title }: { id: string; title: string }) => { - dispatch(timelineActions.updateTitle({ id, title })); - }, - toggleLock: ({ linkToId }: { linkToId: InputsModelId }) => { - dispatch(inputsActions.toggleTimelineLinkTo({ linkToId })); - }, + ), + updateDescription: ({ id, description }: { id: string; description: string }) => + dispatch(timelineActions.updateDescription({ id, description })), + updateIsFavorite: ({ id, isFavorite }: { id: string; isFavorite: boolean }) => + dispatch(timelineActions.updateIsFavorite({ id, isFavorite })), + updateIsLive: ({ id, isLive }: { id: string; isLive: boolean }) => + dispatch(timelineActions.updateIsLive({ id, isLive })), + updateNote: (note: Note) => dispatch(appActions.updateNote({ note })), + updateTitle: ({ id, title }: { id: string; title: string }) => + dispatch(timelineActions.updateTitle({ id, title })), + toggleLock: ({ linkToId }: { linkToId: InputsModelId }) => + dispatch(inputsActions.toggleTimelineLinkTo({ linkToId })), }); -export const FlyoutHeader = connect(makeMapStateToProps, mapDispatchToProps)(StatefulFlyoutHeader); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const FlyoutHeader = connector(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 9fb59e2034b08..d18c22e44ce94 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -7,9 +7,8 @@ import { EuiBadge } from '@elastic/eui'; import { defaultTo, getOr } from 'lodash/fp'; import React from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; -import { ActionCreator } from 'typescript-fsa'; import { State, timelineSelectors } from '../../store'; import { DataProvider } from '../timeline/data_providers/data_provider'; @@ -46,30 +45,7 @@ interface OwnProps { usersViewing: string[]; } -interface DispatchProps { - showTimeline: ActionCreator<{ id: string; show: boolean }>; - applyDeltaToWidth?: ({ - id, - delta, - bodyClientWidthPixels, - maxWidthPercent, - minWidthPixels, - }: { - id: string; - delta: number; - bodyClientWidthPixels: number; - maxWidthPercent: number; - minWidthPixels: number; - }) => void; -} - -interface StateReduxProps { - dataProviders?: DataProvider[]; - show: boolean; - width: number; -} - -type Props = OwnProps & DispatchProps & StateReduxProps; +type Props = OwnProps & ProsFromRedux; export const FlyoutComponent = React.memo( ({ @@ -110,15 +86,21 @@ FlyoutComponent.displayName = 'FlyoutComponent'; const mapStateToProps = (state: State, { timelineId }: OwnProps) => { const timelineById = defaultTo({}, timelineSelectors.timelineByIdSelector(state)); - const dataProviders = getOr([], `${timelineId}.dataProviders`, timelineById); - const show = getOr('false', `${timelineId}.show`, timelineById); - const width = getOr(DEFAULT_TIMELINE_WIDTH, `${timelineId}.width`, timelineById); + const dataProviders = getOr([], `${timelineId}.dataProviders`, timelineById) as DataProvider[]; + const show = getOr(false, `${timelineId}.show`, timelineById) as boolean; + const width = getOr(DEFAULT_TIMELINE_WIDTH, `${timelineId}.width`, timelineById) as number; return { dataProviders, show, width }; }; -export const Flyout = connect(mapStateToProps, { +const mapDispatchToProps = { showTimeline: timelineActions.showTimeline, -})(FlyoutComponent); +}; + +const connector = connect(mapStateToProps, mapDispatchToProps); + +type ProsFromRedux = ConnectedProps; + +export const Flyout = connector(FlyoutComponent); Flyout.displayName = 'Flyout'; 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 00ac15092a6ec..fb977417ffbbf 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 @@ -6,9 +6,8 @@ import { EuiButtonIcon, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiToolTip } from '@elastic/eui'; import React, { useCallback, useState } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; -import { ActionCreator } from 'typescript-fsa'; import { Resizable, ResizeCallback } from 're-resizable'; import { throttle } from 'lodash/fp'; @@ -30,17 +29,7 @@ interface OwnProps { width: number; } -interface DispatchProps { - applyDeltaToWidth: ActionCreator<{ - id: string; - delta: number; - bodyClientWidthPixels: number; - maxWidthPercent: number; - minWidthPixels: number; - }>; -} - -type Props = OwnProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const EuiFlyoutContainer = styled.div<{ headerHeight: number }>` .timeline-flyout { @@ -183,8 +172,14 @@ const FlyoutPaneComponent: React.FC = ({ ); }; -export const Pane = connect(null, { +const mapDispatchToProps = { applyDeltaToWidth: timelineActions.applyDeltaToWidth, -})(React.memo(FlyoutPaneComponent)); +}; + +const connector = connect(null, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const Pane = connector(React.memo(FlyoutPaneComponent)); Pane.displayName = 'Pane'; diff --git a/x-pack/legacy/plugins/siem/public/components/notes/note_card/__snapshots__/note_card_body.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/notes/note_card/__snapshots__/note_card_body.test.tsx.snap index ba35940ff0e5f..bbacc86dcca2c 100644 --- a/x-pack/legacy/plugins/siem/public/components/notes/note_card/__snapshots__/note_card_body.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/notes/note_card/__snapshots__/note_card_body.test.tsx.snap @@ -333,6 +333,7 @@ exports[`NoteCardBody renders correctly against snapshot 1`] = ` "graphic": "#e7664c", }, }, + "euiPaletteColorBlindKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9'", "euiPanelPaddingModifiers": Object { "paddingLarge": "24px", "paddingMedium": "16px", @@ -437,6 +438,54 @@ exports[`NoteCardBody renders correctly against snapshot 1`] = ` "euiTextScale": "2.25 1.75 1.25 1.125 1 0.875 0.75", "euiTitleColor": "#dfe5ef", "euiToastWidth": "320px", + "euiTokenGrayColor": "#535966", + "euiTokenTypeKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9', 'gray'", + "euiTokenTypes": Object { + "euiColorVis0": Object { + "behindText": "#6dccb1", + "graphic": "#54b399", + }, + "euiColorVis1": Object { + "behindText": "#79aad9", + "graphic": "#6092c0", + }, + "euiColorVis2": Object { + "behindText": "#ee789d", + "graphic": "#d36086", + }, + "euiColorVis3": Object { + "behindText": "#a987d1", + "graphic": "#9170b8", + }, + "euiColorVis4": Object { + "behindText": "#e4a6c7", + "graphic": "#ca8eae", + }, + "euiColorVis5": Object { + "behindText": "#f1d86f", + "graphic": "#d6bf57", + }, + "euiColorVis6": Object { + "behindText": "#d2c0a0", + "graphic": "#b9a888", + }, + "euiColorVis7": Object { + "behindText": "#f5a35c", + "graphic": "#da8b45", + }, + "euiColorVis8": Object { + "behindText": "#c47c6c", + "graphic": "#aa6556", + }, + "euiColorVis9": Object { + "behindText": "#ff7e62", + "graphic": "#e7664c", + }, + "gray": Object { + "behindText": "#535966", + "graphic": "#535966", + }, + }, "euiTooltipAnimations": Object { "bottom": "euiToolTipLeft", "left": "euiToolTipBottom", @@ -548,20 +597,6 @@ exports[`NoteCardBody renders correctly against snapshot 1`] = ` "success": "#7de2d1", "warning": "#ffce7a", }, - "tokenTypes": Object { - "tokenTint01": "#1ba9f5", - "tokenTint02": "#f990c0", - "tokenTint03": "#9170b8", - "tokenTint04": "#da8b45", - "tokenTint05": "#6092c0", - "tokenTint06": "#e6c220", - "tokenTint07": "#54b399", - "tokenTint08": "#920000", - "tokenTint09": "#ff00ff", - "tokenTint10": "#26ab00", - "tokenTint11": "#4c1604", - "tokenTint12": "#666666", - }, }, } } diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts b/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts index 432939b0729d7..61c3d9f73e0d0 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts @@ -6,7 +6,7 @@ import ApolloClient from 'apollo-client'; import { getOr, set } from 'lodash/fp'; -import { ActionCreator } from 'typescript-fsa'; +import { Action } from 'typescript-fsa'; import { Dispatch } from 'redux'; import { oneTimelineQuery } from '../../containers/timeline/one/index.gql_query'; @@ -183,7 +183,13 @@ export interface QueryTimelineById { timelineId: string; onOpenTimeline?: (timeline: TimelineModel) => void; openTimeline?: boolean; - updateIsLoading: ActionCreator<{ id: string; isLoading: boolean }>; + updateIsLoading: ({ + id, + isLoading, + }: { + id: string; + isLoading: boolean; + }) => Action<{ id: string; isLoading: boolean }>; updateTimeline: DispatchUpdateTimeline; } diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx index a97cfefaf0393..daa64f9f16c83 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx @@ -6,7 +6,7 @@ import ApolloClient from 'apollo-client'; import React, { useEffect, useState, useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { defaultHeaders } from '../../components/timeline/body/column_headers/default_headers'; @@ -39,8 +39,6 @@ import { OpenTimelineResult, OnToggleShowNotes, OnDeleteOneTimeline, - OpenTimelineDispatchProps, - OpenTimelineReduxProps, } from './types'; import { DEFAULT_SORT_FIELD, DEFAULT_SORT_DIRECTION } from './constants'; @@ -55,8 +53,7 @@ interface OwnProps { export type OpenTimelineOwnProps = OwnProps & Pick & - OpenTimelineDispatchProps & - OpenTimelineReduxProps; + PropsFromRedux; /** Returns a collection of selected timeline ids */ export const getSelectedTimelineIds = (selectedItems: OpenTimelineResult[]): string[] => @@ -346,7 +343,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateTimeline: dispatchUpdateTimeline(dispatch), }); -export const StatefulOpenTimeline = connect( - makeMapStateToProps, - mapDispatchToProps -)(StatefulOpenTimelineComponent); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulOpenTimeline = connector(StatefulOpenTimelineComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/types.ts b/x-pack/legacy/plugins/siem/public/components/open_timeline/types.ts index e5e85ccf0954a..b14bb1cf86d31 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/types.ts @@ -4,11 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ActionCreator } from 'typescript-fsa'; - import { AllTimelinesVariables } from '../../containers/timeline/all'; import { TimelineModel } from '../../store/timeline/model'; -import { ColumnHeader } from '../timeline/body/column_headers/column_header'; import { NoteResult } from '../../graphql/types'; /** The users who added a timeline to favorites */ @@ -163,17 +160,3 @@ export type DispatchUpdateTimeline = ({ timeline, to, }: UpdateTimeline) => () => void; - -export interface OpenTimelineDispatchProps { - updateTimeline: DispatchUpdateTimeline; - createNewTimeline: ActionCreator<{ - id: string; - columns: ColumnHeader[]; - show?: boolean; - }>; - updateIsLoading: ActionCreator<{ id: string; isLoading: boolean }>; -} - -export interface OpenTimelineReduxProps { - timeline: TimelineModel; -} 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 f5485922647ca..853ba7ae23414 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 @@ -8,8 +8,7 @@ import { has } from 'lodash/fp'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { hostsActions } from '../../../../store/hosts'; import { AuthenticationsEdges } from '../../../../graphql/types'; @@ -40,24 +39,6 @@ interface OwnProps { type: hostsModel.HostsType; } -interface AuthenticationTableReduxProps { - activePage: number; - limit: number; -} - -interface AuthenticationTableDispatchProps { - updateTableActivePage: ActionCreator<{ - activePage: number; - hostsType: hostsModel.HostsType; - tableType: hostsModel.HostsTableType; - }>; - updateTableLimit: ActionCreator<{ - limit: number; - hostsType: hostsModel.HostsType; - tableType: hostsModel.HostsTableType; - }>; -} - export type AuthTableColumns = [ Columns, Columns, @@ -70,9 +51,7 @@ export type AuthTableColumns = [ Columns ]; -type AuthenticationTableProps = OwnProps & - AuthenticationTableReduxProps & - AuthenticationTableDispatchProps; +type AuthenticationTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -154,10 +133,16 @@ const makeMapStateToProps = () => { }; }; -export const AuthenticationTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateTableActivePage: hostsActions.updateTableActivePage, updateTableLimit: hostsActions.updateTableLimit, -})(AuthenticationTableComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const AuthenticationTable = connector(AuthenticationTableComponent); const getAuthenticationColumns = (): AuthTableColumns => [ { 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 79bdf5c4b8315..0f56ef53ac081 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 @@ -5,8 +5,7 @@ */ import React, { useMemo, useCallback } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { IIndexPattern } from 'src/plugins/data/public'; import { hostsActions } from '../../../../store/actions'; import { @@ -46,30 +45,6 @@ interface OwnProps { type: hostsModel.HostsType; } -interface HostsTableReduxProps { - activePage: number; - direction: Direction; - limit: number; - sortField: HostsFields; -} - -interface HostsTableDispatchProps { - updateHostsSort: ActionCreator<{ - hostsType: hostsModel.HostsType; - sort: HostsSortField; - }>; - updateTableActivePage: ActionCreator<{ - activePage: number; - hostsType: hostsModel.HostsType; - tableType: hostsModel.HostsTableType; - }>; - updateTableLimit: ActionCreator<{ - hostsType: hostsModel.HostsType; - limit: number; - tableType: hostsModel.HostsTableType; - }>; -} - export type HostsTableColumns = [ Columns, Columns, @@ -77,7 +52,7 @@ export type HostsTableColumns = [ Columns ]; -type HostsTableProps = OwnProps & HostsTableReduxProps & HostsTableDispatchProps; +type HostsTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -217,10 +192,16 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const HostsTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateHostsSort: hostsActions.updateHostsSort, updateTableActivePage: hostsActions.updateTableActivePage, updateTableLimit: hostsActions.updateTableLimit, -})(HostsTableComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const HostsTable = connector(HostsTableComponent); HostsTable.displayName = 'HostsTable'; 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 b4c01053f0e9c..12744ddafa396 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 @@ -7,8 +7,7 @@ /* eslint-disable react/display-name */ import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { hostsActions } from '../../../../store/actions'; import { UncommonProcessesEdges, UncommonProcessItem } from '../../../../graphql/types'; @@ -33,24 +32,6 @@ interface OwnProps { type: hostsModel.HostsType; } -interface UncommonProcessTableReduxProps { - activePage: number; - limit: number; -} - -interface UncommonProcessTableDispatchProps { - updateTableActivePage: ActionCreator<{ - activePage: number; - hostsType: hostsModel.HostsType; - tableType: hostsModel.HostsTableType; - }>; - updateTableLimit: ActionCreator<{ - limit: number; - hostsType: hostsModel.HostsType; - tableType: hostsModel.HostsTableType; - }>; -} - export type UncommonProcessTableColumns = [ Columns, Columns, @@ -60,9 +41,7 @@ export type UncommonProcessTableColumns = [ Columns ]; -type UncommonProcessTableProps = OwnProps & - UncommonProcessTableReduxProps & - UncommonProcessTableDispatchProps; +type UncommonProcessTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -150,10 +129,16 @@ const makeMapStateToProps = () => { return (state: State, { type }: OwnProps) => getUncommonProcessesSelector(state, type); }; -export const UncommonProcessTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateTableActivePage: hostsActions.updateTableActivePage, updateTableLimit: hostsActions.updateTableLimit, -})(UncommonProcessTableComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const UncommonProcessTable = connector(UncommonProcessTableComponent); UncommonProcessTable.displayName = 'UncommonProcessTable'; 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 e316f951a0363..f3fe98936a55d 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 @@ -6,8 +6,7 @@ import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { networkActions } from '../../../../store/actions'; import { @@ -37,22 +36,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface NetworkDnsTableReduxProps { - activePage: number; - limit: number; - sort: NetworkDnsSortField; - isPtrIncluded: boolean; -} - -interface NetworkDnsTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.AllNetworkTables; - updates: networkModel.TableUpdates; - }>; -} - -type NetworkDnsTableProps = OwnProps & NetworkDnsTableReduxProps & NetworkDnsTableDispatchProps; +type NetworkDnsTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -172,6 +156,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const NetworkDnsTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, -})(NetworkDnsTableComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const NetworkDnsTable = connector(NetworkDnsTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/__snapshots__/index.test.tsx.snap index dfc1b2cf64e38..875a490d86be3 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/__snapshots__/index.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`NetworkHttp Table Component rendering it renders the default NetworkHttp table 1`] = ` - { ); - expect(wrapper.find('Connect(NetworkHttpTableComponent)')).toMatchSnapshot(); + expect(wrapper.find('Connect(Component)')).toMatchSnapshot(); }); }); 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 58adc971b0101..87038eb6aaeeb 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 @@ -5,17 +5,10 @@ */ import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { networkActions } from '../../../../store/actions'; -import { - Direction, - NetworkHttpEdges, - NetworkHttpFields, - NetworkHttpSortField, -} from '../../../../graphql/types'; +import { Direction, NetworkHttpEdges, NetworkHttpFields } from '../../../../graphql/types'; import { networkModel, networkSelectors, State } from '../../../../store'; import { Criteria, ItemsPerRow, PaginatedTable } from '../../../paginated_table'; @@ -34,21 +27,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface NetworkHttpTableReduxProps { - activePage: number; - limit: number; - sort: NetworkHttpSortField; -} - -interface NetworkHttpTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.AllNetworkTables; - updates: networkModel.TableUpdates; - }>; -} - -type NetworkHttpTableProps = OwnProps & NetworkHttpTableReduxProps & NetworkHttpTableDispatchProps; +type NetworkHttpTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -61,91 +40,89 @@ const rowItems: ItemsPerRow[] = [ }, ]; -const NetworkHttpTableComponent = React.memo( - ({ - activePage, - data, - fakeTotalCount, - id, - isInspect, - limit, - loading, - loadPage, - showMorePagesIndicator, - sort, - totalCount, - type, - updateNetworkTable, - }) => { - const tableType = - type === networkModel.NetworkType.page - ? networkModel.NetworkTableType.http - : networkModel.IpDetailsTableType.http; - - const updateLimitPagination = useCallback( - newLimit => +const NetworkHttpTableComponent: React.FC = ({ + activePage, + data, + fakeTotalCount, + id, + isInspect, + limit, + loading, + loadPage, + showMorePagesIndicator, + sort, + totalCount, + type, + updateNetworkTable, +}) => { + const tableType = + type === networkModel.NetworkType.page + ? networkModel.NetworkTableType.http + : networkModel.IpDetailsTableType.http; + + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable, tableType] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable, tableType] + ); + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null && criteria.sort.direction !== sort.direction) { updateNetworkTable({ networkType: type, tableType, - updates: { limit: newLimit }, - }), - [type, updateNetworkTable, tableType] - ); - - const updateActivePage = useCallback( - newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }), - [type, updateNetworkTable, tableType] - ); - - const onChange = useCallback( - (criteria: Criteria) => { - if (criteria.sort != null && criteria.sort.direction !== sort.direction) { - updateNetworkTable({ - networkType: type, - tableType, - updates: { - sort: { - direction: criteria.sort.direction as Direction, - }, + updates: { + sort: { + direction: criteria.sort.direction as Direction, }, - }); - } - }, - [tableType, sort.direction, type, updateNetworkTable] - ); - - const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; - - return ( - - ); - } -); + }, + }); + } + }, + [tableType, sort.direction, type, updateNetworkTable] + ); + + const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; + + return ( + + ); +}; NetworkHttpTableComponent.displayName = 'NetworkHttpTableComponent'; @@ -155,8 +132,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const NetworkHttpTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(NetworkHttpTableComponent); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const NetworkHttpTable = connector(React.memo(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 6d14b52d3586d..37355a37fa6d7 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 @@ -6,9 +6,7 @@ import { isEqual, last } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { IIndexPattern } from 'src/plugins/data/public'; import { networkActions } from '../../../../store/actions'; @@ -39,23 +37,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface NetworkTopCountriesTableReduxProps { - activePage: number; - limit: number; - sort: NetworkTopTablesSortField; -} - -interface NetworkTopCountriesTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.AllNetworkTables; - updates: networkModel.TableUpdates; - }>; -} - -type NetworkTopCountriesTableProps = OwnProps & - NetworkTopCountriesTableReduxProps & - NetworkTopCountriesTableDispatchProps; +type NetworkTopCountriesTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -197,8 +179,12 @@ const makeMapStateToProps = () => { getTopCountriesSelector(state, type, flowTargeted); }; -export const NetworkTopCountriesTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(NetworkTopCountriesTableComponent); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const NetworkTopCountriesTable = connector(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 7c1fcb2681a8c..c4f6dad0a47ed 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 @@ -5,9 +5,7 @@ */ import { isEqual, last } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { networkActions } from '../../../../store/actions'; import { @@ -36,23 +34,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface NetworkTopNFlowTableReduxProps { - activePage: number; - limit: number; - sort: NetworkTopTablesSortField; -} - -interface NetworkTopNFlowTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.TopNTableType; - updates: networkModel.TableUpdates; - }>; -} - -type NetworkTopNFlowTableProps = OwnProps & - NetworkTopNFlowTableReduxProps & - NetworkTopNFlowTableDispatchProps; +type NetworkTopNFlowTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -180,8 +162,12 @@ const makeMapStateToProps = () => { getTopNFlowSelector(state, type, flowTargeted); }; -export const NetworkTopNFlowTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(React.memo(NetworkTopNFlowTableComponent)); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const NetworkTopNFlowTable = connector(React.memo(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 95c0fff054440..77abae68b76bf 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 @@ -6,9 +6,7 @@ import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { networkActions } from '../../../../store/network'; import { TlsEdges, TlsSortField, TlsFields, Direction } from '../../../../graphql/types'; @@ -29,21 +27,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface TlsTableReduxProps { - activePage: number; - limit: number; - sort: TlsSortField; -} - -interface TlsTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.AllNetworkTables; - updates: networkModel.TableUpdates; - }>; -} - -type TlsTableProps = OwnProps & TlsTableReduxProps & TlsTableDispatchProps; +type TlsTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -152,11 +136,15 @@ const makeMapStateToProps = () => { return (state: State, { type }: OwnProps) => getTlsSelector(state, type); }; -export const TlsTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(TlsTableComponent); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const TlsTable = connector(TlsTableComponent); const getSortField = (sortField: TlsSortField): SortingBasicTable => ({ field: `node.${sortField.field}`, 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 f4f14c7c009dc..bc7ef2314add4 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 @@ -6,8 +6,7 @@ import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { networkActions } from '../../../../store/network'; import { @@ -38,21 +37,7 @@ interface OwnProps { type: networkModel.NetworkType; } -interface UsersTableReduxProps { - activePage: number; - limit: number; - sort: UsersSortField; -} - -interface UsersTableDispatchProps { - updateNetworkTable: ActionCreator<{ - networkType: networkModel.NetworkType; - tableType: networkModel.AllNetworkTables; - updates: networkModel.TableUpdates; - }>; -} - -type UsersTableProps = OwnProps & UsersTableReduxProps & UsersTableDispatchProps; +type UsersTableProps = OwnProps & PropsFromRedux; const rowItems: ItemsPerRow[] = [ { @@ -159,9 +144,15 @@ const makeMapStateToProps = () => { }); }; -export const UsersTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, -})(UsersTableComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const UsersTable = connector(UsersTableComponent); const getSortField = (sortField: UsersSortField): SortingBasicTable => { switch (sortField.field) { diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap index 59d2d91897254..86a3c67227119 100644 --- a/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap @@ -333,6 +333,7 @@ exports[`Paginated Table Component rendering it renders the default load more ta "graphic": "#e7664c", }, }, + "euiPaletteColorBlindKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9'", "euiPanelPaddingModifiers": Object { "paddingLarge": "24px", "paddingMedium": "16px", @@ -437,6 +438,54 @@ exports[`Paginated Table Component rendering it renders the default load more ta "euiTextScale": "2.25 1.75 1.25 1.125 1 0.875 0.75", "euiTitleColor": "#dfe5ef", "euiToastWidth": "320px", + "euiTokenGrayColor": "#535966", + "euiTokenTypeKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9', 'gray'", + "euiTokenTypes": Object { + "euiColorVis0": Object { + "behindText": "#6dccb1", + "graphic": "#54b399", + }, + "euiColorVis1": Object { + "behindText": "#79aad9", + "graphic": "#6092c0", + }, + "euiColorVis2": Object { + "behindText": "#ee789d", + "graphic": "#d36086", + }, + "euiColorVis3": Object { + "behindText": "#a987d1", + "graphic": "#9170b8", + }, + "euiColorVis4": Object { + "behindText": "#e4a6c7", + "graphic": "#ca8eae", + }, + "euiColorVis5": Object { + "behindText": "#f1d86f", + "graphic": "#d6bf57", + }, + "euiColorVis6": Object { + "behindText": "#d2c0a0", + "graphic": "#b9a888", + }, + "euiColorVis7": Object { + "behindText": "#f5a35c", + "graphic": "#da8b45", + }, + "euiColorVis8": Object { + "behindText": "#c47c6c", + "graphic": "#aa6556", + }, + "euiColorVis9": Object { + "behindText": "#ff7e62", + "graphic": "#e7664c", + }, + "gray": Object { + "behindText": "#535966", + "graphic": "#535966", + }, + }, "euiTooltipAnimations": Object { "bottom": "euiToolTipLeft", "left": "euiToolTipBottom", @@ -548,20 +597,6 @@ exports[`Paginated Table Component rendering it renders the default load more ta "success": "#7de2d1", "warning": "#ffce7a", }, - "tokenTypes": Object { - "tokenTint01": "#1ba9f5", - "tokenTint02": "#f990c0", - "tokenTint03": "#9170b8", - "tokenTint04": "#da8b45", - "tokenTint05": "#6092c0", - "tokenTint06": "#e6c220", - "tokenTint07": "#54b399", - "tokenTint08": "#920000", - "tokenTint09": "#ff00ff", - "tokenTint10": "#26ab00", - "tokenTint11": "#4c1604", - "tokenTint12": "#666666", - }, }, } } diff --git a/x-pack/legacy/plugins/siem/public/components/recent_timelines/index.tsx b/x-pack/legacy/plugins/siem/public/components/recent_timelines/index.tsx index d5157e81b0fc8..41eb137742963 100644 --- a/x-pack/legacy/plugins/siem/public/components/recent_timelines/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/recent_timelines/index.tsx @@ -7,14 +7,14 @@ import ApolloClient from 'apollo-client'; import { EuiHorizontalRule, EuiLink, EuiText } from '@elastic/eui'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { ActionCreator } from 'typescript-fsa'; import { AllTimelinesQuery } from '../../containers/timeline/all'; import { SortFieldTimeline, Direction } from '../../graphql/types'; import { queryTimelineById, dispatchUpdateTimeline } from '../open_timeline/helpers'; -import { DispatchUpdateTimeline, OnOpenTimeline } from '../open_timeline/types'; +import { OnOpenTimeline } from '../open_timeline/types'; import { LoadingPlaceholders } from '../page/overview/loading_placeholders'; import { updateIsLoading as dispatchUpdateIsLoading } from '../../store/timeline/actions'; @@ -31,12 +31,7 @@ interface OwnProps { filterBy: FilterMode; } -interface DispatchProps { - updateIsLoading: ({ id, isLoading }: { id: string; isLoading: boolean }) => void; - updateTimeline: DispatchUpdateTimeline; -} - -export type Props = OwnProps & DispatchProps; +export type Props = OwnProps & PropsFromRedux; const StatefulRecentTimelinesComponent = React.memo( ({ apolloClient, filterBy, updateIsLoading, updateTimeline }) => { @@ -100,7 +95,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateTimeline: dispatchUpdateTimeline(dispatch), }); -export const StatefulRecentTimelines = connect( - null, - mapDispatchToProps -)(StatefulRecentTimelinesComponent); +const connector = connect(null, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulRecentTimelines = connector(StatefulRecentTimelinesComponent); 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 2c3f677cc585d..cb5729ad8e26e 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 @@ -6,7 +6,7 @@ import { getOr, isEqual, set } from 'lodash/fp'; import React, { memo, useEffect, useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { Subscription } from 'rxjs'; import styled from 'styled-components'; @@ -34,29 +34,6 @@ import { import { timelineActions, hostsActions, networkActions } from '../../store/actions'; import { useKibana } from '../../lib/kibana'; -interface SiemSearchBarRedux { - end: number; - fromStr: string; - isLoading: boolean; - queries: inputsModel.GlobalGraphqlQuery[]; - filterQuery: Query; - savedQuery?: SavedQuery; - start: number; - toStr: string; -} - -interface SiemSearchBarDispatch { - updateSearch: DispatchUpdateSearch; - setSavedQuery: ({ - id, - savedQuery, - }: { - id: InputsModelId; - savedQuery: SavedQuery | undefined; - }) => void; - setSearchBarFilter: ({ id, filters }: { id: InputsModelId; filters: Filter[] }) => void; -} - interface SiemSearchBarProps { id: InputsModelId; indexPattern: IIndexPattern; @@ -70,7 +47,7 @@ const SearchBarContainer = styled.div` } `; -const SearchBarComponent = memo( +const SearchBarComponent = memo( ({ end, filterQuery, @@ -322,15 +299,7 @@ interface UpdateReduxSearchBar extends OnTimeChangeProps { updateTime: boolean; } -type DispatchUpdateSearch = ({ - end, - id, - isQuickSelection, - start, - timelineId, -}: UpdateReduxSearchBar) => void; - -const dispatchUpdateSearch = (dispatch: Dispatch) => ({ +export const dispatchUpdateSearch = (dispatch: Dispatch) => ({ end, filters, id, @@ -403,4 +372,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(inputsActions.setSearchBarFilter({ id, filters })), }); -export const SiemSearchBar = connect(makeMapStateToProps, mapDispatchToProps)(SearchBarComponent); +export const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const SiemSearchBar = connector(SearchBarComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx index 0877906c721ce..ad38a7d61bcba 100644 --- a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx @@ -14,7 +14,7 @@ import { } from '@elastic/eui'; import { getOr, take, isEmpty } from 'lodash/fp'; import React, { useState, useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { DEFAULT_TIMEPICKER_QUICK_RANGES } from '../../../common/constants'; @@ -34,7 +34,7 @@ import { queriesSelector, kqlQuerySelector, } from './selectors'; -import { InputsRange, Policy } from '../../store/inputs/model'; +import { InputsRange } from '../../store/inputs/model'; const MAX_RECENTLY_USED_RANGES = 9; @@ -44,19 +44,6 @@ interface Range { display: string; } -interface SuperDatePickerStateRedux { - duration: number; - end: number; - fromStr: string; - isLoading: boolean; - kind: string; - kqlQuery: inputsModel.GlobalKqlQuery; - policy: Policy['kind']; - queries: inputsModel.GlobalGraphqlQuery[]; - start: number; - toStr: string; -} - interface UpdateReduxTime extends OnTimeChangeProps { id: InputsModelId; kql?: inputsModel.GlobalKqlQuery | undefined; @@ -76,22 +63,13 @@ export type DispatchUpdateReduxTime = ({ timelineId, }: UpdateReduxTime) => ReturnUpdateReduxTime; -interface SuperDatePickerDispatchProps { - setDuration: ({ id, duration }: { id: InputsModelId; duration: number }) => void; - startAutoReload: ({ id }: { id: InputsModelId }) => void; - stopAutoReload: ({ id }: { id: InputsModelId }) => void; - updateReduxTime: DispatchUpdateReduxTime; -} - interface OwnProps { disabled?: boolean; id: InputsModelId; timelineId?: string; } -export type SuperDatePickerProps = OwnProps & - SuperDatePickerDispatchProps & - SuperDatePickerStateRedux; +export type SuperDatePickerProps = OwnProps & PropsFromRedux; export const SuperDatePickerComponent = React.memo( ({ @@ -308,9 +286,9 @@ export const makeMapStateToProps = () => { fromStr: getFromStrSelector(inputsRange), isLoading: getIsLoadingSelector(inputsRange), kind: getKindSelector(inputsRange), - kqlQuery: getKqlQuerySelector(inputsRange), + kqlQuery: getKqlQuerySelector(inputsRange) as inputsModel.GlobalKqlQuery, policy: getPolicySelector(inputsRange), - queries: getQueriesSelector(inputsRange), + queries: getQueriesSelector(inputsRange) as inputsModel.GlobalGraphqlQuery[], start: getStartSelector(inputsRange), toStr: getToStrSelector(inputsRange), }; @@ -328,7 +306,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateReduxTime: dispatchUpdateReduxTime(dispatch), }); -export const SuperDatePicker = connect( - makeMapStateToProps, - mapDispatchToProps -)(SuperDatePickerComponent); +export const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const SuperDatePicker = connector(SuperDatePickerComponent); 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 c2dfda6a81ce4..90d0738aba72f 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 @@ -12,41 +12,17 @@ import { } from '@elastic/eui'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { State, timelineSelectors } from '../../../store'; import { setTimelineRangeDatePicker as dispatchSetTimelineRangeDatePicker } from '../../../store/inputs/actions'; -import { TimelineModel } from '../../../store/timeline/model'; import * as i18n from './translations'; import { timelineActions } from '../../../store/timeline'; import { AutoSavedWarningMsg } from '../../../store/timeline/types'; import { useStateToaster } from '../../toasters'; -interface ReduxProps { - timelineId: string | null; - newTimelineModel: TimelineModel | null; -} - -interface DispatchProps { - setTimelineRangeDatePicker: ActionCreator<{ - from: number; - to: number; - }>; - updateAutoSaveMsg: ActionCreator<{ - timelineId: string | null; - newTimelineModel: TimelineModel | null; - }>; - updateTimeline: ActionCreator<{ - id: string; - timeline: TimelineModel; - }>; -} - -type OwnProps = ReduxProps & DispatchProps; - -const AutoSaveWarningMsgComponent = React.memo( +const AutoSaveWarningMsgComponent = React.memo( ({ newTimelineModel, setTimelineRangeDatePicker, @@ -106,8 +82,14 @@ const mapStateToProps = (state: State) => { }; }; -export const AutoSaveWarningMsg = connect(mapStateToProps, { +const mapDispatchToProps = { setTimelineRangeDatePicker: dispatchSetTimelineRangeDatePicker, updateAutoSaveMsg: timelineActions.updateAutoSaveMsg, updateTimeline: timelineActions.updateTimeline, -})(AutoSaveWarningMsgComponent); +}; + +const connector = connect(mapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const AutoSaveWarningMsg = connector(AutoSaveWarningMsgComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/index.test.tsx index 239d8a9d77916..cf35c8e565bbc 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/index.test.tsx @@ -66,7 +66,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} @@ -110,7 +109,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} @@ -154,7 +152,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} @@ -200,7 +197,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} @@ -293,7 +289,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} @@ -339,7 +334,6 @@ describe('Body', () => { onUnPinEvent={jest.fn()} onUpdateColumns={jest.fn()} pinnedEventIds={{}} - range={'1 Day'} rowRenderers={rowRenderers} selectedEventIds={{}} sort={mockSort} diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/index.tsx index f00da48266927..7f689a877c6b7 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/index.tsx @@ -54,7 +54,6 @@ export interface BodyProps { onUpdateColumns: OnUpdateColumns; onUnPinEvent: OnUnPinEvent; pinnedEventIds: Readonly>; - range: string; rowRenderers: RowRenderer[]; selectedEventIds: Readonly>; showCheckboxes: boolean; 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 edf0613ac2693..ffb5f2a206f4d 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 @@ -7,13 +7,12 @@ import { noop } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import React, { useCallback, useEffect } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { BrowserFields } from '../../../containers/source'; -import { TimelineItem, TimelineNonEcsData } from '../../../graphql/types'; +import { TimelineItem } from '../../../graphql/types'; import { Note } from '../../../lib/note'; -import { appModel, appSelectors, State, timelineSelectors } from '../../../store'; +import { appSelectors, State, timelineSelectors } from '../../../store'; import { AddNoteToEvent, UpdateNote } from '../../notes/helpers'; import { OnColumnRemoved, @@ -46,59 +45,7 @@ interface OwnProps { toggleColumn: (column: ColumnHeader) => void; } -interface ReduxProps { - columnHeaders: ColumnHeader[]; - eventIdToNoteIds: Readonly>; - isSelectAllChecked: boolean; - loadingEventIds: Readonly; - notesById: appModel.NotesById; - pinnedEventIds: Readonly>; - range?: string; - selectedEventIds: Readonly>; - showCheckboxes: boolean; - showRowRenderers: boolean; -} - -interface DispatchProps { - addNoteToEvent?: ActionCreator<{ id: string; noteId: string; eventId: string }>; - applyDeltaToColumnWidth?: ActionCreator<{ - id: string; - columnId: string; - delta: number; - }>; - clearSelected?: ActionCreator<{ - id: string; - }>; - pinEvent?: ActionCreator<{ - id: string; - eventId: string; - }>; - removeColumn?: ActionCreator<{ - id: string; - columnId: string; - }>; - setSelected?: ActionCreator<{ - id: string; - eventIds: Record; - isSelected: boolean; - isSelectAllChecked: boolean; - }>; - unPinEvent?: ActionCreator<{ - id: string; - eventId: string; - }>; - updateColumns?: ActionCreator<{ - id: string; - columns: ColumnHeader[]; - }>; - updateSort?: ActionCreator<{ - id: string; - sort: Sort; - }>; - updateNote?: ActionCreator<{ note: Note }>; -} - -type StatefulBodyComponentProps = OwnProps & ReduxProps & DispatchProps; +type StatefulBodyComponentProps = OwnProps & PropsFromRedux; export const emptyColumnHeaders: ColumnHeader[] = []; @@ -118,7 +65,6 @@ const StatefulBodyComponent = React.memo( notesById, pinEvent, pinnedEventIds, - range, removeColumn, selectedEventIds, setSelected, @@ -234,7 +180,6 @@ const StatefulBodyComponent = React.memo( onUnPinEvent={onUnPinEvent} onUpdateColumns={onUpdateColumns} pinnedEventIds={pinnedEventIds} - range={range!} rowRenderers={showRowRenderers ? rowRenderers : [plainRowRenderer]} selectedEventIds={selectedEventIds} showCheckboxes={showCheckboxes} @@ -260,7 +205,6 @@ const StatefulBodyComponent = React.memo( prevProps.selectedEventIds === nextProps.selectedEventIds && prevProps.showCheckboxes === nextProps.showCheckboxes && prevProps.showRowRenderers === nextProps.showRowRenderers && - prevProps.range === nextProps.range && prevProps.sort === nextProps.sort ); } @@ -307,7 +251,7 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulBody = connect(makeMapStateToProps, { +const mapDispatchToProps = { addNoteToEvent: timelineActions.addNoteToEvent, applyDeltaToColumnWidth: timelineActions.applyDeltaToColumnWidth, clearSelected: timelineActions.clearSelected, @@ -319,4 +263,10 @@ export const StatefulBody = connect(makeMapStateToProps, { updateColumns: timelineActions.updateColumns, updateNote: appActions.updateNote, updateSort: timelineActions.updateSort, -})(StatefulBodyComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulBody = connector(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 4b1e723f1bb3a..65c539d77a16b 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 @@ -5,37 +5,21 @@ */ import { memo, useEffect } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { IIndexPattern } from 'src/plugins/data/public'; -import { inputsModel, KueryFilterQuery, timelineSelectors, State } from '../../store'; +import { timelineSelectors, State } from '../../store'; import { inputsActions } from '../../store/actions'; import { InputsModelId } from '../../store/inputs/constants'; import { useUpdateKql } from '../../utils/kql/use_update_kql'; -interface TimelineKqlFetchRedux { - kueryFilterQuery: KueryFilterQuery | null; - kueryFilterQueryDraft: KueryFilterQuery | null; -} - -interface TimelineKqlFetchDispatch { - setTimelineQuery: ActionCreator<{ - id: string; - inputId: InputsModelId; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch | inputsModel.RefetchKql | null; - }>; -} - export interface TimelineKqlFetchProps { id: string; indexPattern: IIndexPattern; inputId: InputsModelId; } -type OwnProps = TimelineKqlFetchProps & TimelineKqlFetchRedux & TimelineKqlFetchDispatch; +type OwnProps = TimelineKqlFetchProps & PropsFromRedux; const TimelineKqlFetchComponent = memo( ({ id, indexPattern, inputId, kueryFilterQuery, kueryFilterQueryDraft, setTimelineQuery }) => { @@ -70,6 +54,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const TimelineKqlFetch = connect(makeMapStateToProps, { +const mapDispatchToProps = { setTimelineQuery: inputsActions.setQuery, -})(TimelineKqlFetchComponent); +}; + +export const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const TimelineKqlFetch = connector(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 b6a57ebacb11c..34f760e411ed4 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx @@ -6,21 +6,16 @@ import { isEqual } from 'lodash/fp'; import React, { useEffect, useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; - -import { Filter } from '../../../../../../../src/plugins/data/public'; +import { connect, ConnectedProps } from 'react-redux'; import { WithSource } from '../../containers/source'; import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store'; import { timelineActions } from '../../store/actions'; -import { EventType, KqlMode, timelineDefaults, TimelineModel } from '../../store/timeline/model'; +import { timelineDefaults, TimelineModel } from '../../store/timeline/model'; import { useSignalIndex } from '../../containers/detection_engine/signals/use_signal_index'; import { ColumnHeader } from './body/column_headers/column_header'; -import { DataProvider, QueryOperator } from './data_providers/data_provider'; import { defaultHeaders } from './body/column_headers/default_headers'; -import { Sort } from './body/sort'; import { OnChangeDataProviderKqlQuery, OnChangeDroppableAndProvider, @@ -38,103 +33,7 @@ export interface OwnProps { flyoutHeight: number; } -interface StateReduxProps { - activePage?: number; - columns: ColumnHeader[]; - dataProviders?: DataProvider[]; - eventType: EventType; - end: number; - filters: Filter[]; - isLive: boolean; - itemsPerPage?: number; - itemsPerPageOptions?: number[]; - kqlMode: KqlMode; - kqlQueryExpression: string; - pageCount?: number; - sort?: Sort; - start: number; - show?: boolean; - showCallOutUnauthorizedMsg: boolean; -} - -interface DispatchProps { - createTimeline?: ActionCreator<{ - id: string; - columns: ColumnHeader[]; - show?: boolean; - }>; - addProvider?: ActionCreator<{ - id: string; - provider: DataProvider; - }>; - onDataProviderEdited?: ActionCreator<{ - andProviderId?: string; - excluded: boolean; - field: string; - id: string; - operator: QueryOperator; - providerId: string; - value: string | number; - }>; - updateColumns?: ActionCreator<{ - id: string; - category: string; - columns: ColumnHeader[]; - }>; - updateProviders?: ActionCreator<{ - id: string; - providers: DataProvider[]; - }>; - removeColumn?: ActionCreator<{ - id: string; - columnId: string; - }>; - removeProvider?: ActionCreator<{ - id: string; - providerId: string; - andProviderId?: string; - }>; - updateDataProviderEnabled?: ActionCreator<{ - id: string; - providerId: string; - enabled: boolean; - andProviderId?: string; - }>; - updateDataProviderExcluded?: ActionCreator<{ - id: string; - excluded: boolean; - providerId: string; - andProviderId?: string; - }>; - updateDataProviderKqlQuery?: ActionCreator<{ - id: string; - kqlQuery: string; - providerId: string; - }>; - updateItemsPerPage?: ActionCreator<{ - id: string; - itemsPerPage: number; - }>; - updateItemsPerPageOptions?: ActionCreator<{ - id: string; - itemsPerPageOptions: number[]; - }>; - updatePageIndex?: ActionCreator<{ - id: string; - activePage: number; - }>; - updateHighlightedDropAndProviderId?: ActionCreator<{ - id: string; - providerId: string; - }>; - upsertColumn?: ActionCreator<{ - column: ColumnHeader; - id: string; - index: number; - }>; -} - -type Props = OwnProps & StateReduxProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const StatefulTimelineComponent = React.memo( ({ @@ -169,7 +68,12 @@ const StatefulTimelineComponent = React.memo( const { loading, signalIndexExists, signalIndexName } = useSignalIndex(); const indexToAdd = useMemo(() => { - if (signalIndexExists && signalIndexName != null && ['signal', 'all'].includes(eventType)) { + if ( + eventType && + signalIndexExists && + signalIndexName != null && + ['signal', 'all'].includes(eventType) + ) { return [signalIndexName]; } return []; @@ -300,7 +204,6 @@ const StatefulTimelineComponent = React.memo( }, (prevProps, nextProps) => { return ( - prevProps.activePage === nextProps.activePage && prevProps.eventType === nextProps.eventType && prevProps.end === nextProps.end && prevProps.flyoutHeaderHeight === nextProps.flyoutHeaderHeight && @@ -310,7 +213,6 @@ const StatefulTimelineComponent = React.memo( prevProps.itemsPerPage === nextProps.itemsPerPage && prevProps.kqlMode === nextProps.kqlMode && prevProps.kqlQueryExpression === nextProps.kqlQueryExpression && - prevProps.pageCount === nextProps.pageCount && prevProps.show === nextProps.show && prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg && prevProps.start === nextProps.start && @@ -344,7 +246,7 @@ const makeMapStateToProps = () => { show, sort, } = timeline; - const kqlQueryExpression = getKqlQueryTimeline(state, id); + const kqlQueryExpression = getKqlQueryTimeline(state, id)!; const timelineFilter = kqlMode === 'filter' ? filters || [] : []; @@ -369,7 +271,7 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const StatefulTimeline = connect(makeMapStateToProps, { +const mapDispatchToProps = { addProvider: timelineActions.addProvider, createTimeline: timelineActions.createTimeline, onDataProviderEdited: timelineActions.dataProviderEdited, @@ -384,4 +286,10 @@ export const StatefulTimeline = connect(makeMapStateToProps, { updateItemsPerPageOptions: timelineActions.updateItemsPerPageOptions, updateSort: timelineActions.updateSort, upsertColumn: timelineActions.upsertColumn, -})(StatefulTimelineComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulTimeline = connector(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 c804ccf658296..3d2ec0683f091 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 @@ -5,33 +5,21 @@ */ import React, { useEffect } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { inputsModel } from '../../store'; import { inputsActions } from '../../store/actions'; import { InputsModelId } from '../../store/inputs/constants'; -interface TimelineRefetchDispatch { - setTimelineQuery: ActionCreator<{ - id: string; - inputId: InputsModelId; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch | inputsModel.RefetchKql | null; - }>; -} - export interface TimelineRefetchProps { id: string; inputId: InputsModelId; inspect: inputsModel.InspectQuery | null; loading: boolean; - refetch: inputsModel.Refetch | null; + refetch: inputsModel.Refetch; } -type OwnProps = TimelineRefetchProps & TimelineRefetchDispatch; +type OwnProps = TimelineRefetchProps & PropsFromRedux; const TimelineRefetchComponent: React.FC = ({ id, @@ -48,8 +36,12 @@ const TimelineRefetchComponent: React.FC = ({ return null; }; -export const TimelineRefetch = compose>( - connect(null, { - setTimelineQuery: inputsActions.setQuery, - }) -)(React.memo(TimelineRefetchComponent)); +const mapDispatchToProps = { + setTimelineQuery: inputsActions.setQuery, +}; + +const connector = connect(null, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const TimelineRefetch = connector(React.memo(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 3c47823fbbc3b..2b139d3948fe1 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 @@ -6,7 +6,7 @@ import { getOr, isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { Filter, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; @@ -22,8 +22,7 @@ import { } from '../../../store'; import { timelineActions } from '../../../store/actions'; import { KqlMode, timelineDefaults, TimelineModel, EventType } from '../../../store/timeline/model'; -import { DispatchUpdateReduxTime, dispatchUpdateReduxTime } from '../../super_date_picker'; -import { DataProvider } from '../data_providers/data_provider'; +import { dispatchUpdateReduxTime } from '../../super_date_picker'; import { SearchOrFilter } from './search_or_filter'; interface OwnProps { @@ -32,45 +31,7 @@ interface OwnProps { timelineId: string; } -interface StateReduxProps { - dataProviders: DataProvider[]; - eventType: EventType; - filters: Filter[]; - filterQuery: KueryFilterQuery; - filterQueryDraft: KueryFilterQuery; - from: number; - fromStr: string; - isRefreshPaused: boolean; - kqlMode: KqlMode; - refreshInterval: number; - savedQueryId: string | null; - to: number; - toStr: string; -} - -interface DispatchProps { - applyKqlFilterQuery: ({ - id, - filterQuery, - }: { - id: string; - filterQuery: SerializedFilterQuery; - }) => void; - updateEventType: ({ id, eventType }: { id: string; eventType: EventType }) => void; - updateKqlMode: ({ id, kqlMode }: { id: string; kqlMode: KqlMode }) => void; - setKqlFilterQueryDraft: ({ - id, - filterQueryDraft, - }: { - id: string; - filterQueryDraft: KueryFilterQuery; - }) => void; - setSavedQueryId: ({ id, savedQueryId }: { id: string; savedQueryId: string | null }) => void; - setFilters: ({ id, filters }: { id: string; filters: Filter[] }) => void; - updateReduxTime: DispatchUpdateReduxTime; -} - -type Props = OwnProps & StateReduxProps & DispatchProps; +type Props = OwnProps & PropsFromRedux; const StatefulSearchOrFilterComponent = React.memo( ({ @@ -217,17 +178,17 @@ const makeMapStateToProps = () => { return { dataProviders: timeline.dataProviders, eventType: timeline.eventType ?? 'raw', - filterQuery: getKqlFilterQuery(state, timelineId), - filterQueryDraft: getKqlFilterQueryDraft(state, timelineId), - filters: timeline.filters, + filterQuery: getKqlFilterQuery(state, timelineId)!, + filterQueryDraft: getKqlFilterQueryDraft(state, timelineId)!, + filters: timeline.filters!, from: input.timerange.from, - fromStr: input.timerange.fromStr, + fromStr: input.timerange.fromStr!, isRefreshPaused: policy.kind === 'manual', kqlMode: getOr('filter', 'kqlMode', timeline), refreshInterval: policy.duration, savedQueryId: getOr(null, 'savedQueryId', timeline), to: input.timerange.to, - toStr: input.timerange.toStr, + toStr: input.timerange.toStr!, }; }; return mapStateToProps; @@ -265,7 +226,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateReduxTime: dispatchUpdateReduxTime(dispatch), }); -export const StatefulSearchOrFilter = connect( - makeMapStateToProps, - mapDispatchToProps -)(StatefulSearchOrFilterComponent); +export const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulSearchOrFilter = connector(StatefulSearchOrFilterComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx index 9d70b69124f30..09457c8f0285a 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx @@ -60,7 +60,7 @@ interface Props { columns: ColumnHeader[]; dataProviders: DataProvider[]; end: number; - eventType: EventType; + eventType?: EventType; filters: Filter[]; flyoutHeaderHeight: number; flyoutHeight: number; diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/errors_types/get_index_error.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/errors_types/get_index_error.ts index e4f2a658b7362..4f45b480772f2 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/errors_types/get_index_error.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/errors_types/get_index_error.ts @@ -8,13 +8,13 @@ import { MessageBody } from '../../../../components/ml/api/throw_if_not_ok'; export class SignalIndexError extends Error { message: string = ''; - statusCode: number = -1; + status_code: number = -1; error: string = ''; constructor(errObj: MessageBody) { super(errObj.message); this.message = errObj.message ?? ''; - this.statusCode = errObj.statusCode ?? -1; + this.status_code = errObj.status_code ?? -1; this.error = errObj.error ?? ''; this.name = 'SignalIndexError'; diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx index 2635d6e5540f1..813bd2483689c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx @@ -60,7 +60,7 @@ export const useSignalIndex = (): Return => { signalIndexName: null, createDeSignalIndex: createIndex, }); - if (error instanceof SignalIndexError && error.statusCode !== 404) { + if (error instanceof SignalIndexError && error.status_code !== 404) { errorToToaster({ title: i18n.SIGNAL_GET_NAME_FAILURE, error, dispatchToaster }); } } 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 d77e0215f8353..caf597d02c835 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 @@ -5,12 +5,10 @@ */ import React, { useState, useEffect } from 'react'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; +import { connect, ConnectedProps } from 'react-redux'; import { inputsModel, inputsSelectors, State } from '../../store'; import { inputsActions } from '../../store/actions'; -import { InputsModelId } from '../../store/inputs/constants'; interface SetQuery { id: string; @@ -19,10 +17,6 @@ interface SetQuery { refetch: inputsModel.Refetch | inputsModel.RefetchKql; } -interface GlobalQuery extends SetQuery { - inputId: InputsModelId; -} - export interface GlobalTimeArgs { from: number; to: number; @@ -31,21 +25,11 @@ export interface GlobalTimeArgs { isInitializing: boolean; } -interface GlobalTimeDispatch { - setGlobalQuery: ActionCreator; - deleteAllQuery: ActionCreator<{ id: InputsModelId }>; - deleteOneQuery: ActionCreator<{ inputId: InputsModelId; id: string }>; -} - -interface GlobalTimeReduxState { - from: number; - to: number; -} interface OwnProps { children: (args: GlobalTimeArgs) => React.ReactNode; } -type GlobalTimeProps = OwnProps & GlobalTimeReduxState & GlobalTimeDispatch; +type GlobalTimeProps = OwnProps & PropsFromRedux; export const GlobalTimeComponent: React.FC = ({ children, @@ -88,8 +72,14 @@ const mapStateToProps = (state: State) => { }; }; -export const GlobalTime = connect(mapStateToProps, { +const mapDispatchToProps = { deleteAllQuery: inputsActions.deleteAllQuery, deleteOneQuery: inputsActions.deleteOneQuery, setGlobalQuery: inputsActions.setQuery, -})(React.memo(GlobalTimeComponent)); +}; + +export const connector = connect(mapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const GlobalTime = connector(React.memo(GlobalTimeComponent)); diff --git a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx index 9576c66c4c9a5..ade94c430c6ef 100644 --- a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetIpOverviewQuery, IpOverviewData } from '../../graphql/types'; @@ -28,17 +28,13 @@ export interface IpOverviewArgs { refetch: inputsModel.Refetch; } -export interface IpOverviewReduxProps { - isInspected: boolean; -} - export interface IpOverviewProps extends QueryTemplateProps { children: (args: IpOverviewArgs) => React.ReactNode; type: networkModel.NetworkType; ip: string; } -const IpOverviewComponentQuery = React.memo( +const IpOverviewComponentQuery = React.memo( ({ id = ID, isInspected, children, filterQuery, skip, sourceId, ip }) => ( query={ipOverviewQuery} @@ -81,4 +77,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const IpOverviewQuery = connect(makeMapStateToProps)(IpOverviewComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const IpOverviewQuery = connector(IpOverviewComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx index 501bc8472b5e2..de9d54b1a185c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { KpiHostDetailsData, GetKpiHostDetailsQuery } from '../../graphql/types'; @@ -32,11 +32,7 @@ export interface QueryKpiHostDetailsProps extends QueryTemplateProps { children: (args: KpiHostDetailsArgs) => React.ReactNode; } -export interface KpiHostDetailsReducer { - isInspected: boolean; -} - -const KpiHostDetailsComponentQuery = React.memo( +const KpiHostDetailsComponentQuery = React.memo( ({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => ( query={kpiHostDetailsQuery} @@ -82,4 +78,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const KpiHostDetailsQuery = connect(makeMapStateToProps)(KpiHostDetailsComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const KpiHostDetailsQuery = connector(KpiHostDetailsComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx index 32472ba6deedf..5be2423e8a162 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetKpiHostsQuery, KpiHostsData } from '../../graphql/types'; @@ -28,15 +28,11 @@ export interface KpiHostsArgs { refetch: inputsModel.Refetch; } -export interface KpiHostsReducer { - isInspected: boolean; -} - export interface KpiHostsProps extends QueryTemplateProps { children: (args: KpiHostsArgs) => React.ReactNode; } -const KpiHostsComponentQuery = React.memo( +const KpiHostsComponentQuery = React.memo( ({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => ( query={kpiHostsQuery} @@ -82,4 +78,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const KpiHostsQuery = connect(makeMapStateToProps)(KpiHostsComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const KpiHostsQuery = connector(KpiHostsComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx index 52b8814958ba0..338cdc39b178c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetKpiNetworkQuery, KpiNetworkData } from '../../graphql/types'; @@ -28,15 +28,11 @@ export interface KpiNetworkArgs { refetch: inputsModel.Refetch; } -export interface KpiNetworkReducer { - isInspected: boolean; -} - export interface KpiNetworkProps extends QueryTemplateProps { children: (args: KpiNetworkArgs) => React.ReactNode; } -const KpiNetworkComponentQuery = React.memo( +const KpiNetworkComponentQuery = React.memo( ({ id = ID, children, filterQuery, isInspected, skip, sourceId, startDate, endDate }) => ( query={kpiNetworkQuery} @@ -82,4 +78,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const KpiNetworkQuery = connect(makeMapStateToProps)(KpiNetworkComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const KpiNetworkQuery = connector(KpiNetworkComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx index 8c40c4044a746..2dd9ccf24d802 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; import { GetOverviewHostQuery, OverviewHostData } from '../../../graphql/types'; @@ -29,10 +29,6 @@ export interface OverviewHostArgs { refetch: inputsModel.Refetch; } -export interface OverviewHostReducer { - isInspected: boolean; -} - export interface OverviewHostProps extends QueryTemplateProps { children: (args: OverviewHostArgs) => React.ReactNode; sourceId: string; @@ -40,7 +36,7 @@ export interface OverviewHostProps extends QueryTemplateProps { startDate: number; } -const OverviewHostComponentQuery = React.memo( +const OverviewHostComponentQuery = React.memo( ({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => { return ( @@ -86,4 +82,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const OverviewHostQuery = connect(makeMapStateToProps)(OverviewHostComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const OverviewHostQuery = connector(OverviewHostComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx index 9e7d59de0e546..d0acd41c224a5 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; import { GetOverviewNetworkQuery, OverviewNetworkData } from '../../../graphql/types'; @@ -29,10 +29,6 @@ export interface OverviewNetworkArgs { refetch: inputsModel.Refetch; } -export interface OverviewNetworkReducer { - isInspected: boolean; -} - export interface OverviewNetworkProps extends QueryTemplateProps { children: (args: OverviewNetworkArgs) => React.ReactNode; sourceId: string; @@ -40,37 +36,37 @@ export interface OverviewNetworkProps extends QueryTemplateProps { startDate: number; } -export const OverviewNetworkComponentQuery = React.memo< - OverviewNetworkProps & OverviewNetworkReducer ->(({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => ( - - query={overviewNetworkQuery} - fetchPolicy={getDefaultFetchPolicy()} - notifyOnNetworkStatusChange - variables={{ - sourceId, - timerange: { - interval: '12h', - from: startDate, - to: endDate, - }, - filterQuery: createFilter(filterQuery), - defaultIndex: useUiSetting(DEFAULT_INDEX_KEY), - inspect: isInspected, - }} - > - {({ data, loading, refetch }) => { - const overviewNetwork = getOr({}, `source.OverviewNetwork`, data); - return children({ - id, - inspect: getOr(null, 'source.OverviewNetwork.inspect', data), - overviewNetwork, - loading, - refetch, - }); - }} - -)); +export const OverviewNetworkComponentQuery = React.memo( + ({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => ( + + query={overviewNetworkQuery} + fetchPolicy={getDefaultFetchPolicy()} + notifyOnNetworkStatusChange + variables={{ + sourceId, + timerange: { + interval: '12h', + from: startDate, + to: endDate, + }, + filterQuery: createFilter(filterQuery), + defaultIndex: useUiSetting(DEFAULT_INDEX_KEY), + inspect: isInspected, + }} + > + {({ data, loading, refetch }) => { + const overviewNetwork = getOr({}, `source.OverviewNetwork`, data); + return children({ + id, + inspect: getOr(null, 'source.OverviewNetwork.inspect', data), + overviewNetwork, + loading, + refetch, + }); + }} + + ) +); OverviewNetworkComponentQuery.displayName = 'OverviewNetworkComponentQuery'; @@ -85,4 +81,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const OverviewNetworkQuery = connect(makeMapStateToProps)(OverviewNetworkComponentQuery); +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const OverviewNetworkQuery = connector(OverviewNetworkComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx b/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx index f4eb088b6ad94..68d87ef565fb7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx @@ -9,7 +9,7 @@ import memoizeOne from 'memoize-one'; import React from 'react'; import { Query } from 'react-apollo'; import { compose } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { IIndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; @@ -39,10 +39,6 @@ export interface TimelineArgs { getUpdatedAt: () => number; } -export interface TimelineQueryReduxProps { - isInspected: boolean; -} - export interface OwnProps extends QueryTemplateProps { children?: (args: TimelineArgs) => React.ReactNode; eventType?: EventType; @@ -53,7 +49,8 @@ export interface OwnProps extends QueryTemplateProps { sortField: SortField; fields: string[]; } -type TimelineQueryProps = OwnProps & TimelineQueryReduxProps & WithKibanaProps; + +type TimelineQueryProps = OwnProps & PropsFromRedux & WithKibanaProps; class TimelineQueryComponent extends QueryTemplate< TimelineQueryProps, @@ -171,7 +168,11 @@ const makeMapStateToProps = () => { return mapStateToProps; }; +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + export const TimelineQuery = compose>( - connect(makeMapStateToProps), + connector, withKibana )(TimelineQueryComponent); diff --git a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx index 520ade954eb5c..0a2ce67d9be80 100644 --- a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { compose } from 'redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; @@ -43,13 +43,7 @@ export interface OwnProps extends QueryTemplatePaginatedProps { type: hostsModel.HostsType; } -export interface UncommonProcessesComponentReduxProps { - activePage: number; - isInspected: boolean; - limit: number; -} - -type UncommonProcessesProps = OwnProps & UncommonProcessesComponentReduxProps & WithKibanaProps; +type UncommonProcessesProps = OwnProps & PropsFromRedux & WithKibanaProps; class UncommonProcessesComponentQuery extends QueryTemplatePaginated< UncommonProcessesProps, @@ -144,7 +138,11 @@ const makeMapStateToProps = () => { return mapStateToProps; }; +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + export const UncommonProcessesQuery = compose>( - connect(makeMapStateToProps), + connector, withKibana )(UncommonProcessesComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/containers/users/index.tsx b/x-pack/legacy/plugins/siem/public/containers/users/index.tsx index ece73b7b10ff0..5f71449c52460 100644 --- a/x-pack/legacy/plugins/siem/public/containers/users/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/users/index.tsx @@ -7,17 +7,11 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { compose } from 'redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { - GetUsersQuery, - FlowTarget, - PageInfoPaginated, - UsersEdges, - UsersSortField, -} from '../../graphql/types'; +import { GetUsersQuery, FlowTarget, PageInfoPaginated, UsersEdges } from '../../graphql/types'; import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store'; import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; @@ -47,14 +41,7 @@ export interface OwnProps extends QueryTemplatePaginatedProps { type: networkModel.NetworkType; } -export interface UsersComponentReduxProps { - activePage: number; - isInspected: boolean; - limit: number; - sort: UsersSortField; -} - -type UsersProps = OwnProps & UsersComponentReduxProps & WithKibanaProps; +type UsersProps = OwnProps & PropsFromRedux & WithKibanaProps; class UsersComponentQuery extends QueryTemplatePaginated< UsersProps, @@ -156,7 +143,11 @@ const makeMapStateToProps = () => { return mapStateToProps; }; +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + export const UsersQuery = compose>( - connect(makeMapStateToProps), + connector, withKibana )(UsersComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx index 8108e24cfa2c3..aacc6d951f4c9 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx @@ -7,17 +7,14 @@ import { EuiPanel, EuiLoadingContent } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; -import { ActionCreator } from 'typescript-fsa'; -import { Filter, esQuery, Query } from '../../../../../../../../../src/plugins/data/public'; +import { Filter, esQuery } from '../../../../../../../../../src/plugins/data/public'; import { useFetchIndexPatterns } from '../../../../containers/detection_engine/rules/fetch_index_patterns'; import { StatefulEventsViewer } from '../../../../components/events_viewer'; import { HeaderSection } from '../../../../components/header_section'; -import { DispatchUpdateTimeline } from '../../../../components/open_timeline/types'; import { combineQueries } from '../../../../components/timeline/helpers'; -import { TimelineNonEcsData } from '../../../../graphql/types'; import { useKibana } from '../../../../lib/kibana'; import { inputsSelectors, State, inputsModel } from '../../../../store'; import { timelineActions, timelineSelectors } from '../../../../store/timeline'; @@ -51,33 +48,6 @@ import { dispatchUpdateTimeline } from '../../../../components/open_timeline/hel const SIGNALS_PAGE_TIMELINE_ID = 'signals-page'; -interface ReduxProps { - globalQuery: Query; - globalFilters: Filter[]; - deletedEventIds: string[]; - isSelectAllChecked: boolean; - loadingEventIds: string[]; - selectedEventIds: Readonly>; -} - -interface DispatchProps { - clearEventsDeleted?: ActionCreator<{ id: string }>; - clearEventsLoading?: ActionCreator<{ id: string }>; - clearSelected?: ActionCreator<{ id: string }>; - setEventsDeleted?: ActionCreator<{ - id: string; - eventIds: string[]; - isDeleted: boolean; - }>; - setEventsLoading?: ActionCreator<{ - id: string; - eventIds: string[]; - isLoading: boolean; - }>; - updateTimelineIsLoading: ActionCreator<{ id: string; isLoading: boolean }>; - updateTimeline: DispatchUpdateTimeline; -} - interface OwnProps { canUserCRUD: boolean; defaultFilters?: Filter[]; @@ -88,7 +58,7 @@ interface OwnProps { to: number; } -type SignalsTableComponentProps = OwnProps & ReduxProps & DispatchProps; +type SignalsTableComponentProps = OwnProps & PropsFromRedux; const SignalsTableComponent: React.FC = ({ canUserCRUD, @@ -390,7 +360,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateTimeline: dispatchUpdateTimeline(dispatch), }); -export const SignalsTable = connect( - makeMapStateToProps, - mapDispatchToProps -)(React.memo(SignalsTableComponent)); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const SignalsTable = connector(React.memo(SignalsTableComponent)); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts index 4cecf7376ca41..8c88fa4a5dae6 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts @@ -86,7 +86,7 @@ export const STACK_BY_USERS = i18n.translate( export const HISTOGRAM_HEADER = i18n.translate( 'xpack.siem.detectionEngine.signals.histogram.headerTitle', { - defaultMessage: 'Signals count', + defaultMessage: 'Signal count', } ); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx index 8cfcac8fc862b..c3fb907ae83e1 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx @@ -8,11 +8,7 @@ import { EuiButton, EuiSpacer } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { useParams } from 'react-router-dom'; import { StickyContainer } from 'react-sticky'; -import { connect } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; - -import { Query } from '../../../../../../../src/plugins/data/common/query'; -import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; +import { connect, ConnectedProps } from 'react-redux'; import { GlobalTime } from '../../containers/global_time'; import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; @@ -30,7 +26,6 @@ import { State } from '../../store'; import { inputsSelectors } from '../../store/inputs'; import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../store/inputs/actions'; import { SpyRoute } from '../../utils/route/spy_routes'; -import { InputsModelId } from '../../store/inputs/constants'; import { InputsRange } from '../../store/inputs/model'; import { AlertsByCategory } from '../overview/alerts_by_category'; import { useSignalInfo } from './components/signals_info'; @@ -47,21 +42,6 @@ import { DetectionEngineUserUnauthenticated } from './detection_engine_user_unau import * as i18n from './translations'; import { DetectionEngineTab } from './types'; -interface ReduxProps { - filters: Filter[]; - query: Query; -} - -export interface DispatchProps { - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: number; - to: number; - }>; -} - -type DetectionEnginePageComponentProps = ReduxProps & DispatchProps; - const detectionsTabs: Record = { [DetectionEngineTab.signals]: { id: DetectionEngineTab.signals, @@ -79,7 +59,7 @@ const detectionsTabs: Record = { }, }; -const DetectionEnginePageComponent: React.FC = ({ +const DetectionEnginePageComponent: React.FC = ({ filters, query, setAbsoluteRangeDatePicker, @@ -234,7 +214,8 @@ const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, }; -export const DetectionEnginePage = connect( - makeMapStateToProps, - mapDispatchToProps -)(React.memo(DetectionEnginePageComponent)); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const DetectionEnginePage = connector(React.memo(DetectionEnginePageComponent)); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx index dc1ebd6052538..83dd18f0f14b7 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx @@ -19,9 +19,8 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { FC, memo, useCallback, useMemo, useState } from 'react'; import { Redirect, useParams } from 'react-router-dom'; import { StickyContainer } from 'react-sticky'; +import { connect, ConnectedProps } from 'react-redux'; -import { ActionCreator } from 'typescript-fsa'; -import { connect } from 'react-redux'; import { FiltersGlobal } from '../../../../components/filters_global'; import { FormattedDate } from '../../../../components/formatted_date'; import { @@ -59,9 +58,6 @@ import * as ruleI18n from '../translations'; import * as i18n from './translations'; import { GlobalTime } from '../../../../containers/global_time'; import { signalsHistogramOptions } from '../../components/signals_histogram_panel/config'; -import { InputsModelId } from '../../../../store/inputs/constants'; -import { Filter } from '../../../../../../../../../src/plugins/data/common/es_query'; -import { Query } from '../../../../../../../../../src/plugins/data/common/query'; import { inputsSelectors } from '../../../../store/inputs'; import { State } from '../../../../store'; import { InputsRange } from '../../../../store/inputs/model'; @@ -71,19 +67,6 @@ import { RuleStatusFailedCallOut } from './status_failed_callout'; import { FailureHistory } from './failure_history'; import { RuleStatus } from '../components/rule_status'; -interface ReduxProps { - filters: Filter[]; - query: Query; -} - -export interface DispatchProps { - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: number; - to: number; - }>; -} - enum RuleDetailTabs { signals = 'signals', failures = 'failures', @@ -102,9 +85,7 @@ const ruleDetailTabs = [ }, ]; -type RuleDetailsComponentProps = ReduxProps & DispatchProps; - -const RuleDetailsPageComponent: FC = ({ +const RuleDetailsPageComponent: FC = ({ filters, query, setAbsoluteRangeDatePicker, @@ -417,7 +398,8 @@ const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, }; -export const RuleDetailsPage = connect( - makeMapStateToProps, - mapDispatchToProps -)(memo(RuleDetailsPageComponent)); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const RuleDetailsPage = connector(memo(RuleDetailsPageComponent)); diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx index 9ee103f88793d..1dce26b7c5d3a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -104,9 +104,7 @@ export const HomePage: React.FC = () => ( /> ( - - )} + render={({ match }) => } /> ( +export const HostDetailsTabs = React.memo( ({ pageFilters, deleteQuery, @@ -105,5 +105,3 @@ const HostDetailsTabs = React.memo( ); HostDetailsTabs.displayName = 'HostDetailsTabs'; - -export { HostDetailsTabs }; 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 a02e2b4aed22e..8af4731e4dda4 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 @@ -6,9 +6,8 @@ import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import React, { useContext, useEffect, useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; -import { compose } from 'redux'; import { FiltersGlobal } from '../../../components/filters_global'; import { HeaderPage } from '../../../components/header_page'; @@ -39,14 +38,14 @@ import { esQuery, Filter } from '../../../../../../../../src/plugins/data/public import { HostsEmptyPage } from '../hosts_empty_page'; import { HostDetailsTabs } from './details_tabs'; import { navTabsHostDetails } from './nav_tabs'; -import { HostDetailsComponentProps, HostDetailsProps } from './types'; +import { HostDetailsProps } from './types'; import { type } from './utils'; import { getHostDetailsPageFilters } from './helpers'; const HostOverviewManage = manageQuery(HostOverview); const KpiHostDetailsManage = manageQuery(KpiHostsComponent); -const HostDetailsComponent = React.memo( +const HostDetailsComponent = React.memo( ({ filters, from, @@ -61,7 +60,7 @@ const HostDetailsComponent = React.memo( hostDetailsPagePath, }) => { useEffect(() => { - setHostDetailsTablesActivePageToZero(null); + setHostDetailsTablesActivePageToZero(); }, [setHostDetailsTablesActivePageToZero, detailName]); const capabilities = useContext(MlCapabilitiesContext); const kibana = useKibana(); @@ -218,9 +217,13 @@ export const makeMapStateToProps = () => { }); }; -export const HostDetails = compose>( - connect(makeMapStateToProps, { - setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, - setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, - }) -)(HostDetailsComponent); +const mapDispatchToProps = { + setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, + setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const HostDetails = connector(HostDetailsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx index 71dc3aac756ba..99cf767c65e08 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx @@ -9,14 +9,12 @@ import { cloneDeep } from 'lodash/fp'; import React from 'react'; import { Router } from 'react-router-dom'; import { MockedProvider } from 'react-apollo/test-utils'; -import { ActionCreator } from 'typescript-fsa'; import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; import '../../mock/match_media'; import { mocksSource } from '../../containers/source/mock'; import { wait } from '../../lib/helpers'; import { apolloClientObservable, TestProviders, mockGlobalState } from '../../mock'; -import { InputsModelId } from '../../store/inputs/constants'; import { SiemNavigation } from '../../components/navigation'; import { inputsActions } from '../../store/inputs'; import { State, createStore } from '../../store'; @@ -77,13 +75,6 @@ describe('Hosts - rendering', () => { to, setQuery: jest.fn(), isInitializing: false, - setAbsoluteRangeDatePicker: (jest.fn() as unknown) as ActionCreator<{ - from: number; - id: InputsModelId; - to: number; - }>, - query: { query: '', language: 'kuery' }, - filters: [], hostsPagePath: '', }; 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 06dffcdb220a9..a7aa9920b7d08 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -6,9 +6,8 @@ import { EuiSpacer } from '@elastic/eui'; import React, { useCallback } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; -import { compose } from 'redux'; import { useParams } from 'react-router-dom'; import { FiltersGlobal } from '../../components/filters_global'; @@ -21,7 +20,6 @@ import { KpiHostsComponent } from '../../components/page/hosts'; import { manageQuery } from '../../components/page/manage_query'; import { SiemSearchBar } from '../../components/search_bar'; import { WrapperPage } from '../../components/wrapper_page'; -import { GlobalTimeArgs } from '../../containers/global_time'; import { KpiHostsQuery } from '../../containers/kpi_hosts'; import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; import { LastEventIndexKey } from '../../graphql/types'; @@ -36,13 +34,13 @@ import { HostsEmptyPage } from './hosts_empty_page'; import { HostsTabs } from './hosts_tabs'; import { navTabsHosts } from './nav_tabs'; import * as i18n from './translations'; -import { HostsComponentProps, HostsComponentReduxProps } from './types'; +import { HostsComponentProps } from './types'; import { filterHostData } from './navigation'; import { HostsTableType } from '../../store/hosts/model'; const KpiHostsComponentManage = manageQuery(KpiHostsComponent); -export const HostsComponent = React.memo( +export const HostsComponent = React.memo( ({ deleteQuery, isInitializing, @@ -161,7 +159,7 @@ HostsComponent.displayName = 'HostsComponent'; const makeMapStateToProps = () => { const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); - const mapStateToProps = (state: State): HostsComponentReduxProps => ({ + const mapStateToProps = (state: State) => ({ query: getGlobalQuerySelector(state), filters: getGlobalFiltersQuerySelector(state), }); @@ -169,13 +167,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -interface HostsProps extends GlobalTimeArgs { - hostsPagePath: string; -} +const mapDispatchToProps = { + setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const Hosts = compose>( - connect(makeMapStateToProps, { - setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, - }) -)(HostsComponent); +export const Hosts = connector(HostsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx index fff5c5218c003..699b1441905c3 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx @@ -56,10 +56,14 @@ export const HostsContainer = React.memo(({ url }) => ( ( + render={({ + match: { + params: { detailName }, + }, + }) => ( ; - hostsPagePath: string; -} - -export type HostsTabsProps = HostsComponentDispatchProps & - HostsQueryProps & { - filterQuery: string; - type: hostsModel.HostsType; - indexPattern: IIndexPattern; - }; +}; export type HostsQueryProps = GlobalTimeArgs; -export type HostsComponentProps = HostsComponentReduxProps & - HostsComponentDispatchProps & - HostsQueryProps; +export type HostsComponentProps = HostsQueryProps & { hostsPagePath: string }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx index 9a9d1cf085eb9..02132d790796c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx @@ -92,7 +92,7 @@ const getMockProps = (ip: string) => ({ from: number; to: number; }>, - setIpDetailsTablesActivePageToZero: (jest.fn() as unknown) as ActionCreator, + setIpDetailsTablesActivePageToZero: (jest.fn() as unknown) as ActionCreator, }); describe('Ip Details', () => { 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 2e8044d2c2fe8..e796eaca0cd28 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 @@ -6,7 +6,7 @@ import { EuiHorizontalRule, EuiSpacer, EuiFlexItem } from '@elastic/eui'; import React, { useCallback, useEffect } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { FiltersGlobal } from '../../../components/filters_global'; @@ -46,7 +46,7 @@ export { getBreadcrumbs } from './utils'; const IpOverviewManage = manageQuery(IpOverview); -export const IPDetailsComponent = ({ +export const IPDetailsComponent: React.FC = ({ detailName, filters, flowTarget, @@ -57,7 +57,7 @@ export const IPDetailsComponent = ({ setIpDetailsTablesActivePageToZero, setQuery, to, -}: IPDetailsComponentProps) => { +}) => { const type = networkModel.NetworkType.details; const narrowDateRange = useCallback( (score, interval) => { @@ -73,7 +73,7 @@ export const IPDetailsComponent = ({ const kibana = useKibana(); useEffect(() => { - setIpDetailsTablesActivePageToZero(null); + setIpDetailsTablesActivePageToZero(); }, [detailName, setIpDetailsTablesActivePageToZero]); return ( @@ -279,13 +279,20 @@ IPDetailsComponent.displayName = 'IPDetailsComponent'; const makeMapStateToProps = () => { const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); + return (state: State) => ({ query: getGlobalQuerySelector(state), filters: getGlobalFiltersQuerySelector(state), }); }; -export const IPDetails = connect(makeMapStateToProps, { +const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, setIpDetailsTablesActivePageToZero: dispatchIpDetailsTablesActivePageToZero, -})(React.memo(IPDetailsComponent)); +}; + +export const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const IPDetails = connector(React.memo(IPDetailsComponent)); diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/types.ts b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/types.ts index b53d58e6664af..ef989fb64eabe 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/types.ts @@ -4,38 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ActionCreator } from 'typescript-fsa'; -import { IIndexPattern, Query, Filter } from 'src/plugins/data/public'; +import { IIndexPattern } from 'src/plugins/data/public'; import { NetworkType } from '../../../store/network/model'; import { ESTermQuery } from '../../../../common/typed_json'; import { InspectQuery, Refetch } from '../../../store/inputs/model'; import { FlowTarget, FlowTargetSourceDest } from '../../../graphql/types'; -import { InputsModelId } from '../../../store/inputs/constants'; import { GlobalTimeArgs } from '../../../containers/global_time'; export const type = NetworkType.details; -type SetAbsoluteRangeDatePicker = ActionCreator<{ - id: InputsModelId; - from: number; - to: number; -}>; - -interface IPDetailsComponentReduxProps { - filters: Filter[]; +export type IPDetailsComponentProps = GlobalTimeArgs & { + detailName: string; flowTarget: FlowTarget; - query: Query; -} - -interface IPDetailsComponentDispatchProps { - setAbsoluteRangeDatePicker: SetAbsoluteRangeDatePicker; - setIpDetailsTablesActivePageToZero: ActionCreator; -} - -export type IPDetailsComponentProps = IPDetailsComponentReduxProps & - IPDetailsComponentDispatchProps & - GlobalTimeArgs & { detailName: string }; +}; export interface OwnProps { type: NetworkType; 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 0f9eaaef48aa7..9b1ee76e1d376 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -6,7 +6,7 @@ import { EuiSpacer } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { useParams } from 'react-router-dom'; import { StickyContainer } from 'react-sticky'; @@ -38,7 +38,7 @@ import { NetworkRouteType } from './navigation/types'; const KpiNetworkComponentManage = manageQuery(KpiNetworkComponent); const sourceId = 'default'; -const NetworkComponent = React.memo( +const NetworkComponent = React.memo( ({ filters, query, @@ -183,6 +183,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const Network = connect(makeMapStateToProps, { +const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, -})(NetworkComponent); +}; + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const Network = connector(NetworkComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/network/types.ts b/x-pack/legacy/plugins/siem/public/pages/network/types.ts index 8a9914133c9af..01d3fb6b48c63 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/types.ts @@ -6,9 +6,8 @@ import { RouteComponentProps } from 'react-router-dom'; import { ActionCreator } from 'typescript-fsa'; -import { GlobalTimeArgs } from '../../containers/global_time'; import { InputsModelId } from '../../store/inputs/constants'; -import { Query, Filter } from '../../../../../../../src/plugins/data/public'; +import { GlobalTimeArgs } from '../../containers/global_time'; export type SetAbsoluteRangeDatePicker = ActionCreator<{ id: InputsModelId; @@ -16,15 +15,8 @@ export type SetAbsoluteRangeDatePicker = ActionCreator<{ to: number; }>; -interface NetworkComponentReduxProps { - filters: Filter[]; - query: Query; - setAbsoluteRangeDatePicker: SetAbsoluteRangeDatePicker; -} - -export type NetworkComponentProps = NetworkComponentReduxProps & - GlobalTimeArgs & - Partial> & { +export type NetworkComponentProps = Partial> & + GlobalTimeArgs & { networkPagePath: string; hasMlUserPermissions: boolean; capabilitiesFetched: boolean; diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx index 8505b91fe1ff5..2db49e60193fc 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx @@ -6,9 +6,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React from 'react'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; -import { compose } from 'redux'; import { Query, Filter } from 'src/plugins/data/public'; import styled from 'styled-components'; @@ -20,7 +19,6 @@ import { GlobalTime } from '../../containers/global_time'; import { WithSource, indicesExistOrDataTemporarilyUnavailable } from '../../containers/source'; import { EventsByDataset } from './events_by_dataset'; import { EventCounts } from './event_counts'; -import { SetAbsoluteRangeDatePicker } from '../network/types'; import { OverviewEmpty } from './overview_empty'; import { StatefulSidebar } from './sidebar'; import { SignalsByCategory } from './signals_by_category'; @@ -35,13 +33,7 @@ const SidebarFlexItem = styled(EuiFlexItem)` margin-right: 24px; `; -interface OverviewComponentReduxProps { - query?: Query; - filters?: Filter[]; - setAbsoluteRangeDatePicker?: SetAbsoluteRangeDatePicker; -} - -const OverviewComponent: React.FC = ({ +const OverviewComponent: React.FC = ({ filters = NO_FILTERS, query = DEFAULT_QUERY, setAbsoluteRangeDatePicker, @@ -133,7 +125,7 @@ const makeMapStateToProps = () => { const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); - const mapStateToProps = (state: State): OverviewComponentReduxProps => ({ + const mapStateToProps = (state: State) => ({ query: getGlobalQuerySelector(state), filters: getGlobalFiltersQuerySelector(state), }); @@ -143,6 +135,8 @@ const makeMapStateToProps = () => { const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker }; -export const StatefulOverview = compose>( - connect(makeMapStateToProps, mapDispatchToProps) -)(React.memo(OverviewComponent)); +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +export const StatefulOverview = connector(React.memo(OverviewComponent)); diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/translations.ts b/x-pack/legacy/plugins/siem/public/pages/overview/translations.ts index e20083bf51772..5ccd25984bc40 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/translations.ts +++ b/x-pack/legacy/plugins/siem/public/pages/overview/translations.ts @@ -7,11 +7,11 @@ import { i18n } from '@kbn/i18n'; export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.overview.alertsGraphTitle', { - defaultMessage: 'External alerts count', + defaultMessage: 'External alert count', }); export const EVENTS = i18n.translate('xpack.siem.overview.eventsTitle', { - defaultMessage: 'Events count', + defaultMessage: 'Event count', }); export const NEWS_FEED_TITLE = i18n.translate('xpack.siem.overview.newsFeedSidebarTitle', { @@ -31,7 +31,7 @@ export const RECENT_TIMELINES = i18n.translate('xpack.siem.overview.recentTimeli }); export const SIGNAL_COUNT = i18n.translate('xpack.siem.overview.signalCountTitle', { - defaultMessage: 'Signals count', + defaultMessage: 'Signal count', }); export const VIEW_ALERTS = i18n.translate('xpack.siem.overview.viewAlertsButtonLabel', { diff --git a/x-pack/legacy/plugins/siem/public/store/inputs/actions.ts b/x-pack/legacy/plugins/siem/public/store/inputs/actions.ts index 8255ba41d2bb1..f9da0e558c655 100644 --- a/x-pack/legacy/plugins/siem/public/store/inputs/actions.ts +++ b/x-pack/legacy/plugins/siem/public/store/inputs/actions.ts @@ -7,7 +7,7 @@ import actionCreatorFactory from 'typescript-fsa'; import { SavedQuery } from 'src/legacy/core_plugins/data/public'; -import { InspectQuery, Refetch } from './model'; +import { InspectQuery, Refetch, RefetchKql } from './model'; import { InputsModelId } from './constants'; import { Filter } from '../../../../../../../src/plugins/data/public'; @@ -42,7 +42,7 @@ export const setQuery = actionCreator<{ inputId: InputsModelId; id: string; loading: boolean; - refetch: Refetch; + refetch: Refetch | RefetchKql; inspect: InspectQuery | null; }>('SET_QUERY'); diff --git a/x-pack/legacy/plugins/siem/public/store/inputs/helpers.ts b/x-pack/legacy/plugins/siem/public/store/inputs/helpers.ts index 194d2e8cd35c3..4a3c17a6234e7 100644 --- a/x-pack/legacy/plugins/siem/public/store/inputs/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/store/inputs/helpers.ts @@ -6,7 +6,7 @@ import { get } from 'lodash/fp'; -import { InputsModel, TimeRange, Refetch, InspectQuery } from './model'; +import { InputsModel, TimeRange, Refetch, RefetchKql, InspectQuery } from './model'; import { InputsModelId } from './constants'; export const updateInputTimerange = ( @@ -59,7 +59,7 @@ export interface UpdateQueryParams { inputId: InputsModelId; inspect: InspectQuery | null; loading: boolean; - refetch: Refetch; + refetch: Refetch | RefetchKql; state: InputsModel; } 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 64a325b6e1ca4..273eaf7c0ee7f 100644 --- a/x-pack/legacy/plugins/siem/public/store/network/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/network/selectors.ts @@ -16,6 +16,9 @@ import { NetworkPageModel, NetworkTableType, NetworkType, + TopCountriesQuery, + TlsQuery, + HttpQuery, } from './model'; const selectNetworkPage = (state: State): NetworkPageModel => state.network.page; @@ -41,7 +44,7 @@ const selectTopNFlowByType = ( export const topNFlowSelector = () => createSelector(selectTopNFlowByType, topNFlowQueries => topNFlowQueries); -const selectTlsByType = (state: State, networkType: NetworkType) => { +const selectTlsByType = (state: State, networkType: NetworkType): TlsQuery => { const tlsType = networkType === NetworkType.page ? NetworkTableType.tls : IpDetailsTableType.tls; return ( get([networkType, 'queries', tlsType], state.network) || @@ -55,7 +58,7 @@ const selectTopCountriesByType = ( state: State, networkType: NetworkType, flowTarget: FlowTargetSourceDest -) => { +): TopCountriesQuery => { const ft = flowTarget === FlowTargetSourceDest.source ? 'topCountriesSource' : 'topCountriesDestination'; const nFlowType = @@ -70,7 +73,7 @@ const selectTopCountriesByType = ( export const topCountriesSelector = () => createSelector(selectTopCountriesByType, topCountriesQueries => topCountriesQueries); -const selectHttpByType = (state: State, networkType: NetworkType) => { +const selectHttpByType = (state: State, networkType: NetworkType): HttpQuery => { const httpType = networkType === NetworkType.page ? NetworkTableType.http : IpDetailsTableType.http; return ( diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index b2b938625180e..dd3b8d3c99e0c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -54,6 +54,7 @@ export const setSignalsStatusRouteDef = ( }, query: queryObject, }, + ignoreUnavailable: true, }); } catch (exc) { // error while getting or updating signal with id: id in signal index .siem-signals diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts index a3602ffbded41..adb6e5f32921a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -38,6 +38,7 @@ export const querySignalsRouteDef = ( return clusterClient.callAsCurrentUser('search', { index, body: { query, aggs, _source, track_total_hits, size }, + ignoreUnavailable: true, }); } catch (exc) { // error while getting or updating signal with id: id in signal index .siem-signals diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_logistics.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_logistics.tsx index 111b46d596e56..ef92edcfaeb35 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_logistics.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_logistics.tsx @@ -94,7 +94,6 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ defaultMessage="A unique identifier for this policy." /> } - idAria="nameDescription" fullWidth > = ({ defaultMessage="Name" /> } - describedByIds={['nameDescription']} isInvalid={touched.name && Boolean(errors.name)} error={errors.name} fullWidth @@ -158,7 +156,6 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ defaultMessage="The repository where you want to store the snapshots." /> } - idAria="policyRepositoryDescription" fullWidth > = ({ defaultMessage="Repository" /> } - describedByIds={['policyRepositoryDescription']} isInvalid={touched.repository && Boolean(errors.repository)} error={errors.repository} fullWidth @@ -307,7 +303,6 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ defaultMessage="The name for the snapshots. A unique identifier is automatically added to each name." /> } - idAria="policySnapshotNameDescription" fullWidth > = ({ defaultMessage="Snapshot name" /> } - describedByIds={['policySnapshotNameDescription']} isInvalid={touched.snapshotName && Boolean(errors.snapshotName)} error={errors.snapshotName} helpText={ @@ -389,7 +383,6 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ defaultMessage="The frequency at which to take the snapshots." /> } - idAria="policyScheduleDescription" fullWidth > {isAdvancedCronVisible ? ( @@ -401,7 +394,6 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ defaultMessage="Schedule" /> } - describedByIds={['policyScheduleDescription']} isInvalid={touched.schedule && Boolean(errors.schedule)} error={errors.schedule} helpText={ diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_retention.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_retention.tsx index df7e2c8807d9f..ec01885e76ff1 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_retention.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_retention.tsx @@ -73,7 +73,6 @@ export const PolicyStepRetention: React.FunctionComponent = ({ defaultMessage="The time to wait before deleting snapshots." /> } - idAria="expirationDescription" fullWidth > = ({ defaultMessage="Delete after" /> } - describedByIds={['expirationDescription']} isInvalid={touched.expireAfterValue && Boolean(errors.expireAfterValue)} error={errors.expireAfterValue} fullWidth @@ -140,7 +138,6 @@ export const PolicyStepRetention: React.FunctionComponent = ({ defaultMessage="The minimum and maximum number of snapshots to store in your cluster." /> } - idAria="countDescription" fullWidth > @@ -152,7 +149,6 @@ export const PolicyStepRetention: React.FunctionComponent = ({ defaultMessage="Mininum count" /> } - describedByIds={['countDescription']} isInvalid={touched.minCount && Boolean(errors.minCount)} error={errors.minCount} fullWidth @@ -180,7 +176,6 @@ export const PolicyStepRetention: React.FunctionComponent = ({ defaultMessage="Maximum count" /> } - describedByIds={['countDescription']} isInvalid={touched.maxCount && Boolean(errors.maxCount)} error={errors.maxCount} fullWidth diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_settings.tsx index 0e3b6e030d1c6..552dbff8e7441 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/policy_form/steps/step_settings.tsx @@ -126,10 +126,9 @@ export const PolicyStepSettings: React.FunctionComponent = ({ defaultMessage="Indices to back up." /> } - idAria="indicesDescription" fullWidth > - + {isManagedPolicy ? ( = ({ defaultMessage="Ignores indices that are unavailable when taking the snapshot. Otherwise, the entire snapshot will fail." /> } - idAria="policyIgnoreUnavailableDescription" fullWidth > - + = ({ defaultMessage="Allows snapshots of indices with primary shards that are unavailable. Otherwise, the entire snapshot will fail." /> } - idAria="policyPartialDescription" fullWidth > - + = ({ defaultMessage="Stores the global state of the cluster as part of the snapshot." /> } - idAria="policyIncludeGlobalStateDescription" fullWidth > - + = ({ defaultMessage="A unique name for the repository." /> } - idAria="repositoryNameDescription" fullWidth > = ({ defaultMessage="Name" /> } - describedByIds={['repositoryNameDescription']} isInvalid={Boolean(hasValidationErrors && validation.errors.name)} error={validation.errors.name} fullWidth @@ -303,10 +301,9 @@ export const RepositoryFormStepOne: React.FunctionComponent = ({ /> } - idAria="sourceOnlyDescription" fullWidth > - + = ({ defaultMessage="The name of the Azure client." /> } - idAria="azureRepositoryClientDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryClientDescription']} isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > @@ -123,7 +121,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="The name of the Azure container to use for snapshots." /> } - idAria="azureRepositoryContainerDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryContainerDescription']} isInvalid={Boolean(hasErrors && settingErrors.container)} error={settingErrors.container} > @@ -169,7 +165,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="The container path to the repository data." /> } - idAria="azureRepositoryBasePathDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryBasePathDescription']} isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > @@ -215,13 +209,11 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="Compresses the index mapping and setting files for snapshots. Data files are not compressed." /> } - idAria="azureRepositoryCompressDescription" fullWidth > @@ -261,7 +253,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="Breaks files into smaller units when taking snapshots." /> } - idAria="azureRepositoryChunkSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryChunkSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.chunkSize)} error={settingErrors.chunkSize} helpText={textService.getSizeNotationHelpText()} @@ -308,7 +298,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="The rate for creating snapshots for each node." /> } - idAria="azureRepositoryMaxSnapshotBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryMaxSnapshotBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxSnapshotBytesPerSec)} error={settingErrors.maxSnapshotBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -355,7 +343,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="The snapshot restore rate for each node." /> } - idAria="azureRepositoryMaxRestoreBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryMaxRestoreBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxRestoreBytesPerSec)} error={settingErrors.maxRestoreBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -402,7 +388,6 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="The primary or secondary location. If secondary, read-only is true." /> } - idAria="azureRepositoryLocationModeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['azureRepositoryLocationModeDescription']} isInvalid={Boolean(hasErrors && settingErrors.locationMode)} error={settingErrors.locationMode} > @@ -450,13 +434,11 @@ export const AzureSettings: React.FunctionComponent = ({ defaultMessage="Only one cluster should have write access to this repository. All other clusters should be read-only." /> } - idAria="azureRepositoryReadonlyDescription" fullWidth > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/fs_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/fs_settings.tsx index 2e2238ac93e3c..711db1ee300cb 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/fs_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/fs_settings.tsx @@ -73,7 +73,6 @@ export const FSSettings: React.FunctionComponent = ({ /> } - idAria="fsRepositoryLocationDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['fsRepositoryLocationDescription']} isInvalid={Boolean(hasErrors && settingErrors.location)} error={settingErrors.location} > @@ -119,13 +117,11 @@ export const FSSettings: React.FunctionComponent = ({ defaultMessage="Compresses the index mapping and setting files for snapshots. Data files are not compressed." /> } - idAria="fsRepositoryCompressDescription" fullWidth > @@ -165,7 +161,6 @@ export const FSSettings: React.FunctionComponent = ({ defaultMessage="Breaks files into smaller units when taking snapshots." /> } - idAria="fsRepositoryChunkSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['fsRepositoryChunkSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.chunkSize)} error={settingErrors.chunkSize} helpText={textService.getSizeNotationHelpText()} @@ -212,7 +206,6 @@ export const FSSettings: React.FunctionComponent = ({ defaultMessage="The rate for creating snapshots for each node." /> } - idAria="fsRepositoryMaxSnapshotBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['fsRepositoryMaxSnapshotBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxSnapshotBytesPerSec)} error={settingErrors.maxSnapshotBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -259,7 +251,6 @@ export const FSSettings: React.FunctionComponent = ({ defaultMessage="The snapshot restore rate for each node." /> } - idAria="fsRepositoryMaxRestoreBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['fsRepositoryMaxRestoreBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxRestoreBytesPerSec)} error={settingErrors.maxRestoreBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -306,13 +296,11 @@ export const FSSettings: React.FunctionComponent = ({ defaultMessage="Only one cluster should have write access to this repository. All other clusters should be read-only." /> } - idAria="fsRepositoryReadonlyDescription" fullWidth > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/gcs_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/gcs_settings.tsx index d15e0043b8c81..5a34d3aac6f6b 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/gcs_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/gcs_settings.tsx @@ -64,7 +64,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="The name of the Google Cloud Storage client." /> } - idAria="gcsRepositoryClientDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryClientDescription']} isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > @@ -110,7 +108,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="The name of the Google Cloud Storage bucket to use for snapshots." /> } - idAria="gcsRepositoryBucketDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryBucketDescription']} isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > @@ -156,7 +152,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="The bucket path to the repository data." /> } - idAria="gcsRepositoryBasePathDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryBasePathDescription']} isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > @@ -202,13 +196,11 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="Compresses the index mapping and setting files for snapshots. Data files are not compressed." /> } - idAria="gcsRepositoryCompressDescription" fullWidth > @@ -248,7 +240,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="Breaks files into smaller units when taking snapshots." /> } - idAria="gcsRepositoryChunkSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryChunkSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.chunkSize)} error={settingErrors.chunkSize} helpText={textService.getSizeNotationHelpText()} @@ -295,7 +285,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="The rate for creating snapshots for each node." /> } - idAria="gcsRepositoryMaxSnapshotBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryMaxSnapshotBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxSnapshotBytesPerSec)} error={settingErrors.maxSnapshotBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -342,7 +330,6 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="The snapshot restore rate for each node." /> } - idAria="gcsRepositoryMaxRestoreBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['gcsRepositoryMaxRestoreBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxRestoreBytesPerSec)} error={settingErrors.maxRestoreBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -389,13 +375,11 @@ export const GCSSettings: React.FunctionComponent = ({ defaultMessage="Only one cluster should have write access to this repository. All other clusters should be read-only." /> } - idAria="gcsRepositoryReadonlyDescription" fullWidth > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/hdfs_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/hdfs_settings.tsx index ae42b810bf059..4ef662d645bea 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/hdfs_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/hdfs_settings.tsx @@ -79,7 +79,6 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="The URI address for HDFS." /> } - idAria="hdfsRepositoryUriDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryUriDescription']} isInvalid={Boolean(hasErrors && settingErrors.uri)} error={settingErrors.uri} > @@ -108,7 +106,7 @@ export const HDFSSettings: React.FunctionComponent = ({ uri: e.target.value ? `hdfs://${e.target.value}` : '', }); }} - aria-describedby="hdfsRepositoryUriDescription hdfsRepositoryUriProtocolDescription" + aria-describedby="hdfsRepositoryUriProtocolDescription" data-test-subj="uriInput" /> @@ -132,7 +130,6 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="The file path where data is stored." /> } - idAria="hdfsRepositoryPathDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryPathDescription']} isInvalid={Boolean(hasErrors && settingErrors.path)} error={settingErrors.path} > @@ -178,13 +174,11 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="Loads the default Hadoop configuration." /> } - idAria="hdfsRepositoryLoadDefaultsDescription" fullWidth > @@ -224,13 +218,11 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="Compresses the index mapping and setting files for snapshots. Data files are not compressed." /> } - idAria="hdfsRepositoryCompressDescription" fullWidth > @@ -270,7 +262,6 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="Breaks files into smaller units when taking snapshots." /> } - idAria="hdfsRepositoryChunkSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryChunkSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.chunkSize)} error={settingErrors.chunkSize} helpText={textService.getSizeNotationHelpText()} @@ -317,7 +307,6 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="The Kerberos principal to use when connecting to a secured HDFS cluster." /> } - idAria="hdfsRepositorySecurityPrincipalDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositorySecurityPrincipalDescription']} isInvalid={Boolean(hasErrors && settingErrors.securityPrincipal)} error={settingErrors.securityPrincipal} > @@ -365,7 +353,6 @@ export const HDFSSettings: React.FunctionComponent = ({ /> } - idAria="hdfsRepositoryConfigurationDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryConfigurationDescription']} isInvalid={isConfInvalid} error={ = ({ defaultMessage="The rate for creating snapshots for each node." /> } - idAria="hdfsRepositoryMaxSnapshotBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryMaxSnapshotBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxSnapshotBytesPerSec)} error={settingErrors.maxSnapshotBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -510,7 +494,6 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="The snapshot restore rate for each node." /> } - idAria="hdfsRepositoryMaxRestoreBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['hdfsRepositoryMaxRestoreBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxRestoreBytesPerSec)} error={settingErrors.maxRestoreBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -557,13 +539,11 @@ export const HDFSSettings: React.FunctionComponent = ({ defaultMessage="Only one cluster should have write access to this repository. All other clusters should be read-only." /> } - idAria="hdfsRepositoryReadonlyDescription" fullWidth > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/readonly_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/readonly_settings.tsx index 5241a55455395..a0cc076465990 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/readonly_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/readonly_settings.tsx @@ -116,7 +116,6 @@ export const ReadonlySettings: React.FunctionComponent = ({ /> } - idAria="readonlyRepositoryUrlDescription" fullWidth >
@@ -130,7 +129,6 @@ export const ReadonlySettings: React.FunctionComponent = ({ /> } fullWidth - describedByIds={['readonlyRepositoryUrlDescription']} > = ({ /> } fullWidth - describedByIds={['readonlyRepositoryUrlDescription readonlyRepositoryUrlHelp']} + describedByIds={['readonlyRepositoryUrlHelp']} isInvalid={Boolean(hasErrors && settingErrors.url)} error={settingErrors.url} > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/s3_settings.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/s3_settings.tsx index a897368ae7ca3..1a9902b42a931 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/s3_settings.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/repository_form/type_settings/s3_settings.tsx @@ -93,7 +93,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The name of the AWS S3 client." /> } - idAria="s3RepositoryClientDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryClientDescription']} isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > @@ -139,7 +137,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The name of the AWS S3 bucket to use for snapshots." /> } - idAria="s3RepositoryBucketDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryBucketDescription']} isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > @@ -185,7 +181,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The bucket path to the repository data." /> } - idAria="s3RepositoryBasePathDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryBasePathDescription']} isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > @@ -231,13 +225,11 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="Compresses the index mapping and setting files for snapshots. Data files are not compressed." /> } - idAria="s3RepositoryCompressDescription" fullWidth > @@ -277,7 +269,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="Breaks files into smaller units when taking snapshots." /> } - idAria="s3RepositoryChunkSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryChunkSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.chunkSize)} error={settingErrors.chunkSize} helpText={textService.getSizeNotationHelpText()} @@ -324,13 +314,11 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="Encrypts files on the server using AES256 algorithm." /> } - idAria="s3RepositoryServerSideEncryptionDescription" fullWidth > @@ -371,7 +359,6 @@ export const S3Settings: React.FunctionComponent = ({ to split the chunk into several parts and upload each in its own request." /> } - idAria="s3RepositoryBufferSizeDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryBufferSizeDescription']} isInvalid={Boolean(hasErrors && settingErrors.bufferSize)} error={settingErrors.bufferSize} helpText={textService.getSizeNotationHelpText()} @@ -418,7 +404,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The canned ACL to add to new S3 buckets and objects." /> } - idAria="s3RepositoryCannedAclDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryCannedAclDescription']} isInvalid={Boolean(hasErrors && settingErrors.cannedAcl)} error={settingErrors.cannedAcl} > @@ -465,7 +449,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The storage class for new objects in the S3 repository." /> } - idAria="s3RepositoryStorageClassDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryStorageClassDescription']} isInvalid={Boolean(hasErrors && settingErrors.storageClass)} error={settingErrors.storageClass} > @@ -512,7 +494,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The rate for creating snapshots for each node." /> } - idAria="s3RepositoryMaxSnapshotBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryMaxSnapshotBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxSnapshotBytesPerSec)} error={settingErrors.maxSnapshotBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -559,7 +539,6 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="The snapshot restore rate for each node." /> } - idAria="s3RepositoryMaxRestoreBytesDescription" fullWidth > = ({ /> } fullWidth - describedByIds={['s3RepositoryMaxRestoreBytesDescription']} isInvalid={Boolean(hasErrors && settingErrors.maxRestoreBytesPerSec)} error={settingErrors.maxRestoreBytesPerSec} helpText={textService.getSizeNotationHelpText()} @@ -606,13 +584,11 @@ export const S3Settings: React.FunctionComponent = ({ defaultMessage="Only one cluster should have write access to this repository. All other clusters should be read-only." /> } - idAria="s3RepositoryReadonlyDescription" fullWidth > diff --git a/x-pack/legacy/plugins/snapshot_restore/public/app/components/restore_snapshot_form/steps/step_logistics.tsx b/x-pack/legacy/plugins/snapshot_restore/public/app/components/restore_snapshot_form/steps/step_logistics.tsx index f5a3180adbd6e..bd8a0650c087f 100644 --- a/x-pack/legacy/plugins/snapshot_restore/public/app/components/restore_snapshot_form/steps/step_logistics.tsx +++ b/x-pack/legacy/plugins/snapshot_restore/public/app/components/restore_snapshot_form/steps/step_logistics.tsx @@ -141,14 +141,9 @@ export const RestoreSnapshotStepLogistics: React.FunctionComponent = if they are closed and have the same number of shards as the snapshot index." /> } - idAria="stepLogisticsIndicesDescription" fullWidth > - + = defaultMessage="Renames indices on restore." /> } - idAria="stepLogisticsRenameIndicesDescription" fullWidth > - + = defaultMessage="Allows restore of indices that don’t have snapshots of all shards." /> } - idAria="stepLogisticsPartialDescription" fullWidth > - + = templates with the same name. Also restores persistent settings." /> } - idAria="stepLogisticsIncludeGlobalStateDescription" fullWidth > = ( }} /> } - idAria="stepSettingsIndexSettingsDescription" fullWidth > - + = ( /> } fullWidth - describedByIds={['stepSettingsIndexSettingsDescription']} isInvalid={Boolean(errors.indexSettings)} error={errors.indexSettings} helpText={ @@ -235,14 +229,9 @@ export const RestoreSnapshotStepSettings: React.FunctionComponent = ( }} /> } - idAria="stepSettingsIgnoreIndexSettingsDescription" fullWidth > - + - @@ -143,7 +143,6 @@ export class CheckupTab extends UpgradeAssistantTabComponent void; currentFilter: LevelFilterOption; onFilterChange: (filter: LevelFilterOption) => void; - search: string; onSearchChange: (filter: string) => void; availableGroupByOptions: GroupByOption[]; currentGroupBy: GroupByOption; onGroupByChange: (groupBy: GroupByOption) => void; } -export const CheckupControlsUI: FunctionComponent = ({ +export const CheckupControls: FunctionComponent = ({ allDeprecations, loadingState, loadData, currentFilter, onFilterChange, - search, onSearchChange, availableGroupByOptions, currentGroupBy, onGroupByChange, - intl, -}) => ( - - - onSearchChange(e.target.value)} - /> - - - {/* These two components provide their own EuiFlexItem wrappers */} - - +}) => { + const [searchTermError, setSearchTermError] = useState(null); + const filterInvalid = Boolean(searchTermError); + return ( + + + + + { + const string = e.target.value; + const errorMessage = validateRegExpString(string); + if (errorMessage) { + // Emit an empty search term to listeners if search term is invalid. + onSearchChange(''); + setSearchTermError(errorMessage); + } else { + onSearchChange(e.target.value); + if (searchTermError) { + setSearchTermError(null); + } + } + }} + /> + - - - - - - -); + {/* These two components provide their own EuiFlexItem wrappers */} + + -export const CheckupControls = injectI18n(CheckupControlsUI); + + + + + + + + {filterInvalid && ( + + + + )} + + ); +}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.test.ts b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.test.ts new file mode 100644 index 0000000000000..067f11798e151 --- /dev/null +++ b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.test.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { validateRegExpString } from './utils'; + +describe('validRegExpString', () => { + it('correctly returns false for invalid strings', () => { + expect(validateRegExpString('?asd')).toContain(`Invalid regular expression`); + expect(validateRegExpString('*asd')).toContain(`Invalid regular expression`); + expect(validateRegExpString('(')).toContain(`Invalid regular expression`); + }); + + it('correctly returns true for valid strings', () => { + expect(validateRegExpString('asd')).toBe(''); + expect(validateRegExpString('.*asd')).toBe(''); + expect(validateRegExpString('')).toBe(''); + }); +}); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.ts b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.ts new file mode 100644 index 0000000000000..6a1f32fe8f20b --- /dev/null +++ b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.ts @@ -0,0 +1,19 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { tryCatch, fold } from 'fp-ts/lib/Either'; + +export const validateRegExpString = (s: string) => + pipe( + tryCatch( + () => new RegExp(s), + e => (e as Error).message + ), + fold( + (errorMessage: string) => errorMessage, + () => '' + ) + ); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx index 744c82a9983c8..b4989282f854c 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx @@ -31,7 +31,7 @@ export interface PingHistogramComponentProps { */ height?: string; - data?: HistogramResult; + data: HistogramResult | null; loading?: boolean; } diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap index 3655db5aaff1e..fa536ce53533a 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap @@ -156,10 +156,7 @@ exports[`MonitorList component renders the monitor list 1`] = ` class="euiTable euiTable--responsive" > diff --git a/x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx b/x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx index 4516289bd51d6..8e406f621f648 100644 --- a/x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx +++ b/x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx @@ -28,6 +28,7 @@ export const UptimeRefreshContextProvider: React.FC = ({ children }) => { const refreshApp = () => { const refreshTime = Date.now(); setLastRefresh(refreshTime); + // @ts-ignore store.dispatch(triggerAppRefresh(refreshTime)); }; diff --git a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx index db34566d6c148..66ff5ba7a58ee 100644 --- a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx @@ -85,6 +85,7 @@ const Application = (props: UptimeAppProps) => { ); }, [canSave, renderGlobalHelpControls, setBadge]); + // @ts-ignore store.dispatch(setBasePath(basePath)); return ( diff --git a/x-pack/package.json b/x-pack/package.json index 43df763c22bdc..37791c255aee9 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -65,7 +65,7 @@ "@types/graphql": "^0.13.2", "@types/gulp": "^4.0.6", "@types/hapi__wreck": "^15.0.1", - "@types/hoist-non-react-statics": "^3.3.0", + "@types/hoist-non-react-statics": "^3.3.1", "@types/history": "^4.7.3", "@types/jest": "24.0.19", "@types/joi": "^13.4.2", @@ -88,14 +88,14 @@ "@types/prop-types": "^15.5.3", "@types/proper-lockfile": "^3.0.1", "@types/puppeteer": "^1.20.1", - "@types/react": "^16.9.11", - "@types/react-dom": "^16.9.4", - "@types/react-redux": "^6.0.6", + "@types/react": "^16.9.19", + "@types/react-dom": "^16.9.5", + "@types/react-redux": "^7.1.7", "@types/react-router-dom": "^5.1.3", "@types/react-sticky": "^6.0.3", "@types/react-test-renderer": "^16.9.1", "@types/recompose": "^0.30.6", - "@types/reduce-reducers": "^0.3.0", + "@types/reduce-reducers": "^1.0.0", "@types/redux-actions": "^2.6.1", "@types/sinon": "^7.0.13", "@types/styled-components": "^4.4.2", @@ -118,10 +118,10 @@ "copy-webpack-plugin": "^5.0.4", "cypress": "^3.6.1", "cypress-multi-reporters": "^1.2.3", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.15.1", - "enzyme-adapter-utils": "^1.12.1", - "enzyme-to-json": "^3.4.3", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.2", + "enzyme-adapter-utils": "^1.13.0", + "enzyme-to-json": "^3.4.4", "execa": "^3.2.0", "fancy-log": "^1.3.2", "fetch-mock": "^7.3.9", @@ -134,6 +134,7 @@ "graphql-codegen-typescript-server": "^0.18.2", "gulp": "4.0.2", "hapi": "^17.5.3", + "hoist-non-react-statics": "^3.3.2", "jest": "^24.9.0", "jest-cli": "^24.9.0", "jest-styled-components": "^7.0.0", @@ -176,7 +177,7 @@ "@elastic/apm-rum-react": "^0.3.2", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.6.0", - "@elastic/eui": "18.3.0", + "@elastic/eui": "19.0.0", "@elastic/filesaver": "1.1.2", "@elastic/maki": "6.1.0", "@elastic/node-crypto": "^1.0.0", @@ -305,7 +306,7 @@ "react-markdown": "^3.4.1", "react-moment-proptypes": "^1.7.0", "react-portal": "^3.2.0", - "react-redux": "^5.1.2", + "react-redux": "^7.1.3", "react-reverse-portal": "^1.0.4", "react-router-dom": "^5.1.2", "react-shortcuts": "^2.0.0", @@ -316,15 +317,15 @@ "react-vis": "^1.8.1", "react-visibility-sensor": "^5.1.1", "recompose": "^0.26.0", - "reduce-reducers": "^0.4.3", - "redux": "4.0.0", - "redux-actions": "2.6.5", - "redux-observable": "^1.0.0", + "reduce-reducers": "^1.0.4", + "redux": "^4.0.5", + "redux-actions": "^2.6.5", + "redux-observable": "^1.2.0", "redux-saga": "^0.16.0", - "redux-thunk": "2.3.0", + "redux-thunk": "^2.3.0", "redux-thunks": "^1.0.0", "request": "^2.88.0", - "reselect": "3.0.1", + "reselect": "^4.0.0", "resize-observer-polyfill": "^1.5.0", "rison-node": "0.3.1", "rxjs": "^6.5.3", @@ -339,8 +340,8 @@ "topojson-client": "3.0.0", "tslib": "^1.9.3", "turf": "3.0.14", - "typescript-fsa": "^2.5.0", - "typescript-fsa-reducers": "^0.4.5", + "typescript-fsa": "^3.0.0", + "typescript-fsa-reducers": "^1.2.1", "ui-select": "0.19.8", "unstated": "^2.1.1", "uuid": "3.3.2", diff --git a/x-pack/plugins/actions/kibana.json b/x-pack/plugins/actions/kibana.json index ff7f22af6261d..0c40dec46a6ee 100644 --- a/x-pack/plugins/actions/kibana.json +++ b/x-pack/plugins/actions/kibana.json @@ -4,7 +4,7 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "actions"], - "requiredPlugins": ["licensing", "taskManager", "encryptedSavedObjects", "event_log"], + "requiredPlugins": ["licensing", "taskManager", "encryptedSavedObjects", "eventLog"], "optionalPlugins": ["spaces"], "ui": false } diff --git a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts index d33574666cebd..919f0800c291c 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts @@ -74,6 +74,12 @@ describe('validateActionTypeSecrets()', () => { }).toThrowErrorMatchingInlineSnapshot( `"error validating action type secrets: [webhookUrl]: expected value of type [string] but got [number]"` ); + + expect(() => { + validateSecrets(actionType, { webhookUrl: 'fee-fi-fo-fum' }); + }).toThrowErrorMatchingInlineSnapshot( + `"error validating action type secrets: error configuring slack action: unable to parse host name from webhookUrl"` + ); }); test('should validate and pass when the slack webhookUrl is whitelisted', () => { @@ -95,8 +101,8 @@ describe('validateActionTypeSecrets()', () => { actionType = getActionType({ configurationUtilities: { ...configUtilsMock, - ensureWhitelistedUri: url => { - throw new Error(`target url is not whitelisted`); + ensureWhitelistedHostname: url => { + throw new Error(`target hostname is not whitelisted`); }, }, }); @@ -104,7 +110,7 @@ describe('validateActionTypeSecrets()', () => { expect(() => { validateSecrets(actionType, { webhookUrl: 'https://api.slack.com/' }); }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type secrets: error configuring slack action: target url is not whitelisted"` + `"error validating action type secrets: error configuring slack action: target hostname is not whitelisted"` ); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/slack.ts b/x-pack/plugins/actions/server/builtin_action_types/slack.ts index b8989e59a2257..042853796695d 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/slack.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/slack.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { URL } from 'url'; import { curry } from 'lodash'; import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; @@ -66,8 +67,17 @@ function valdiateActionTypeConfig( configurationUtilities: ActionsConfigurationUtilities, secretsObject: ActionTypeSecretsType ) { + let url: URL; try { - configurationUtilities.ensureWhitelistedUri(secretsObject.webhookUrl); + url = new URL(secretsObject.webhookUrl); + } catch (err) { + return i18n.translate('xpack.actions.builtin.slack.slackConfigurationErrorNoHostname', { + defaultMessage: 'error configuring slack action: unable to parse host name from webhookUrl', + }); + } + + try { + configurationUtilities.ensureWhitelistedHostname(url.hostname); } catch (whitelistError) { return i18n.translate('xpack.actions.builtin.slack.slackConfigurationError', { defaultMessage: 'error configuring slack action: {message}', diff --git a/x-pack/plugins/actions/server/plugin.test.ts b/x-pack/plugins/actions/server/plugin.test.ts index ba6fbcd32daee..91944dfa8f3ad 100644 --- a/x-pack/plugins/actions/server/plugin.test.ts +++ b/x-pack/plugins/actions/server/plugin.test.ts @@ -27,7 +27,7 @@ describe('Actions Plugin', () => { taskManager: taskManagerMock.createSetup(), encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), licensing: licensingMock.createSetup(), - event_log: eventLogMock.createSetup(), + eventLog: eventLogMock.createSetup(), }; }); @@ -107,7 +107,7 @@ describe('Actions Plugin', () => { taskManager: taskManagerMock.createSetup(), encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), licensing: licensingMock.createSetup(), - event_log: eventLogMock.createSetup(), + eventLog: eventLogMock.createSetup(), }; pluginsStart = { taskManager: taskManagerMock.createStart(), diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 1714666882b05..b0555921f395f 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -70,7 +70,7 @@ export interface ActionsPluginsSetup { encryptedSavedObjects: EncryptedSavedObjectsPluginSetup; licensing: LicensingPluginSetup; spaces?: SpacesPluginSetup; - event_log: IEventLogService; + eventLog: IEventLogService; } export interface ActionsPluginsStart { encryptedSavedObjects: EncryptedSavedObjectsPluginStart; @@ -132,8 +132,8 @@ export class ActionsPlugin implements Plugin, Plugi attributesToEncrypt: new Set(['apiKey']), }); - plugins.event_log.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); - this.eventLogger = plugins.event_log.getLogger({ + plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); + this.eventLogger = plugins.eventLog.getLogger({ event: { provider: EVENT_LOG_PROVIDER }, }); diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts index 0dc3fc29ca805..5ef9d22e4dd7b 100644 --- a/x-pack/plugins/endpoint/common/types.ts +++ b/x-pack/plugins/endpoint/common/types.ts @@ -118,4 +118,4 @@ export interface EndpointMetadata { /** * The PageId type is used for the payload when firing userNavigatedToPage actions */ -export type PageId = 'alertsPage' | 'managementPage'; +export type PageId = 'alertsPage' | 'managementPage' | 'policyListPage'; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts b/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts new file mode 100644 index 0000000000000..83f4bc1e79317 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/components/truncate_text.ts @@ -0,0 +1,13 @@ +/* + * 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 styled from 'styled-components'; + +export const TruncateText = styled.div` + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +`; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx index a86c647e771d4..7bb3b13525914 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx @@ -14,6 +14,7 @@ import { Store } from 'redux'; import { appStoreFactory } from './store'; import { AlertIndex } from './view/alerts'; import { ManagementList } from './view/managing'; +import { PolicyList } from './view/policy'; /** * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle. @@ -51,6 +52,7 @@ const AppRoot: React.FunctionComponent = React.memo(({ basename, st /> + ( diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/action.ts index 04c6cf7fc4634..d099c81317090 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/action.ts @@ -7,5 +7,6 @@ import { ManagementAction } from './managing'; import { AlertAction } from './alerts'; import { RoutingAction } from './routing'; +import { PolicyListAction } from './policy_list'; -export type AppAction = ManagementAction | AlertAction | RoutingAction; +export type AppAction = ManagementAction | AlertAction | RoutingAction | PolicyListAction; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts index 3bbcc3f25a6d8..8fe61ae01d319 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts @@ -17,6 +17,7 @@ import { CoreStart } from 'kibana/public'; import { appReducer } from './reducer'; import { alertMiddlewareFactory } from './alerts/middleware'; import { managementMiddlewareFactory } from './managing'; +import { policyListMiddlewareFactory } from './policy_list'; import { GlobalState } from '../types'; import { AppAction } from './action'; @@ -56,6 +57,10 @@ export const appStoreFactory = (coreStart: CoreStart): Store => { substateMiddlewareFactory( globalState => globalState.managementList, managementMiddlewareFactory(coreStart) + ), + substateMiddlewareFactory( + globalState => globalState.policyList, + policyListMiddlewareFactory(coreStart) ) ) ) diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts new file mode 100644 index 0000000000000..5ac2a4328b00a --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts @@ -0,0 +1,27 @@ +/* + * 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 { PolicyData } from '../../types'; + +interface ServerReturnedPolicyListData { + type: 'serverReturnedPolicyListData'; + payload: { + policyItems: PolicyData[]; + total: number; + pageSize: number; + pageIndex: number; + }; +} + +interface UserPaginatedPolicyListTable { + type: 'userPaginatedPolicyListTable'; + payload: { + pageSize: number; + pageIndex: number; + }; +} + +export type PolicyListAction = ServerReturnedPolicyListData | UserPaginatedPolicyListTable; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts new file mode 100644 index 0000000000000..62bdd28f30be1 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts @@ -0,0 +1,53 @@ +/* + * 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. + */ + +// !!!! Should be deleted when https://github.com/elastic/endpoint-app-team/issues/150 +// is implemented + +const dateOffsets = [ + 0, + 1000, + 300000, // 5 minutes + 3.6e6, // 1 hour + 86340000, // 23h, 59m + 9e7, // 25h + 9e7 * 5, // 5d +]; + +const randomNumbers = [5, 50, 500, 5000, 50000]; + +const getRandomDateIsoString = () => { + const randomIndex = Math.floor(Math.random() * Math.floor(dateOffsets.length)); + return new Date(Date.now() - dateOffsets[randomIndex]).toISOString(); +}; + +const getRandomNumber = () => { + const randomIndex = Math.floor(Math.random() * Math.floor(randomNumbers.length)); + return randomNumbers[randomIndex]; +}; + +export const getFakeDatasourceApiResponse = async (page: number, pageSize: number) => { + await new Promise(resolve => setTimeout(resolve, 500)); + + // Emulates the API response - see PR: + // https://github.com/elastic/kibana/pull/56567/files#diff-431549a8739efe0c56763f164c32caeeR25 + return { + items: Array.from({ length: pageSize }, (x, i) => ({ + name: `policy with some protections ${i + 1}`, + total: getRandomNumber(), + pending: getRandomNumber(), + failed: getRandomNumber(), + created_by: `admin ABC`, + created: getRandomDateIsoString(), + updated_by: 'admin 123', + updated: getRandomDateIsoString(), + })), + success: true, + total: pageSize * 10, + page, + perPage: pageSize, + }; +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts new file mode 100644 index 0000000000000..ae4a0868a68fe --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PolicyListState } from '../../types'; +import { applyMiddleware, createStore, Dispatch, Store } from 'redux'; +import { AppAction } from '../action'; +import { policyListReducer } from './reducer'; +import { policyListMiddlewareFactory } from './middleware'; +import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { CoreStart } from 'kibana/public'; +import { selectIsLoading } from './selectors'; + +describe('policy list store concerns', () => { + const sleep = () => new Promise(resolve => setTimeout(resolve, 1000)); + let fakeCoreStart: jest.Mocked; + let store: Store; + let getState: typeof store['getState']; + let dispatch: Dispatch; + + beforeEach(() => { + fakeCoreStart = coreMock.createStart({ basePath: '/mock' }); + store = createStore( + policyListReducer, + applyMiddleware(policyListMiddlewareFactory(fakeCoreStart)) + ); + getState = store.getState; + dispatch = store.dispatch; + }); + + test('it sets `isLoading` when `userNavigatedToPage`', async () => { + expect(selectIsLoading(getState())).toBe(false); + dispatch({ type: 'userNavigatedToPage', payload: 'policyListPage' }); + expect(selectIsLoading(getState())).toBe(true); + await sleep(); + expect(selectIsLoading(getState())).toBe(false); + }); + + test('it sets `isLoading` when `userPaginatedPolicyListTable`', async () => { + expect(selectIsLoading(getState())).toBe(false); + dispatch({ + type: 'userPaginatedPolicyListTable', + payload: { + pageSize: 10, + pageIndex: 1, + }, + }); + expect(selectIsLoading(getState())).toBe(true); + await sleep(); + expect(selectIsLoading(getState())).toBe(false); + }); + + test('it resets state on `userNavigatedFromPage` action', async () => { + dispatch({ + type: 'serverReturnedPolicyListData', + payload: { + policyItems: [], + pageIndex: 20, + pageSize: 50, + total: 200, + }, + }); + dispatch({ type: 'userNavigatedFromPage', payload: 'policyListPage' }); + expect(getState()).toEqual({ + policyItems: [], + isLoading: false, + pageIndex: 0, + pageSize: 10, + total: 0, + }); + }); +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.ts new file mode 100644 index 0000000000000..8086acc41d2bd --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { policyListReducer } from './reducer'; +export { PolicyListAction } from './action'; +export { policyListMiddlewareFactory } from './middleware'; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts new file mode 100644 index 0000000000000..f8e2b7d07c389 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MiddlewareFactory, PolicyListState } from '../../types'; + +export const policyListMiddlewareFactory: MiddlewareFactory = coreStart => { + return ({ getState, dispatch }) => next => async action => { + next(action); + + if ( + (action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') || + action.type === 'userPaginatedPolicyListTable' + ) { + const state = getState(); + let pageSize: number; + let pageIndex: number; + + if (action.type === 'userPaginatedPolicyListTable') { + pageSize = action.payload.pageSize; + pageIndex = action.payload.pageIndex; + } else { + pageSize = state.pageSize; + pageIndex = state.pageIndex; + } + + // Need load data from API and remove fake data below + // Refactor tracked via: https://github.com/elastic/endpoint-app-team/issues/150 + const { getFakeDatasourceApiResponse } = await import('./fake_data'); + const { items: policyItems, total } = await getFakeDatasourceApiResponse(pageIndex, pageSize); + + dispatch({ + type: 'serverReturnedPolicyListData', + payload: { + policyItems, + pageIndex, + pageSize, + total, + }, + }); + } + }; +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts new file mode 100644 index 0000000000000..77f536d413ae3 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts @@ -0,0 +1,48 @@ +/* + * 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 { Reducer } from 'redux'; +import { PolicyListState } from '../../types'; +import { AppAction } from '../action'; + +const initialPolicyListState = (): PolicyListState => { + return { + policyItems: [], + isLoading: false, + pageIndex: 0, + pageSize: 10, + total: 0, + }; +}; + +export const policyListReducer: Reducer = ( + state = initialPolicyListState(), + action +) => { + if (action.type === 'serverReturnedPolicyListData') { + return { + ...state, + ...action.payload, + isLoading: false, + }; + } + + if ( + action.type === 'userPaginatedPolicyListTable' || + (action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') + ) { + return { + ...state, + isLoading: true, + }; + } + + if (action.type === 'userNavigatedFromPage' && action.payload === 'policyListPage') { + return initialPolicyListState(); + } + + return state; +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts new file mode 100644 index 0000000000000..b9c2edbf5d55b --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts @@ -0,0 +1,17 @@ +/* + * 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 { PolicyListState } from '../../types'; + +export const selectPolicyItems = (state: PolicyListState) => state.policyItems; + +export const selectPageIndex = (state: PolicyListState) => state.pageIndex; + +export const selectPageSize = (state: PolicyListState) => state.pageSize; + +export const selectTotal = (state: PolicyListState) => state.total; + +export const selectIsLoading = (state: PolicyListState) => state.isLoading; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/reducer.ts index 7d738c266fae0..3d9d21c0da9c3 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/reducer.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/reducer.ts @@ -8,8 +8,10 @@ import { managementListReducer } from './managing'; import { AppAction } from './action'; import { alertListReducer } from './alerts'; import { GlobalState } from '../types'; +import { policyListReducer } from './policy_list'; export const appReducer: Reducer = combineReducers({ managementList: managementListReducer, alertList: alertListReducer, + policyList: policyListReducer, }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts index 263a3f72d57d5..9080af8c91817 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts @@ -11,4 +11,9 @@ interface UserNavigatedToPage { readonly payload: PageId; } -export type RoutingAction = UserNavigatedToPage; +interface UserNavigatedFromPage { + readonly type: 'userNavigatedFromPage'; + readonly payload: PageId; +} + +export type RoutingAction = UserNavigatedToPage | UserNavigatedFromPage; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index 02a7793fc38b0..6b20012592fd9 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -29,9 +29,38 @@ export interface ManagementListPagination { pageSize: number; } +// REFACTOR to use Types from Ingest Manager - see: https://github.com/elastic/endpoint-app-team/issues/150 +export interface PolicyData { + name: string; + total: number; + pending: number; + failed: number; + created_by: string; + created: string; + updated_by: string; + updated: string; +} + +/** + * Policy list store state + */ +export interface PolicyListState { + /** Array of policy items */ + policyItems: PolicyData[]; + /** total number of policies */ + total: number; + /** Number of policies per page */ + pageSize: number; + /** page number (zero based) */ + pageIndex: number; + /** data is being retrieved from server */ + isLoading: boolean; +} + export interface GlobalState { readonly managementList: ManagementListState; readonly alertList: AlertListState; + readonly policyList: PolicyListState; } export type AlertListData = AlertResultList; diff --git a/x-pack/legacy/plugins/index_management/public/app/store/reducers/index.js b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/index.ts similarity index 81% rename from x-pack/legacy/plugins/index_management/public/app/store/reducers/index.js rename to x-pack/plugins/endpoint/public/applications/endpoint/view/policy/index.ts index eeae581be9473..d561da7574de0 100644 --- a/x-pack/legacy/plugins/index_management/public/app/store/reducers/index.js +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { indexManagement } from './index_management'; +export * from './policy_list'; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_hooks.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_hooks.ts new file mode 100644 index 0000000000000..14558fb6504bb --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_hooks.ts @@ -0,0 +1,12 @@ +/* + * 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 { useSelector } from 'react-redux'; +import { GlobalState, PolicyListState } from '../../types'; + +export function usePolicyListSelector(selector: (state: PolicyListState) => TSelected) { + return useSelector((state: GlobalState) => selector(state.policyList)); +} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx new file mode 100644 index 0000000000000..75ffa5e8806e9 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx @@ -0,0 +1,232 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useCallback, useMemo } from 'react'; +import { + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageContentBody, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiTitle, + EuiBasicTable, + EuiText, + EuiTableFieldDataColumnType, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { + FormattedMessage, + FormattedDate, + FormattedTime, + FormattedNumber, + FormattedRelative, +} from '@kbn/i18n/react'; +import { useDispatch } from 'react-redux'; +import styled from 'styled-components'; +import { usePageId } from '../use_page_id'; +import { + selectIsLoading, + selectPageIndex, + selectPageSize, + selectPolicyItems, + selectTotal, +} from '../../store/policy_list/selectors'; +import { usePolicyListSelector } from './policy_hooks'; +import { PolicyListAction } from '../../store/policy_list'; +import { PolicyData } from '../../types'; +import { TruncateText } from '../../components/truncate_text'; + +interface TableChangeCallbackArguments { + page: { index: number; size: number }; +} + +const TruncateTooltipText = styled(TruncateText)` + .euiToolTipAnchor { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +`; + +const FormattedDateAndTime: React.FC<{ date: Date }> = ({ date }) => { + // If date is greater than or equal to 24h (ago), then show it as a date + // else, show it as relative to "now" + return Date.now() - date.getTime() >= 8.64e7 ? ( + <> + + {' @'} + + + ) : ( + <> + + + ); +}; + +const renderDate = (date: string, _item: PolicyData) => ( + + + + + +); + +const renderFormattedNumber = (value: number, _item: PolicyData) => ( + + + +); + +export const PolicyList = React.memo(() => { + usePageId('policyListPage'); + + const dispatch = useDispatch<(action: PolicyListAction) => void>(); + const policyItems = usePolicyListSelector(selectPolicyItems); + const pageIndex = usePolicyListSelector(selectPageIndex); + const pageSize = usePolicyListSelector(selectPageSize); + const totalItemCount = usePolicyListSelector(selectTotal); + const loading = usePolicyListSelector(selectIsLoading); + + const paginationSetup = useMemo(() => { + return { + pageIndex, + pageSize, + totalItemCount, + pageSizeOptions: [10, 20, 50], + hidePerPageOptions: false, + }; + }, [pageIndex, pageSize, totalItemCount]); + + const handleTableChange = useCallback( + ({ page: { index, size } }: TableChangeCallbackArguments) => { + dispatch({ + type: 'userPaginatedPolicyListTable', + payload: { + pageIndex: index, + pageSize: size, + }, + }); + }, + [dispatch] + ); + + const columns: Array> = useMemo( + () => [ + { + field: 'name', + name: i18n.translate('xpack.endpoint.policyList.nameField', { + defaultMessage: 'Policy Name', + }), + truncateText: true, + }, + { + field: 'total', + name: i18n.translate('xpack.endpoint.policyList.totalField', { + defaultMessage: 'Total', + }), + render: renderFormattedNumber, + dataType: 'number', + truncateText: true, + width: '15ch', + }, + { + field: 'pending', + name: i18n.translate('xpack.endpoint.policyList.pendingField', { + defaultMessage: 'Pending', + }), + render: renderFormattedNumber, + dataType: 'number', + truncateText: true, + width: '15ch', + }, + { + field: 'failed', + name: i18n.translate('xpack.endpoint.policyList.failedField', { + defaultMessage: 'Failed', + }), + render: renderFormattedNumber, + dataType: 'number', + truncateText: true, + width: '15ch', + }, + { + field: 'created_by', + name: i18n.translate('xpack.endpoint.policyList.createdByField', { + defaultMessage: 'Created By', + }), + truncateText: true, + }, + { + field: 'created', + name: i18n.translate('xpack.endpoint.policyList.createdField', { + defaultMessage: 'Created', + }), + render: renderDate, + truncateText: true, + }, + { + field: 'updated_by', + name: i18n.translate('xpack.endpoint.policyList.updatedByField', { + defaultMessage: 'Last Updated By', + }), + truncateText: true, + }, + { + field: 'updated', + name: i18n.translate('xpack.endpoint.policyList.updatedField', { + defaultMessage: 'Last Updated', + }), + render: renderDate, + truncateText: true, + }, + ], + [] + ); + + return ( + + + + + + +

+ +

+
+

+ + + +

+
+
+ + + +
+
+
+ ); +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts index 9e241af4c0445..49c39064c8d9a 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts @@ -10,11 +10,19 @@ import { PageId } from '../../../../common/types'; import { RoutingAction } from '../store/routing'; /** - * Dispatches a 'userNavigatedToPage' action with the given 'pageId' as the action payload + * Dispatches a 'userNavigatedToPage' action with the given 'pageId' as the action payload. + * When the component is un-mounted, a `userNavigatedFromPage` action will be dispatched + * with the given `pageId`. + * + * @param pageId A page id */ export function usePageId(pageId: PageId) { const dispatch: (action: RoutingAction) => unknown = useDispatch(); useEffect(() => { dispatch({ type: 'userNavigatedToPage', payload: pageId }); + + return () => { + dispatch({ type: 'userNavigatedFromPage', payload: pageId }); + }; }, [dispatch, pageId]); } diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts new file mode 100644 index 0000000000000..ae3c9962ecadb --- /dev/null +++ b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { installXJsonMode, XJsonMode } from './x_json'; diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts new file mode 100644 index 0000000000000..ae3c9962ecadb --- /dev/null +++ b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { installXJsonMode, XJsonMode } from './x_json'; diff --git a/x-pack/plugins/searchprofiler/public/application/editor/worker/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/editor/worker/index.ts rename to x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts diff --git a/x-pack/plugins/searchprofiler/public/application/editor/worker/worker.d.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/editor/worker/worker.d.ts rename to x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.d.ts diff --git a/x-pack/plugins/searchprofiler/public/application/editor/worker/worker.js b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.js similarity index 100% rename from x-pack/plugins/searchprofiler/public/application/editor/worker/worker.js rename to x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/worker.js diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts new file mode 100644 index 0000000000000..bfeca045bea02 --- /dev/null +++ b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/x_json.ts @@ -0,0 +1,34 @@ +/* + * 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 ace from 'brace'; +import { XJsonMode } from '../../../../../../../src/plugins/es_ui_shared/console_lang'; +import { workerModule } from './worker'; +const { WorkerClient } = ace.acequire('ace/worker/worker_client'); + +// Then clobber `createWorker` method to install our worker source. Per ace's wiki: https://github.com/ajaxorg/ace/wiki/Syntax-validation +(XJsonMode.prototype as any).createWorker = function(session: ace.IEditSession) { + const xJsonWorker = new WorkerClient(['ace'], workerModule, 'JsonWorker'); + + xJsonWorker.attachToDocument(session.getDocument()); + + xJsonWorker.on('annotate', function(e: { data: any }) { + session.setAnnotations(e.data); + }); + + xJsonWorker.on('terminate', function() { + session.clearAnnotations(); + }); + + return xJsonWorker; +}; + +export { XJsonMode }; + +export function installXJsonMode(editor: ace.Editor) { + const session = editor.getSession(); + session.setMode(new (XJsonMode as any)()); +} diff --git a/x-pack/plugins/es_ui_shared/console_lang/index.ts b/x-pack/plugins/es_ui_shared/console_lang/index.ts new file mode 100644 index 0000000000000..b5fe3a554e34d --- /dev/null +++ b/x-pack/plugins/es_ui_shared/console_lang/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { XJsonMode, installXJsonMode } from './ace/modes'; diff --git a/x-pack/plugins/es_ui_shared/console_lang/mocks.ts b/x-pack/plugins/es_ui_shared/console_lang/mocks.ts new file mode 100644 index 0000000000000..68480282ddc03 --- /dev/null +++ b/x-pack/plugins/es_ui_shared/console_lang/mocks.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +jest.mock('./ace/modes/x_json/worker', () => ({ + workerModule: { id: 'ace/mode/json_worker', src: '' }, +})); diff --git a/x-pack/plugins/event_log/README.md b/x-pack/plugins/event_log/README.md index d2d67ffc27d94..027bbc694801f 100644 --- a/x-pack/plugins/event_log/README.md +++ b/x-pack/plugins/event_log/README.md @@ -9,14 +9,14 @@ and actions. ## Basic Usage - Logging Events -Follow these steps to use `event_log` in your plugin: +Follow these steps to use `eventLog` in your plugin: -1. Declare `event_log` as a dependency in `kibana.json`: +1. Declare `eventLog` as a dependency in `kibana.json`: ```json { ... - "requiredPlugins": ["event_log"], + "requiredPlugins": ["eventLog"], ... } ``` @@ -28,13 +28,13 @@ API provided in the `setup` stage: ... import { IEventLogger, IEventLogService } from '../../event_log/server'; interface PluginSetupDependencies { - event_log: IEventLogService; + eventLog: IEventLogService; } ... -public setup(core: CoreSetup, { event_log }: PluginSetupDependencies) { +public setup(core: CoreSetup, { eventLog }: PluginSetupDependencies) { ... - event_log.registerProviderActions('my-plugin', ['action-1, action-2']); - const eventLogger: IEventLogger = event_log.getLogger({ event: { provider: 'my-plugin' } }); + eventLog.registerProviderActions('my-plugin', ['action-1, action-2']); + const eventLogger: IEventLogger = eventLog.getLogger({ event: { provider: 'my-plugin' } }); ... } ... @@ -73,7 +73,7 @@ a new elasticsearch index referred to as the "event log". Example events are actions firing, alerts running their scheduled functions, alerts scheduling actions to run, etc. -This functionality will be provided in a new NP plugin `event_log`, and will +This functionality will be provided in a new NP plugin `eventLog`, and will provide server-side plugin APIs to write to the event log, and run limited queries against it. For now, access via HTTP will not be available, due to security concerns and lack of use cases. diff --git a/x-pack/plugins/event_log/kibana.json b/x-pack/plugins/event_log/kibana.json index 52b68deeffce5..7231d967b4c8d 100644 --- a/x-pack/plugins/event_log/kibana.json +++ b/x-pack/plugins/event_log/kibana.json @@ -1,8 +1,8 @@ { - "id": "event_log", + "id": "eventLog", "version": "0.0.1", "kibanaVersion": "kibana", - "configPath": ["xpack", "event_log"], + "configPath": ["xpack", "eventLog"], "server": true, "ui": false } diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts new file mode 100644 index 0000000000000..87e8fb0f521a9 --- /dev/null +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IClusterClientAdapter } from './cluster_client_adapter'; + +const createClusterClientMock = () => { + const mock: jest.Mocked = { + indexDocument: jest.fn(), + doesIlmPolicyExist: jest.fn(), + createIlmPolicy: jest.fn(), + doesIndexTemplateExist: jest.fn(), + createIndexTemplate: jest.fn(), + doesAliasExist: jest.fn(), + createIndex: jest.fn(), + }; + return mock; +}; + +export const clusterClientAdapterMock = { + create: createClusterClientMock, +}; diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts new file mode 100644 index 0000000000000..ecefd4bfa271e --- /dev/null +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -0,0 +1,196 @@ +/* + * 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 { ClusterClient, Logger } from '../../../../../src/core/server'; +import { elasticsearchServiceMock, loggingServiceMock } from '../../../../../src/core/server/mocks'; +import { ClusterClientAdapter, IClusterClientAdapter } from './cluster_client_adapter'; + +type EsClusterClient = Pick, 'callAsInternalUser' | 'asScoped'>; + +let logger: Logger; +let clusterClient: EsClusterClient; +let clusterClientAdapter: IClusterClientAdapter; + +beforeEach(() => { + logger = loggingServiceMock.createLogger(); + clusterClient = elasticsearchServiceMock.createClusterClient(); + clusterClientAdapter = new ClusterClientAdapter({ + logger, + clusterClient, + }); +}); + +describe('indexDocument', () => { + test('should call cluster client with given doc', async () => { + await clusterClientAdapter.indexDocument({ args: true }); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('index', { + args: true, + }); + }); + + test('should throw error when cluster client throws an error', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.indexDocument({ args: true }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Fail"`); + }); +}); + +describe('doesIlmPolicyExist', () => { + const notFoundError = new Error('Not found') as any; + notFoundError.statusCode = 404; + + test('should call cluster with proper arguments', async () => { + await clusterClientAdapter.doesIlmPolicyExist('foo'); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('transport.request', { + method: 'GET', + path: '_ilm/policy/foo', + }); + }); + + test('should return false when 404 error is returned by Elasticsearch', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(notFoundError); + await expect(clusterClientAdapter.doesIlmPolicyExist('foo')).resolves.toEqual(false); + }); + + test('should throw error when error is not 404', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.doesIlmPolicyExist('foo') + ).rejects.toThrowErrorMatchingInlineSnapshot(`"error checking existance of ilm policy: Fail"`); + }); + + test('should return true when no error is thrown', async () => { + await expect(clusterClientAdapter.doesIlmPolicyExist('foo')).resolves.toEqual(true); + }); +}); + +describe('createIlmPolicy', () => { + test('should call cluster client with given policy', async () => { + clusterClient.callAsInternalUser.mockResolvedValue({ success: true }); + await clusterClientAdapter.createIlmPolicy('foo', { args: true }); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('transport.request', { + method: 'PUT', + path: '_ilm/policy/foo', + body: { args: true }, + }); + }); + + test('should throw error when call cluster client throws', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.createIlmPolicy('foo', { args: true }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"error creating ilm policy: Fail"`); + }); +}); + +describe('doesIndexTemplateExist', () => { + test('should call cluster with proper arguments', async () => { + await clusterClientAdapter.doesIndexTemplateExist('foo'); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('indices.existsTemplate', { + name: 'foo', + }); + }); + + test('should return true when call cluster returns true', async () => { + clusterClient.callAsInternalUser.mockResolvedValue(true); + await expect(clusterClientAdapter.doesIndexTemplateExist('foo')).resolves.toEqual(true); + }); + + test('should return false when call cluster returns false', async () => { + clusterClient.callAsInternalUser.mockResolvedValue(false); + await expect(clusterClientAdapter.doesIndexTemplateExist('foo')).resolves.toEqual(false); + }); + + test('should throw error when call cluster throws an error', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.doesIndexTemplateExist('foo') + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"error checking existance of index template: Fail"` + ); + }); +}); + +describe('createIndexTemplate', () => { + test('should call cluster with given template', async () => { + await clusterClientAdapter.createIndexTemplate('foo', { args: true }); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('indices.putTemplate', { + name: 'foo', + create: true, + body: { args: true }, + }); + }); + + test(`should throw error if index template still doesn't exist after error is thrown`, async () => { + clusterClient.callAsInternalUser.mockRejectedValueOnce(new Error('Fail')); + clusterClient.callAsInternalUser.mockResolvedValueOnce(false); + await expect( + clusterClientAdapter.createIndexTemplate('foo', { args: true }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"error creating index template: Fail"`); + }); + + test('should not throw error if index template exists after error is thrown', async () => { + clusterClient.callAsInternalUser.mockRejectedValueOnce(new Error('Fail')); + clusterClient.callAsInternalUser.mockResolvedValueOnce(true); + await clusterClientAdapter.createIndexTemplate('foo', { args: true }); + }); +}); + +describe('doesAliasExist', () => { + test('should call cluster with proper arguments', async () => { + await clusterClientAdapter.doesAliasExist('foo'); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('indices.existsAlias', { + name: 'foo', + }); + }); + + test('should return true when call cluster returns true', async () => { + clusterClient.callAsInternalUser.mockResolvedValueOnce(true); + await expect(clusterClientAdapter.doesAliasExist('foo')).resolves.toEqual(true); + }); + + test('should return false when call cluster returns false', async () => { + clusterClient.callAsInternalUser.mockResolvedValueOnce(false); + await expect(clusterClientAdapter.doesAliasExist('foo')).resolves.toEqual(false); + }); + + test('should throw error when call cluster throws an error', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.doesAliasExist('foo') + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"error checking existance of initial index: Fail"` + ); + }); +}); + +describe('createIndex', () => { + test('should call cluster with proper arguments', async () => { + await clusterClientAdapter.createIndex('foo'); + expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('indices.create', { + index: 'foo', + }); + }); + + test('should throw error when not getting an error of type resource_already_exists_exception', async () => { + clusterClient.callAsInternalUser.mockRejectedValue(new Error('Fail')); + await expect( + clusterClientAdapter.createIndex('foo') + ).rejects.toThrowErrorMatchingInlineSnapshot(`"error creating initial index: Fail"`); + }); + + test(`shouldn't throw when an error of type resource_already_exists_exception is thrown`, async () => { + const err = new Error('Already exists') as any; + err.body = { + error: { + type: 'resource_already_exists_exception', + }, + }; + clusterClient.callAsInternalUser.mockRejectedValue(err); + await clusterClientAdapter.createIndex('foo'); + }); +}); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts new file mode 100644 index 0000000000000..c74eeacc9bb19 --- /dev/null +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -0,0 +1,126 @@ +/* + * 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 { Logger, ClusterClient } from '../../../../../src/core/server'; + +export type EsClusterClient = Pick; +export type IClusterClientAdapter = PublicMethodsOf; + +export interface ConstructorOpts { + logger: Logger; + clusterClient: EsClusterClient; +} + +export class ClusterClientAdapter { + private readonly logger: Logger; + private readonly clusterClient: EsClusterClient; + + constructor(opts: ConstructorOpts) { + this.logger = opts.logger; + this.clusterClient = opts.clusterClient; + } + + public async indexDocument(doc: any): Promise { + await this.callEs('index', doc); + } + + public async doesIlmPolicyExist(policyName: string): Promise { + const request = { + method: 'GET', + path: `_ilm/policy/${policyName}`, + }; + try { + await this.callEs('transport.request', request); + } catch (err) { + if (err.statusCode === 404) return false; + throw new Error(`error checking existance of ilm policy: ${err.message}`); + } + return true; + } + + public async createIlmPolicy(policyName: string, policy: any): Promise { + const request = { + method: 'PUT', + path: `_ilm/policy/${policyName}`, + body: policy, + }; + try { + await this.callEs('transport.request', request); + } catch (err) { + throw new Error(`error creating ilm policy: ${err.message}`); + } + } + + public async doesIndexTemplateExist(name: string): Promise { + let result; + try { + result = await this.callEs('indices.existsTemplate', { name }); + } catch (err) { + throw new Error(`error checking existance of index template: ${err.message}`); + } + return result as boolean; + } + + public async createIndexTemplate(name: string, template: any): Promise { + const addTemplateParams = { + name, + create: true, + body: template, + }; + try { + await this.callEs('indices.putTemplate', addTemplateParams); + } catch (err) { + // The error message doesn't have a type attribute we can look to guarantee it's due + // to the template already existing (only long message) so we'll check ourselves to see + // if the template now exists. This scenario would happen if you startup multiple Kibana + // instances at the same time. + const existsNow = await this.doesIndexTemplateExist(name); + if (!existsNow) { + throw new Error(`error creating index template: ${err.message}`); + } + } + } + + public async doesAliasExist(name: string): Promise { + let result; + try { + result = await this.callEs('indices.existsAlias', { name }); + } catch (err) { + throw new Error(`error checking existance of initial index: ${err.message}`); + } + return result as boolean; + } + + public async createIndex(name: string): Promise { + try { + await this.callEs('indices.create', { index: name }); + } catch (err) { + if (err.body?.error?.type !== 'resource_already_exists_exception') { + throw new Error(`error creating initial index: ${err.message}`); + } + } + } + + private async callEs(operation: string, body?: any): Promise { + try { + this.debug(`callEs(${operation}) calls:`, body); + const result = await this.clusterClient.callAsInternalUser(operation, body); + this.debug(`callEs(${operation}) result:`, result); + return result; + } catch (err) { + this.debug(`callEs(${operation}) error:`, { + message: err.message, + statusCode: err.statusCode, + }); + throw err; + } + } + + private debug(message: string, object?: any) { + const objectString = object == null ? '' : JSON.stringify(object); + this.logger.debug(`esContext: ${message} ${objectString}`); + } +} diff --git a/x-pack/plugins/event_log/server/es/context.mock.ts b/x-pack/plugins/event_log/server/es/context.mock.ts index fb894ce6e7787..6581cd689e43d 100644 --- a/x-pack/plugins/event_log/server/es/context.mock.ts +++ b/x-pack/plugins/event_log/server/es/context.mock.ts @@ -4,43 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, ClusterClient } from '../../../../../src/core/server'; import { EsContext } from './context'; - -import { EsNames } from './names'; - -export type EsClusterClient = Pick; - -export interface EsError { - readonly statusCode: number; - readonly message: string; -} - -interface CreateMockEsContextParams { - logger: Logger; - esNames: EsNames; -} - -export function createMockEsContext(params: CreateMockEsContextParams): EsContext { - return new EsContextMock(params); -} - -class EsContextMock implements EsContext { - public logger: Logger; - public esNames: EsNames; - - constructor(params: CreateMockEsContextParams) { - this.logger = params.logger; - this.esNames = params.esNames; - } - - initialize() {} - - async waitTillReady(): Promise { - return true; - } - - async callEs(operation: string, body?: any): Promise { - return {}; - } -} +import { namesMock } from './names.mock'; +import { IClusterClientAdapter } from './cluster_client_adapter'; +import { loggingServiceMock } from '../../../../../src/core/server/mocks'; +import { clusterClientAdapterMock } from './cluster_client_adapter.mock'; + +const createContextMock = () => { + const mock: jest.Mocked & { + esAdapter: jest.Mocked; + } = { + logger: loggingServiceMock.createLogger(), + esNames: namesMock.create(), + initialize: jest.fn(), + waitTillReady: jest.fn(), + esAdapter: clusterClientAdapterMock.create(), + }; + return mock; +}; + +export const contextMock = { + create: createContextMock, +}; diff --git a/x-pack/plugins/event_log/server/es/context.ts b/x-pack/plugins/event_log/server/es/context.ts index b93c1892d0206..144f44ac8e5ea 100644 --- a/x-pack/plugins/event_log/server/es/context.ts +++ b/x-pack/plugins/event_log/server/es/context.ts @@ -8,6 +8,7 @@ import { Logger, ClusterClient } from 'src/core/server'; import { EsNames, getEsNames } from './names'; import { initializeEs } from './init'; +import { ClusterClientAdapter, IClusterClientAdapter } from './cluster_client_adapter'; import { createReadySignal, ReadySignal } from '../lib/ready_signal'; export type EsClusterClient = Pick; @@ -15,9 +16,9 @@ export type EsClusterClient = Pick; - callEs(operation: string, body?: any): Promise; } export interface EsError { @@ -38,16 +39,19 @@ export interface EsContextCtorParams { class EsContextImpl implements EsContext { public readonly logger: Logger; public readonly esNames: EsNames; - private readonly clusterClient: EsClusterClient; + public esAdapter: IClusterClientAdapter; private readonly readySignal: ReadySignal; private initialized: boolean; constructor(params: EsContextCtorParams) { this.logger = params.logger; this.esNames = getEsNames(params.indexNameRoot); - this.clusterClient = params.clusterClient; this.readySignal = createReadySignal(); this.initialized = false; + this.esAdapter = new ClusterClientAdapter({ + logger: params.logger, + clusterClient: params.clusterClient, + }); } initialize() { @@ -73,27 +77,7 @@ class EsContextImpl implements EsContext { return await this.readySignal.wait(); } - async callEs(operation: string, body?: any): Promise { - try { - this.debug(`callEs(${operation}) calls:`, body); - const result = await this.clusterClient.callAsInternalUser(operation, body); - this.debug(`callEs(${operation}) result:`, result); - return result; - } catch (err) { - this.debug(`callEs(${operation}) error:`, { - message: err.message, - statusCode: err.statusCode, - }); - throw err; - } - } - private async _initialize() { await initializeEs(this); } - - private debug(message: string, object?: any) { - const objectString = object == null ? '' : JSON.stringify(object); - this.logger.debug(`esContext: ${message} ${objectString}`); - } } diff --git a/x-pack/plugins/event_log/server/es/documents.test.ts b/x-pack/plugins/event_log/server/es/documents.test.ts index 2dec23c61de2f..7edca4b3943a6 100644 --- a/x-pack/plugins/event_log/server/es/documents.test.ts +++ b/x-pack/plugins/event_log/server/es/documents.test.ts @@ -21,23 +21,13 @@ describe('getIndexTemplate()', () => { const esNames = getEsNames('XYZ'); test('returns the correct details of the index template', () => { - const indexTemplate = getIndexTemplate(esNames, true); + const indexTemplate = getIndexTemplate(esNames); expect(indexTemplate.index_patterns).toEqual([esNames.indexPattern]); expect(indexTemplate.aliases[esNames.alias]).toEqual({}); expect(indexTemplate.settings.number_of_shards).toBeGreaterThanOrEqual(0); expect(indexTemplate.settings.number_of_replicas).toBeGreaterThanOrEqual(0); - expect(indexTemplate.mappings).toMatchObject({}); - }); - - test('returns correct index template bits for ilm when ilm is supported', () => { - const indexTemplate = getIndexTemplate(esNames, true); expect(indexTemplate.settings['index.lifecycle.name']).toBe(esNames.ilmPolicy); expect(indexTemplate.settings['index.lifecycle.rollover_alias']).toBe(esNames.alias); - }); - - test('returns correct index template bits for ilm when ilm is not supported', () => { - const indexTemplate = getIndexTemplate(esNames, false); - expect(indexTemplate.settings['index.lifecycle.name']).toBeUndefined(); - expect(indexTemplate.settings['index.lifecycle.rollover_alias']).toBeUndefined(); + expect(indexTemplate.mappings).toMatchObject({}); }); }); diff --git a/x-pack/plugins/event_log/server/es/documents.ts b/x-pack/plugins/event_log/server/es/documents.ts index dfc544f8a41cb..09dd7383c4c5e 100644 --- a/x-pack/plugins/event_log/server/es/documents.ts +++ b/x-pack/plugins/event_log/server/es/documents.ts @@ -8,7 +8,7 @@ import { EsNames } from './names'; import mappings from '../../generated/mappings.json'; // returns the body of an index template used in an ES indices.putTemplate call -export function getIndexTemplate(esNames: EsNames, ilmExists: boolean) { +export function getIndexTemplate(esNames: EsNames) { const indexTemplateBody: any = { index_patterns: [esNames.indexPattern], aliases: { @@ -23,11 +23,6 @@ export function getIndexTemplate(esNames: EsNames, ilmExists: boolean) { mappings, }; - if (!ilmExists) { - delete indexTemplateBody.settings['index.lifecycle.name']; - delete indexTemplateBody.settings['index.lifecycle.rollover_alias']; - } - return indexTemplateBody; } diff --git a/x-pack/plugins/event_log/server/es/init.test.ts b/x-pack/plugins/event_log/server/es/init.test.ts new file mode 100644 index 0000000000000..ad237e522c0a5 --- /dev/null +++ b/x-pack/plugins/event_log/server/es/init.test.ts @@ -0,0 +1,64 @@ +/* + * 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 { contextMock } from './context.mock'; +import { initializeEs } from './init'; + +describe('initializeEs', () => { + let esContext = contextMock.create(); + + beforeEach(() => { + esContext = contextMock.create(); + }); + + test(`should create ILM policy if it doesn't exist`, async () => { + esContext.esAdapter.doesIlmPolicyExist.mockResolvedValue(false); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIlmPolicy).toHaveBeenCalled(); + }); + + test(`shouldn't create ILM policy if it exists`, async () => { + esContext.esAdapter.doesIlmPolicyExist.mockResolvedValue(true); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIlmPolicy).not.toHaveBeenCalled(); + }); + + test(`should create index template if it doesn't exist`, async () => { + esContext.esAdapter.doesIndexTemplateExist.mockResolvedValue(false); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesIndexTemplateExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIndexTemplate).toHaveBeenCalled(); + }); + + test(`shouldn't create index template if it already exists`, async () => { + esContext.esAdapter.doesIndexTemplateExist.mockResolvedValue(true); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesIndexTemplateExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIndexTemplate).not.toHaveBeenCalled(); + }); + + test(`should create initial index if it doesn't exist`, async () => { + esContext.esAdapter.doesAliasExist.mockResolvedValue(false); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesAliasExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIndex).toHaveBeenCalled(); + }); + + test(`shouldn't create initial index if it already exists`, async () => { + esContext.esAdapter.doesAliasExist.mockResolvedValue(true); + + await initializeEs(esContext); + expect(esContext.esAdapter.doesAliasExist).toHaveBeenCalled(); + expect(esContext.esAdapter.createIndex).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/event_log/server/es/init.ts b/x-pack/plugins/event_log/server/es/init.ts index d87f5bce03475..7094277f7aa9f 100644 --- a/x-pack/plugins/event_log/server/es/init.ts +++ b/x-pack/plugins/event_log/server/es/init.ts @@ -23,25 +23,10 @@ export async function initializeEs(esContext: EsContext): Promise { async function initializeEsResources(esContext: EsContext) { const steps = new EsInitializationSteps(esContext); - let ilmExists: boolean; - // create the ilm policy, if required - ilmExists = await steps.doesIlmPolicyExist(); - if (!ilmExists) { - ilmExists = await steps.createIlmPolicy(); - } - - if (!(await steps.doesIndexTemplateExist())) { - await steps.createIndexTemplate({ ilmExists }); - } - - if (!(await steps.doesInitialIndexExist())) { - await steps.createInitialIndex(); - } -} - -interface AddTemplateOpts { - ilmExists: boolean; + await steps.createIlmPolicyIfNotExists(); + await steps.createIndexTemplateIfNotExists(); + await steps.createInitialIndexIfNotExists(); } class EsInitializationSteps { @@ -49,89 +34,35 @@ class EsInitializationSteps { this.esContext = esContext; } - async doesIlmPolicyExist(): Promise { - const request = { - method: 'GET', - path: `_ilm/policy/${this.esContext.esNames.ilmPolicy}`, - }; - try { - await this.esContext.callEs('transport.request', request); - } catch (err) { - if (err.statusCode === 404) return false; - // TODO: remove following once kibana user can access ilm - if (err.statusCode === 403) return false; - - throw new Error(`error checking existance of ilm policy: ${err.message}`); - } - return true; - } - - async createIlmPolicy(): Promise { - const request = { - method: 'PUT', - path: `_ilm/policy/${this.esContext.esNames.ilmPolicy}`, - body: getIlmPolicy(), - }; - try { - await this.esContext.callEs('transport.request', request); - } catch (err) { - // TODO: remove following once kibana user can access ilm - if (err.statusCode === 403) return false; - throw new Error(`error creating ilm policy: ${err.message}`); + async createIlmPolicyIfNotExists(): Promise { + const exists = await this.esContext.esAdapter.doesIlmPolicyExist( + this.esContext.esNames.ilmPolicy + ); + if (!exists) { + await this.esContext.esAdapter.createIlmPolicy( + this.esContext.esNames.ilmPolicy, + getIlmPolicy() + ); } - return true; } - async doesIndexTemplateExist(): Promise { - const name = this.esContext.esNames.indexTemplate; - let result; - try { - result = await this.esContext.callEs('indices.existsTemplate', { name }); - } catch (err) { - throw new Error(`error checking existance of index template: ${err.message}`); + async createIndexTemplateIfNotExists(): Promise { + const exists = await this.esContext.esAdapter.doesIndexTemplateExist( + this.esContext.esNames.indexTemplate + ); + if (!exists) { + const templateBody = getIndexTemplate(this.esContext.esNames); + await this.esContext.esAdapter.createIndexTemplate( + this.esContext.esNames.indexTemplate, + templateBody + ); } - return result as boolean; } - async createIndexTemplate(opts: AddTemplateOpts): Promise { - const templateBody = getIndexTemplate(this.esContext.esNames, opts.ilmExists); - const addTemplateParams = { - create: true, - name: this.esContext.esNames.indexTemplate, - body: templateBody, - }; - try { - await this.esContext.callEs('indices.putTemplate', addTemplateParams); - } catch (err) { - throw new Error(`error creating index template: ${err.message}`); + async createInitialIndexIfNotExists(): Promise { + const exists = await this.esContext.esAdapter.doesAliasExist(this.esContext.esNames.alias); + if (!exists) { + await this.esContext.esAdapter.createIndex(this.esContext.esNames.initialIndex); } } - - async doesInitialIndexExist(): Promise { - const name = this.esContext.esNames.alias; - let result; - try { - result = await this.esContext.callEs('indices.existsAlias', { name }); - } catch (err) { - throw new Error(`error checking existance of initial index: ${err.message}`); - } - return result as boolean; - } - - async createInitialIndex(): Promise { - const index = this.esContext.esNames.initialIndex; - try { - await this.esContext.callEs('indices.create', { index }); - } catch (err) { - throw new Error(`error creating initial index: ${err.message}`); - } - } - - debug(message: string) { - this.esContext.logger.debug(message); - } - - warn(message: string) { - this.esContext.logger.warn(message); - } } diff --git a/x-pack/plugins/event_log/server/es/names.mock.ts b/x-pack/plugins/event_log/server/es/names.mock.ts new file mode 100644 index 0000000000000..7b013a0d263da --- /dev/null +++ b/x-pack/plugins/event_log/server/es/names.mock.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EsNames } from './names'; + +const createNamesMock = () => { + const mock: jest.Mocked = { + base: '.kibana', + alias: '.kibana-event-log', + ilmPolicy: '.kibana-event-log-policy', + indexPattern: '.kibana-event-log-*', + initialIndex: '.kibana-event-log-000001', + indexTemplate: '.kibana-event-log-template', + }; + return mock; +}; + +export const namesMock = { + create: createNamesMock, +}; diff --git a/x-pack/plugins/event_log/server/event_log_service.test.ts b/x-pack/plugins/event_log/server/event_log_service.test.ts index c7e752d1a652b..3b250b7462009 100644 --- a/x-pack/plugins/event_log/server/event_log_service.test.ts +++ b/x-pack/plugins/event_log/server/event_log_service.test.ts @@ -6,18 +6,14 @@ import { IEventLogConfig } from './types'; import { EventLogService } from './event_log_service'; -import { getEsNames } from './es/names'; -import { createMockEsContext } from './es/context.mock'; +import { contextMock } from './es/context.mock'; import { loggingServiceMock } from '../../../../src/core/server/logging/logging_service.mock'; const loggingService = loggingServiceMock.create(); const systemLogger = loggingService.get(); describe('EventLogService', () => { - const esContext = createMockEsContext({ - esNames: getEsNames('ABC'), - logger: systemLogger, - }); + const esContext = contextMock.create(); function getService(config: IEventLogConfig) { const { enabled, logEntries, indexEntries } = config; diff --git a/x-pack/plugins/event_log/server/event_logger.test.ts b/x-pack/plugins/event_log/server/event_logger.test.ts index c2de8d4dfd12b..673bac4f396e1 100644 --- a/x-pack/plugins/event_log/server/event_logger.test.ts +++ b/x-pack/plugins/event_log/server/event_logger.test.ts @@ -7,9 +7,8 @@ import { IEvent, IEventLogger, IEventLogService } from './index'; import { ECS_VERSION } from './types'; import { EventLogService } from './event_log_service'; -import { getEsNames } from './es/names'; import { EsContext } from './es/context'; -import { createMockEsContext } from './es/context.mock'; +import { contextMock } from './es/context.mock'; import { loggerMock, MockedLogger } from '../../../../src/core/server/logging/logger.mock'; import { delay } from './lib/delay'; import { EVENT_LOGGED_PREFIX } from './event_logger'; @@ -24,7 +23,7 @@ describe('EventLogger', () => { beforeEach(() => { systemLogger = loggerMock.create(); - esContext = createMockEsContext({ esNames: getEsNames('ABC'), logger: systemLogger }); + esContext = contextMock.create(); service = new EventLogService({ esContext, systemLogger, @@ -57,8 +56,6 @@ describe('EventLogger', () => { kibana: { server_uuid: '424-24-2424', }, - error: {}, - user: {}, }); const $timeStamp = event!['@timestamp']!; diff --git a/x-pack/plugins/event_log/server/event_logger.ts b/x-pack/plugins/event_log/server/event_logger.ts index 891abda947fc8..f5149da069953 100644 --- a/x-pack/plugins/event_log/server/event_logger.ts +++ b/x-pack/plugins/event_log/server/event_logger.ts @@ -171,7 +171,7 @@ function indexEventDoc(esContext: EsContext, doc: Doc): void { async function indexLogEventDoc(esContext: EsContext, doc: any) { esContext.logger.debug(`writing to event log: ${JSON.stringify(doc)}`); await esContext.waitTillReady(); - await esContext.callEs('index', doc); + await esContext.esAdapter.indexDocument(doc); esContext.logger.debug(`writing to event log complete`); } diff --git a/x-pack/plugins/event_log/server/plugin.ts b/x-pack/plugins/event_log/server/plugin.ts index e32d4ff6f7acc..fdb08b2d090a6 100644 --- a/x-pack/plugins/event_log/server/plugin.ts +++ b/x-pack/plugins/event_log/server/plugin.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Observable } from 'rxjs'; import { first } from 'rxjs/operators'; import { CoreSetup, @@ -12,6 +13,7 @@ import { Plugin as CorePlugin, PluginInitializerContext, ClusterClient, + SharedGlobalConfig, } from 'src/core/server'; import { IEventLogConfig, IEventLogService, IEventLogger, IEventLogConfig$ } from './types'; @@ -20,10 +22,8 @@ import { createEsContext, EsContext } from './es'; export type PluginClusterClient = Pick; -// TODO - figure out how to get ${kibana.index} for `.kibana` -const KIBANA_INDEX = '.kibana'; +const PROVIDER = 'eventLog'; -const PROVIDER = 'event_log'; const ACTIONS = { starting: 'starting', stopping: 'stopping', @@ -35,13 +35,18 @@ export class Plugin implements CorePlugin { private eventLogService?: IEventLogService; private esContext?: EsContext; private eventLogger?: IEventLogger; + private globalConfig$: Observable; constructor(private readonly context: PluginInitializerContext) { this.systemLogger = this.context.logger.get(); this.config$ = this.context.config.create(); + this.globalConfig$ = this.context.config.legacy.globalConfig$; } async setup(core: CoreSetup): Promise { + const globalConfig = await this.globalConfig$.pipe(first()).toPromise(); + const kibanaIndex = globalConfig.kibana.index; + this.systemLogger.debug('setting up plugin'); const config = await this.config$.pipe(first()).toPromise(); @@ -49,7 +54,7 @@ export class Plugin implements CorePlugin { this.esContext = createEsContext({ logger: this.systemLogger, // TODO: get index prefix from config.get(kibana.index) - indexNameRoot: KIBANA_INDEX, + indexNameRoot: kibanaIndex, clusterClient: core.elasticsearch.adminClient, }); @@ -84,7 +89,7 @@ export class Plugin implements CorePlugin { // will log the event after initialization this.eventLogger.logEvent({ event: { action: ACTIONS.starting }, - message: 'event_log starting', + message: 'eventLog starting', }); } @@ -97,7 +102,7 @@ export class Plugin implements CorePlugin { // when Kibana is actuaelly stopping, as it's written asynchronously this.eventLogger.logEvent({ event: { action: ACTIONS.stopping }, - message: 'event_log stopping', + message: 'eventLog stopping', }); } } diff --git a/x-pack/plugins/observability/public/components/action_menu.tsx b/x-pack/plugins/observability/public/components/action_menu.tsx index 6e964dde3aecf..a5f59ecd5506f 100644 --- a/x-pack/plugins/observability/public/components/action_menu.tsx +++ b/x-pack/plugins/observability/public/components/action_menu.tsx @@ -16,6 +16,7 @@ import { import React, { HTMLAttributes } from 'react'; import { EuiListGroupItemProps } from '@elastic/eui/src/components/list_group/list_group_item'; +import styled from 'styled-components'; type Props = EuiPopoverProps & HTMLAttributes; @@ -45,7 +46,12 @@ export const SectionLinks: React.FC<{}> = props => ( export const SectionSpacer: React.FC<{}> = () => ; -export const Section: React.FC<{}> = props => <>{props.children}; +export const Section = styled.div` + margin-bottom: 24px; + &:last-of-type { + margin-bottom: 0; + } +`; export type SectionLinkProps = EuiListGroupItemProps; export const SectionLink: React.FC = props => ( diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/constants.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/constants.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/constants.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/constants.js diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/index.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js similarity index 96% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/index.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js index 084a370666e45..d70ba2a21e176 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/index.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js @@ -8,7 +8,7 @@ import { setup as remoteClustersAddSetup } from './remote_clusters_add.helpers'; import { setup as remoteClustersEditSetup } from './remote_clusters_edit.helpers'; import { setup as remoteClustersListSetup } from './remote_clusters_list.helpers'; -export { nextTick, getRandomString, findTestSubject } from '../../../../../../test_utils'; +export { nextTick, getRandomString, findTestSubject } from '../../../../../test_utils'; export { setupEnvironment } from './setup_environment'; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js similarity index 66% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js index e573a4ebcef92..dd1d5d2187176 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_add.helpers.js @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed } from '../../../../../../test_utils'; -import { RemoteClusterAdd } from '../../../public/app/sections/remote_cluster_add'; -import { createRemoteClustersStore } from '../../../public/app/store'; -import { registerRouter } from '../../../public/app/services/routing'; +import { registerTestBed } from '../../../../../test_utils'; + +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import { RemoteClusterAdd } from '../../../public/application/sections/remote_cluster_add'; +import { createRemoteClustersStore } from '../../../public/application/store'; +import { registerRouter } from '../../../public/application/services/routing'; const testBedConfig = { store: createRemoteClustersStore, diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js similarity index 68% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js index 6a90ed6657c78..426aea90e5a99 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_edit.helpers.js @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed } from '../../../../../../test_utils'; -import { RemoteClusterEdit } from '../../../public/app/sections/remote_cluster_edit'; -import { createRemoteClustersStore } from '../../../public/app/store'; -import { registerRouter } from '../../../public/app/services/routing'; +import { registerTestBed } from '../../../../../test_utils'; + +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import { RemoteClusterEdit } from '../../../public/application/sections/remote_cluster_edit'; +import { createRemoteClustersStore } from '../../../public/application/store'; +import { registerRouter } from '../../../public/application/services/routing'; import { REMOTE_CLUSTER_EDIT_NAME } from './constants'; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js similarity index 88% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js index 0009bd84ffa6a..dc9b22b40542a 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_list.helpers.js @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed, findTestSubject } from '../../../../../../test_utils'; -import { RemoteClusterList } from '../../../public/app/sections/remote_cluster_list'; -import { createRemoteClustersStore } from '../../../public/app/store'; -import { registerRouter } from '../../../public/app/services/routing'; +import { registerTestBed, findTestSubject } from '../../../../../test_utils'; + +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import { RemoteClusterList } from '../../../public/application/sections/remote_cluster_list'; +import { createRemoteClustersStore } from '../../../public/application/store'; +import { registerRouter } from '../../../public/application/services/routing'; const testBedConfig = { store: createRemoteClustersStore, diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js new file mode 100644 index 0000000000000..c912a4ddabc9d --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js @@ -0,0 +1,48 @@ +/* + * 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 { + notificationServiceMock, + fatalErrorsServiceMock, + docLinksServiceMock, + injectedMetadataServiceMock, +} from '../../../../../../src/core/public/mocks'; + +import { usageCollectionPluginMock } from '../../../../../../src/plugins/usage_collection/public/mocks'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { HttpService } from '../../../../../../src/core/public/http'; + +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import { init as initBreadcrumb } from '../../../public/application/services/breadcrumb'; +import { init as initHttp } from '../../../public/application/services/http'; +import { init as initNotification } from '../../../public/application/services/notification'; +import { init as initUiMetric } from '../../../public/application/services/ui_metric'; +import { init as initDocumentation } from '../../../public/application/services/documentation'; +import { init as initHttpRequests } from './http_requests'; + +export const setupEnvironment = () => { + const httpServiceSetupMock = new HttpService().setup({ + injectedMetadata: injectedMetadataServiceMock.createSetupContract(), + fatalErrors: fatalErrorsServiceMock.createSetupContract(), + }); + + initBreadcrumb(() => {}); + initDocumentation(docLinksServiceMock.createStartContract()); + initUiMetric(usageCollectionPluginMock.createSetupContract()); + initNotification( + notificationServiceMock.createSetupContract().toasts, + fatalErrorsServiceMock.createSetupContract() + ); + initHttp(httpServiceSetupMock); + + const { server, httpRequestsMockHelpers } = initHttpRequests(); + + return { + server, + httpRequestsMockHelpers, + }; +}; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js similarity index 93% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js index 95dc65a96e30a..cab91854a5114 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js @@ -5,7 +5,7 @@ */ jest.mock('ui/new_platform'); -import { RemoteClusterForm } from '../../public/app/sections/components/remote_cluster_form'; +import { RemoteClusterForm } from '../../public/application/sections/components/remote_cluster_form'; import { pageHelpers, setupEnvironment, nextTick } from './helpers'; import { REMOTE_CLUSTER_EDIT, REMOTE_CLUSTER_EDIT_NAME } from './helpers/constants'; @@ -31,7 +31,7 @@ describe('Edit Remote cluster', () => { httpRequestsMockHelpers.setLoadRemoteClustersResponse([REMOTE_CLUSTER_EDIT]); ({ component, find, exists } = setup()); - await nextTick(); + await nextTick(100); // We need to wait next tick for the mock server response to kick in component.update(); }); diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js similarity index 96% rename from x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js index 699c00e450a1f..1b7c600218cee 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js @@ -12,7 +12,7 @@ import { findTestSubject, } from './helpers'; -import { getRouter } from '../../public/app/services'; +import { getRouter } from '../../public/application/services'; import { getRemoteClusterMock } from '../../fixtures/remote_cluster'; jest.mock('ui/new_platform'); @@ -39,11 +39,11 @@ describe('', () => { describe('on component mount', () => { let exists; - beforeEach(async () => { + beforeEach(() => { ({ exists } = setup()); }); - test('should show a "loading remote clusters" indicator', async () => { + test('should show a "loading remote clusters" indicator', () => { expect(exists('remoteClustersTableLoading')).toBe(true); }); }); @@ -55,7 +55,7 @@ describe('', () => { beforeEach(async () => { ({ exists, component } = setup()); - await nextTick(); // We need to wait next tick for the mock server response to kick in + await nextTick(100); // We need to wait next tick for the mock server response to kick in component.update(); }); @@ -97,7 +97,7 @@ describe('', () => { // Mount the component ({ component, find, exists, table, actions } = setup()); - await nextTick(); // Make sure that the Http request is fulfilled + await nextTick(100); // Make sure that the Http request is fulfilled component.update(); // Read the remote clusters list table @@ -206,7 +206,7 @@ describe('', () => { actions.clickBulkDeleteButton(); actions.clickConfirmModalDeleteRemoteCluster(); - await nextTick(550); // there is a 500ms timeout in the api action + await nextTick(600); // there is a 500ms timeout in the api action component.update(); ({ rows } = table.getMetaData('remoteClusterListTable')); diff --git a/x-pack/legacy/plugins/remote_clusters/fixtures/remote_cluster.js b/x-pack/plugins/remote_clusters/fixtures/remote_cluster.js similarity index 91% rename from x-pack/legacy/plugins/remote_clusters/fixtures/remote_cluster.js rename to x-pack/plugins/remote_clusters/fixtures/remote_cluster.js index 248e2b8232cad..e3e087548cf00 100644 --- a/x-pack/legacy/plugins/remote_clusters/fixtures/remote_cluster.js +++ b/x-pack/plugins/remote_clusters/fixtures/remote_cluster.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { getRandomString } from '../../../../test_utils'; +import { getRandomString } from '../../../test_utils'; export const getRemoteClusterMock = ({ name = getRandomString(), diff --git a/x-pack/plugins/remote_clusters/kibana.json b/x-pack/plugins/remote_clusters/kibana.json index de1e3d1e26865..27ae6802966dd 100644 --- a/x-pack/plugins/remote_clusters/kibana.json +++ b/x-pack/plugins/remote_clusters/kibana.json @@ -1,9 +1,17 @@ { "id": "remote_clusters", "version": "kibana", + "configPath": [ + "xpack", + "remote_clusters" + ], "requiredPlugins": [ - "licensing" + "licensing", + "management" + ], + "optionalPlugins": [ + "usageCollection" ], "server": true, - "ui": false + "ui": true } diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/app.js b/x-pack/plugins/remote_clusters/public/application/app.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/app.js rename to x-pack/plugins/remote_clusters/public/application/app.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/constants/index.ts b/x-pack/plugins/remote_clusters/public/application/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/constants/index.ts rename to x-pack/plugins/remote_clusters/public/application/constants/index.ts diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/constants/paths.ts b/x-pack/plugins/remote_clusters/public/application/constants/paths.ts similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/constants/paths.ts rename to x-pack/plugins/remote_clusters/public/application/constants/paths.ts diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/constants/ui_metric.ts b/x-pack/plugins/remote_clusters/public/application/constants/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/constants/ui_metric.ts rename to x-pack/plugins/remote_clusters/public/application/constants/ui_metric.ts diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/redirect.js b/x-pack/plugins/remote_clusters/public/application/index.d.ts similarity index 50% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/redirect.js rename to x-pack/plugins/remote_clusters/public/application/index.d.ts index ec77c2a2bfe99..b5c5ad5522134 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/redirect.js +++ b/x-pack/plugins/remote_clusters/public/application/index.d.ts @@ -4,14 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -// This depends upon Angular, which is why we use this provider pattern to access it within -// our React app. -let _redirect; +import { RegisterManagementAppArgs, I18nStart } from '../types'; -export function setRedirect(redirect) { - _redirect = redirect; -} - -export function redirect(path) { - _redirect(path); -} +export declare const renderApp: ( + elem: HTMLElement | null, + I18nContext: I18nStart['Context'] +) => ReturnType; diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/index.js b/x-pack/plugins/remote_clusters/public/application/index.js similarity index 80% rename from x-pack/legacy/plugins/remote_clusters/public/app/index.js rename to x-pack/plugins/remote_clusters/public/application/index.js index 2de59f4590553..0b8b26ace5daa 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/index.js +++ b/x-pack/plugins/remote_clusters/public/application/index.js @@ -5,14 +5,14 @@ */ import React from 'react'; -import { render } from 'react-dom'; +import { render, unmountComponentAtNode } from 'react-dom'; import { HashRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; import { App } from './app'; import { remoteClustersStore } from './store'; -export const renderReact = async (elem, I18nContext) => { +export const renderApp = (elem, I18nContext) => { render( @@ -23,4 +23,5 @@ export const renderReact = async (elem, I18nContext) => { , elem ); + return () => unmountComponentAtNode(elem); }; diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/configured_by_node_warning/configured_by_node_warning.js b/x-pack/plugins/remote_clusters/public/application/sections/components/configured_by_node_warning/configured_by_node_warning.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/configured_by_node_warning/configured_by_node_warning.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/configured_by_node_warning/configured_by_node_warning.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/configured_by_node_warning/index.js b/x-pack/plugins/remote_clusters/public/application/sections/components/configured_by_node_warning/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/configured_by_node_warning/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/configured_by_node_warning/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/index.js b/x-pack/plugins/remote_clusters/public/application/sections/components/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap similarity index 94% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap index 65fc455417fe3..45751997eb0d5 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap @@ -5,27 +5,28 @@ Array [
-
+
-

- Name -

+ + +
-
-
+
+
-

- Seed nodes for cluster discovery -

+ + +
-
-
+
+
-

- Make remote cluster optional -

+ + +
-
+
,
{cause[0]}

; } else { diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/remote_cluster_form.test.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/remote_cluster_form.test.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/request_flyout.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.js similarity index 97% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/request_flyout.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.js index deec26129abe5..70e2267001e3c 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/request_flyout.js +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.js @@ -26,7 +26,7 @@ import { EuiTitle, } from '@elastic/eui'; -import { serializeCluster } from '../../../../../common'; +import { serializeCluster } from '../../../../../common/constants'; export class RequestFlyout extends PureComponent { static propTypes = { diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/__snapshots__/validate_name.test.js.snap b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/__snapshots__/validate_name.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/__snapshots__/validate_name.test.js.snap rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/__snapshots__/validate_name.test.js.snap diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/__snapshots__/validate_seeds.test.js.snap b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/__snapshots__/validate_seeds.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/__snapshots__/validate_seeds.test.js.snap rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/__snapshots__/validate_seeds.test.js.snap diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/index.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_name.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_name.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_name.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_name.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_name.test.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_name.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_name.test.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_name.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seed.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seed.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seed.test.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seed.test.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seeds.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seeds.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seeds.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seeds.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seeds.test.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seeds.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/validators/validate_seeds.test.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seeds.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_page_title/index.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_page_title/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_page_title/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_page_title/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_page_title/remote_cluster_page_title.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_page_title/remote_cluster_page_title.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_page_title/remote_cluster_page_title.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_page_title/remote_cluster_page_title.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/index.js b/x-pack/plugins/remote_clusters/public/application/sections/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/remote_cluster_add.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/remote_cluster_add.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/remote_cluster_add.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_add/remote_cluster_add.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/remote_cluster_edit.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/remote_cluster_edit.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/remote_cluster_edit.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_edit/remote_cluster_edit.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/connection_status.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/connection_status/connection_status.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/connection_status.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/connection_status/connection_status.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/connection_status/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/connection_status/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/connection_status/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/detail_panel.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/detail_panel.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/detail_panel.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/detail_panel.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/detail_panel.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/detail_panel.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/detail_panel.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/detail_panel/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/detail_panel/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_list.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_list.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_list.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_list.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_list.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_list.js similarity index 98% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_list.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_list.js index dea6bc7627cc1..207aa8045c011 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_list.js +++ b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_list.js @@ -145,9 +145,9 @@ export class RemoteClusterList extends Component { } renderError(error) { - // We can safely depend upon the shape of this error coming from Angular $http, because we + // We can safely depend upon the shape of this error coming from http service, because we // handle unexpected error shapes in the API action. - const { statusCode, error: errorString } = error.data; + const { statusCode, error: errorString } = error.body; const title = i18n.translate('xpack.remoteClusters.remoteClusterList.loadingErrorTitle', { defaultMessage: 'Error loading remote clusters', diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/index.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.container.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.container.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.container.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.container.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.js rename to x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/remote_cluster_table/remote_cluster_table.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/api.js b/x-pack/plugins/remote_clusters/public/application/services/api.js similarity index 93% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/api.js rename to x-pack/plugins/remote_clusters/public/application/services/api.js index 8631bc5af12a8..72d5e3f9c3f9e 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/api.js +++ b/x-pack/plugins/remote_clusters/public/application/services/api.js @@ -9,19 +9,19 @@ import { trackUserRequest } from './ui_metric'; import { sendGet, sendPost, sendPut, sendDelete } from './http'; export async function loadClusters() { - const response = await sendGet(); - return response.data; + return await sendGet(); } export async function addCluster(cluster) { const request = sendPost('', cluster); + return await trackUserRequest(request, UIM_CLUSTER_ADD); } export async function editCluster(cluster) { const { name, ...rest } = cluster; - const request = sendPut(name, rest); + return await trackUserRequest(request, UIM_CLUSTER_UPDATE); } diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/api_errors.js b/x-pack/plugins/remote_clusters/public/application/services/api_errors.js similarity index 77% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/api_errors.js rename to x-pack/plugins/remote_clusters/public/application/services/api_errors.js index c50ad92532071..8376f37f36f49 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/api_errors.js +++ b/x-pack/plugins/remote_clusters/public/application/services/api_errors.js @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fatalError, toasts } from './notification'; +import { toasts, fatalError } from './notification'; function createToastConfig(error, errorTitle) { - // Expect an error in the shape provided by Angular's $http service. - if (error && error.data) { - const { error: errorString, statusCode, message } = error.data; + // Expect an error in the shape provided by http service. + if (error && error.body) { + const { error: errorString, statusCode, message } = error.body; return { title: errorTitle, text: `${statusCode}: ${errorString}. ${message}`, @@ -26,7 +26,7 @@ export function showApiWarning(error, errorTitle) { // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - return fatalError(error, errorTitle); + return fatalError.add(error, errorTitle); } export function showApiError(error, errorTitle) { @@ -38,5 +38,5 @@ export function showApiError(error, errorTitle) { // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - fatalError(error, errorTitle); + fatalError.add(error, errorTitle); } diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/breadcrumb.ts b/x-pack/plugins/remote_clusters/public/application/services/breadcrumb.ts similarity index 68% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/breadcrumb.ts rename to x-pack/plugins/remote_clusters/public/application/services/breadcrumb.ts index 68d34cc2a17d4..f90a0d3456166 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/breadcrumb.ts +++ b/x-pack/plugins/remote_clusters/public/application/services/breadcrumb.ts @@ -8,13 +8,22 @@ import { i18n } from '@kbn/i18n'; import { CRUD_APP_BASE_PATH } from '../constants'; -let _setBreadcrumbs: any; -let _breadcrumbs: any; +interface Breadcrumb { + text: string; + href?: string; +} +interface Breadcrumbs { + home: Breadcrumb; + add: Breadcrumb; + edit: Breadcrumb; +} + +let _setBreadcrumbs: (breadcrumbs: Breadcrumb[]) => void; +let _breadcrumbs: Breadcrumbs; -export function init(setGlobalBreadcrumbs: any, managementBreadcrumb: any): void { +export function init(setGlobalBreadcrumbs: (breadcrumbs: Breadcrumb[]) => void): void { _setBreadcrumbs = setGlobalBreadcrumbs; _breadcrumbs = { - management: managementBreadcrumb, home: { text: i18n.translate('xpack.remoteClusters.listBreadcrumbTitle', { defaultMessage: 'Remote Clusters', @@ -34,13 +43,13 @@ export function init(setGlobalBreadcrumbs: any, managementBreadcrumb: any): void }; } -export function setBreadcrumbs(type: string, queryParams?: string): void { +export function setBreadcrumbs(type: 'home' | 'add' | 'edit', queryParams?: string): void { if (!_breadcrumbs[type]) { return; } if (type === 'home') { - _setBreadcrumbs([_breadcrumbs.management, _breadcrumbs.home]); + _setBreadcrumbs([_breadcrumbs.home]); } else { // Support deep-linking back to a remote cluster in the detail panel. const homeBreadcrumb = { @@ -48,6 +57,6 @@ export function setBreadcrumbs(type: string, queryParams?: string): void { href: `${_breadcrumbs.home.href}${queryParams}`, }; - _setBreadcrumbs([_breadcrumbs.management, homeBreadcrumb, _breadcrumbs[type]]); + _setBreadcrumbs([homeBreadcrumb, _breadcrumbs[type]]); } } diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/documentation.ts b/x-pack/plugins/remote_clusters/public/application/services/documentation.ts similarity index 70% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/documentation.ts rename to x-pack/plugins/remote_clusters/public/application/services/documentation.ts index 4d04aa6fad74d..38cf2223a313b 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/documentation.ts +++ b/x-pack/plugins/remote_clusters/public/application/services/documentation.ts @@ -4,11 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { DocLinksStart } from 'kibana/public'; + export let skippingDisconnectedClustersUrl: string; export let remoteClustersUrl: string; export let transportPortUrl: string; -export function init(esDocBasePath: string): void { +export function init(docLinks: DocLinksStart): void { + const { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL } = docLinks; + const esDocBasePath = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}`; + skippingDisconnectedClustersUrl = `${esDocBasePath}/modules-cross-cluster-search.html#_skipping_disconnected_clusters`; remoteClustersUrl = `${esDocBasePath}/modules-remote-clusters.html`; transportPortUrl = `${esDocBasePath}/modules-transport.html`; diff --git a/x-pack/plugins/remote_clusters/public/application/services/http.ts b/x-pack/plugins/remote_clusters/public/application/services/http.ts new file mode 100644 index 0000000000000..b49e95f3a5c65 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/services/http.ts @@ -0,0 +1,55 @@ +/* + * 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 { HttpSetup, HttpResponse } from 'kibana/public'; +import { API_BASE_PATH } from '../../../common/constants'; + +let _httpClient: HttpSetup; + +export function init(httpClient: HttpSetup): void { + _httpClient = httpClient; +} + +export function getFullPath(path: string): string { + if (path) { + return `${API_BASE_PATH}/${path}`; + } + + return API_BASE_PATH; +} + +export function sendPost( + path: string, + payload: { + name: string; + seeds: string[]; + skipUnavailable: boolean; + } +): Promise { + return _httpClient.post(getFullPath(path), { + body: JSON.stringify(payload), + }); +} + +export function sendGet(path: string): Promise { + return _httpClient.get(getFullPath(path)); +} + +export function sendPut( + path: string, + payload: { + seeds: string[]; + skipUnavailable: boolean; + } +): Promise { + return _httpClient.put(getFullPath(path), { + body: JSON.stringify(payload), + }); +} + +export function sendDelete(path: string): Promise { + return _httpClient.delete(getFullPath(path)); +} diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/index.js b/x-pack/plugins/remote_clusters/public/application/services/index.js similarity index 93% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/index.js rename to x-pack/plugins/remote_clusters/public/application/services/index.js index 69679e55dfef5..031770d9500ed 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/index.js +++ b/x-pack/plugins/remote_clusters/public/application/services/index.js @@ -8,7 +8,7 @@ export { loadClusters, addCluster, editCluster, removeClusterRequest } from './a export { showApiError, showApiWarning } from './api_errors'; -export { setRedirect, redirect } from './redirect'; +export { initRedirect, redirect } from './redirect'; export { isSeedNodeValid, isSeedNodePortValid } from './validate_seed_node'; diff --git a/x-pack/plugins/remote_clusters/public/application/services/notification.ts b/x-pack/plugins/remote_clusters/public/application/services/notification.ts new file mode 100644 index 0000000000000..1c9173e519b48 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/services/notification.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { NotificationsSetup, FatalErrorsSetup } from 'src/core/public'; + +export let toasts: NotificationsSetup['toasts']; +export let fatalError: FatalErrorsSetup; + +export function init(_toasts: NotificationsSetup['toasts'], _fatalError: FatalErrorsSetup): void { + toasts = _toasts; + fatalError = _fatalError; +} diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/query_params.js b/x-pack/plugins/remote_clusters/public/application/services/query_params.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/query_params.js rename to x-pack/plugins/remote_clusters/public/application/services/query_params.js diff --git a/x-pack/plugins/remote_clusters/public/application/services/redirect.ts b/x-pack/plugins/remote_clusters/public/application/services/redirect.ts new file mode 100644 index 0000000000000..00a97fa74c5ce --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/services/redirect.ts @@ -0,0 +1,17 @@ +/* + * 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 { CoreStart } from 'kibana/public'; + +let navigateToApp: CoreStart['application']['navigateToApp']; + +export function init(_navigateToApp: CoreStart['application']['navigateToApp']) { + navigateToApp = _navigateToApp; +} + +export function redirect(path: string) { + navigateToApp('kibana', { path: `#${path}` }); +} diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/routing.js b/x-pack/plugins/remote_clusters/public/application/services/routing.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/routing.js rename to x-pack/plugins/remote_clusters/public/application/services/routing.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/ui_metric.ts b/x-pack/plugins/remote_clusters/public/application/services/ui_metric.ts similarity index 62% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/ui_metric.ts rename to x-pack/plugins/remote_clusters/public/application/services/ui_metric.ts index 36a23476c1873..91354155cacb0 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/services/ui_metric.ts +++ b/x-pack/plugins/remote_clusters/public/application/services/ui_metric.ts @@ -4,17 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; +import { UiStatsMetricType } from '@kbn/analytics'; import { UIM_APP_NAME } from '../constants'; -import { - createUiStatsReporter, - METRIC_TYPE, -} from '../../../../../../../src/legacy/core_plugins/ui_metric/public'; -export let trackUiMetric: ReturnType; -export { METRIC_TYPE }; +export let trackUiMetric: (metricType: UiStatsMetricType, eventName: string) => void; +export let METRIC_TYPE: UsageCollectionSetup['METRIC_TYPE']; -export function init(getReporter: typeof createUiStatsReporter): void { - trackUiMetric = getReporter(UIM_APP_NAME); +export function init(usageCollection: UsageCollectionSetup): void { + trackUiMetric = usageCollection.reportUiStats.bind(usageCollection, UIM_APP_NAME); + METRIC_TYPE = usageCollection.METRIC_TYPE; } /** diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/validate_seed_node.js b/x-pack/plugins/remote_clusters/public/application/services/validate_seed_node.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/validate_seed_node.js rename to x-pack/plugins/remote_clusters/public/application/services/validate_seed_node.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/services/validate_seed_node.test.js b/x-pack/plugins/remote_clusters/public/application/services/validate_seed_node.test.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/services/validate_seed_node.test.js rename to x-pack/plugins/remote_clusters/public/application/services/validate_seed_node.test.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/action_types.js b/x-pack/plugins/remote_clusters/public/application/store/action_types.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/action_types.js rename to x-pack/plugins/remote_clusters/public/application/store/action_types.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/add_cluster.js b/x-pack/plugins/remote_clusters/public/application/store/actions/add_cluster.js similarity index 88% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/add_cluster.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/add_cluster.js index 726bc56b08f12..0b7838f48b137 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/add_cluster.js +++ b/x-pack/plugins/remote_clusters/public/application/store/actions/add_cluster.js @@ -35,12 +35,12 @@ export const addCluster = cluster => async dispatch => { ]); } catch (error) { if (error) { - const { statusCode, data } = error; + const { body } = error; - // Expect an error in the shape provided by Angular's $http service. - if (data) { - // Some errors have statusCode directly available but some are under a data property. - if ((statusCode || (data && data.statusCode)) === 409) { + // Expect an error in the shape provided by http service. + if (body) { + const { statusCode, message } = body; + if (statusCode && statusCode === 409) { return dispatch({ type: ADD_CLUSTER_FAILURE, payload: { @@ -63,9 +63,8 @@ export const addCluster = cluster => async dispatch => { error: { message: i18n.translate('xpack.remoteClusters.addAction.failedDefaultErrorMessage', { defaultMessage: 'Request failed with a {statusCode} error. {message}', - values: { statusCode, message: data.message }, + values: { statusCode, message }, }), - cause: data.cause, }, }, }); @@ -74,7 +73,7 @@ export const addCluster = cluster => async dispatch => { // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - return fatalError( + return fatalError.add( error, i18n.translate('xpack.remoteClusters.addAction.errorTitle', { defaultMessage: 'Error adding cluster', diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/detail_panel.js b/x-pack/plugins/remote_clusters/public/application/store/actions/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/detail_panel.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/detail_panel.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/edit_cluster.js b/x-pack/plugins/remote_clusters/public/application/store/actions/edit_cluster.js similarity index 90% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/edit_cluster.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/edit_cluster.js index 3ed481aa0f8ea..062704472521e 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/edit_cluster.js +++ b/x-pack/plugins/remote_clusters/public/application/store/actions/edit_cluster.js @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; -import { fatalError, toasts } from '../../services/notification'; +import { toasts, fatalError } from '../../services/notification'; import { CRUD_APP_BASE_PATH } from '../../constants'; import { loadClusters } from './load_clusters'; @@ -39,19 +39,19 @@ export const editCluster = cluster => async dispatch => { ]); } catch (error) { if (error) { - const { statusCode, data } = error; + const { body } = error; - // Expect an error in the shape provided by Angular's $http service. - if (data) { + // Expect an error in the shape provided by http service. + if (body) { + const { statusCode, message } = body; return dispatch({ type: EDIT_CLUSTER_FAILURE, payload: { error: { message: i18n.translate('xpack.remoteClusters.editAction.failedDefaultErrorMessage', { defaultMessage: 'Request failed with a {statusCode} error. {message}', - values: { statusCode, message: data.message }, + values: { statusCode, message }, }), - cause: data.cause, }, }, }); @@ -60,7 +60,7 @@ export const editCluster = cluster => async dispatch => { // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - return fatalError( + return fatalError.add( error, i18n.translate('xpack.remoteClusters.editAction.errorTitle', { defaultMessage: 'Error editing cluster', diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/index.js b/x-pack/plugins/remote_clusters/public/application/store/actions/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/index.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/load_clusters.js b/x-pack/plugins/remote_clusters/public/application/store/actions/load_clusters.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/load_clusters.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/load_clusters.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/refresh_clusters.js b/x-pack/plugins/remote_clusters/public/application/store/actions/refresh_clusters.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/refresh_clusters.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/refresh_clusters.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/remove_clusters.js b/x-pack/plugins/remote_clusters/public/application/store/actions/remove_clusters.js similarity index 95% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/actions/remove_clusters.js rename to x-pack/plugins/remote_clusters/public/application/store/actions/remove_clusters.js index 4086a91e29021..8e22eac8b292b 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/store/actions/remove_clusters.js +++ b/x-pack/plugins/remote_clusters/public/application/store/actions/remove_clusters.js @@ -30,7 +30,7 @@ function getErrorTitle(count, name = null) { } } else { return i18n.translate('xpack.remoteClusters.removeAction.errorMultipleNotificationTitle', { - defaultMessage: `Error removing '{count}' remote clusters`, + defaultMessage: `Error removing {count} remote clusters`, values: { count }, }); } @@ -46,7 +46,7 @@ export const removeClusters = names => async (dispatch, getState) => { await Promise.all([ sendRemoveClusterRequest(names.join(',')).then(response => { - ({ itemsDeleted, errors } = response.data); + ({ itemsDeleted, errors } = response); }), // Wait at least half a second to avoid a weird flicker of the saving feedback (only visible // when requests resolve very quickly). @@ -55,7 +55,7 @@ export const removeClusters = names => async (dispatch, getState) => { const errorTitle = getErrorTitle(names.length, names[0]); toasts.addDanger({ title: errorTitle, - text: error.data.message, + text: error.body?.message, }); }); diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/index.js b/x-pack/plugins/remote_clusters/public/application/store/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/index.js rename to x-pack/plugins/remote_clusters/public/application/store/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/middleware/detail_panel.js b/x-pack/plugins/remote_clusters/public/application/store/middleware/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/middleware/detail_panel.js rename to x-pack/plugins/remote_clusters/public/application/store/middleware/detail_panel.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/middleware/index.js b/x-pack/plugins/remote_clusters/public/application/store/middleware/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/middleware/index.js rename to x-pack/plugins/remote_clusters/public/application/store/middleware/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/add_cluster.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/add_cluster.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/add_cluster.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/add_cluster.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/clusters.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/clusters.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/clusters.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/clusters.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/detail_panel.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/detail_panel.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/detail_panel.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/edit_cluster.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/edit_cluster.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/edit_cluster.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/edit_cluster.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/index.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/index.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/remove_cluster.js b/x-pack/plugins/remote_clusters/public/application/store/reducers/remove_cluster.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/reducers/remove_cluster.js rename to x-pack/plugins/remote_clusters/public/application/store/reducers/remove_cluster.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/selectors/index.js b/x-pack/plugins/remote_clusters/public/application/store/selectors/index.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/selectors/index.js rename to x-pack/plugins/remote_clusters/public/application/store/selectors/index.js diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/store/store.js b/x-pack/plugins/remote_clusters/public/application/store/store.js similarity index 100% rename from x-pack/legacy/plugins/remote_clusters/public/app/store/store.js rename to x-pack/plugins/remote_clusters/public/application/store/store.js diff --git a/x-pack/plugins/remote_clusters/public/index.ts b/x-pack/plugins/remote_clusters/public/index.ts new file mode 100644 index 0000000000000..dbe22b71b48df --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { RemoteClustersUIPlugin } from './plugin'; + +export const plugin = () => new RemoteClustersUIPlugin(); diff --git a/x-pack/plugins/remote_clusters/public/plugin.ts b/x-pack/plugins/remote_clusters/public/plugin.ts new file mode 100644 index 0000000000000..5b84fa1fde369 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/plugin.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { CoreSetup, Plugin, CoreStart } from 'kibana/public'; +import { init as initBreadcrumbs } from './application/services/breadcrumb'; +import { init as initDocumentation } from './application/services/documentation'; +import { init as initHttp } from './application/services/http'; +import { init as initUiMetric } from './application/services/ui_metric'; +import { init as initNotification } from './application/services/notification'; +import { init as initRedirect } from './application/services/redirect'; +import { Dependencies } from './types'; + +export class RemoteClustersUIPlugin implements Plugin { + setup( + { notifications: { toasts }, http, getStartServices }: CoreSetup, + { management, usageCollection }: Dependencies + ) { + const esSection = management.sections.getSection('elasticsearch'); + + esSection!.registerApp({ + id: 'remote_clusters', + title: i18n.translate('xpack.remoteClusters.appTitle', { + defaultMessage: 'Remote Clusters', + }), + mount: async ({ element, setBreadcrumbs }) => { + const [core] = await getStartServices(); + const { + i18n: { Context: i18nContext }, + docLinks, + fatalErrors, + } = core; + + // Initialize services + initBreadcrumbs(setBreadcrumbs); + initDocumentation(docLinks); + initUiMetric(usageCollection); + initNotification(toasts, fatalErrors); + initHttp(http); + + const { renderApp } = await import('./application'); + return renderApp(element, i18nContext); + }, + }); + } + + start({ application }: CoreStart) { + initRedirect(application.navigateToApp); + } + + stop() {} +} diff --git a/x-pack/plugins/remote_clusters/public/types.ts b/x-pack/plugins/remote_clusters/public/types.ts new file mode 100644 index 0000000000000..45ae90f91587a --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/types.ts @@ -0,0 +1,19 @@ +/* + * 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 { ManagementSetup } from 'src/plugins/management/public'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; +import { RegisterManagementAppArgs } from 'src/plugins/management/public'; +import { I18nStart } from 'kibana/public'; + +export interface Dependencies { + management: ManagementSetup; + usageCollection: UsageCollectionSetup; +} + +export { RegisterManagementAppArgs }; + +export { I18nStart }; diff --git a/x-pack/plugins/remote_clusters/server/config.ts b/x-pack/plugins/remote_clusters/server/config.ts new file mode 100644 index 0000000000000..9525fe1e2a0db --- /dev/null +++ b/x-pack/plugins/remote_clusters/server/config.ts @@ -0,0 +1,21 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { PluginConfigDescriptor } from 'kibana/server'; + +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type ConfigType = TypeOf; + +export const config: PluginConfigDescriptor = { + schema: configSchema, + exposeToBrowser: { + enabled: true, + }, +}; diff --git a/x-pack/plugins/remote_clusters/server/index.ts b/x-pack/plugins/remote_clusters/server/index.ts index 896161d82919b..927fa768fc9fd 100644 --- a/x-pack/plugins/remote_clusters/server/index.ts +++ b/x-pack/plugins/remote_clusters/server/index.ts @@ -6,4 +6,6 @@ import { PluginInitializerContext } from 'kibana/server'; import { RemoteClustersServerPlugin } from './plugin'; +export { config } from './config'; + export const plugin = (ctx: PluginInitializerContext) => new RemoteClustersServerPlugin(ctx); diff --git a/x-pack/plugins/remote_clusters/server/plugin.ts b/x-pack/plugins/remote_clusters/server/plugin.ts index dd0bb536d2695..d15ae44c8d5db 100644 --- a/x-pack/plugins/remote_clusters/server/plugin.ts +++ b/x-pack/plugins/remote_clusters/server/plugin.ts @@ -6,10 +6,12 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; -import { PLUGIN } from '../common/constants'; +import { Observable } from 'rxjs'; import { LICENSE_CHECK_STATE } from '../../licensing/common/types'; -import { Dependencies, LicenseStatus, RouteDependencies } from './types'; +import { PLUGIN } from '../common/constants'; +import { Dependencies, LicenseStatus, RouteDependencies } from './types'; +import { ConfigType } from './config'; import { registerGetRoute, registerAddRoute, @@ -20,9 +22,11 @@ import { export class RemoteClustersServerPlugin implements Plugin { licenseStatus: LicenseStatus; log: Logger; + config: Observable; - constructor({ logger }: PluginInitializerContext) { + constructor({ logger, config }: PluginInitializerContext) { this.log = logger.get(); + this.config = config.create(); this.licenseStatus = { valid: false }; } diff --git a/x-pack/plugins/remote_clusters/server/routes/api/add_route.ts b/x-pack/plugins/remote_clusters/server/routes/api/add_route.ts index aa09b6bf45667..e4ede01ca23ea 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/add_route.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/add_route.ts @@ -38,8 +38,7 @@ export const register = (deps: RouteDependencies): void => { // Check if cluster already exists. const existingCluster = await doesClusterExist(callAsCurrentUser, name); if (existingCluster) { - return response.customError({ - statusCode: 409, + return response.conflict({ body: { message: i18n.translate( 'xpack.remoteClusters.addRemoteCluster.existingRemoteClusterErrorMessage', diff --git a/x-pack/plugins/remote_clusters/server/routes/api/update_route.ts b/x-pack/plugins/remote_clusters/server/routes/api/update_route.ts index fd707f15ad11e..ed584307d84c1 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/update_route.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/update_route.ts @@ -44,8 +44,7 @@ export const register = (deps: RouteDependencies): void => { // Check if cluster does exist. const existingCluster = await doesClusterExist(callAsCurrentUser, name); if (!existingCluster) { - return response.customError({ - statusCode: 404, + return response.notFound({ body: { message: i18n.translate( 'xpack.remoteClusters.updateRemoteCluster.noRemoteClusterErrorMessage', diff --git a/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx b/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx index 90617ba1c5167..aa6c20aa6a7f3 100644 --- a/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx +++ b/x-pack/plugins/searchprofiler/public/application/containers/main/main.tsx @@ -5,7 +5,6 @@ */ import React, { useCallback } from 'react'; -import _ from 'lodash'; import { EuiPage, diff --git a/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx b/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx index a70d70f117edb..ad56b3957eb74 100644 --- a/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx +++ b/x-pack/plugins/searchprofiler/public/application/editor/editor.test.tsx @@ -6,9 +6,7 @@ import 'brace'; import 'brace/mode/json'; -jest.mock('./worker', () => { - return { workerModule: { id: 'ace/mode/json_worker', src: '' } }; -}); +import '../../../../es_ui_shared/console_lang/mocks'; import { registerTestBed } from '../../../../../test_utils'; import { Editor, Props } from '.'; diff --git a/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts b/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts index e5aad16bc4af2..6f19ce12eb639 100644 --- a/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts +++ b/x-pack/plugins/searchprofiler/public/application/editor/init_editor.ts @@ -5,7 +5,7 @@ */ import ace from 'brace'; -import { installXJsonMode } from './x_json_mode'; +import { installXJsonMode } from '../../../../es_ui_shared/console_lang'; export function initializeEditor({ el, diff --git a/x-pack/plugins/searchprofiler/public/application/editor/x_json_highlight_rules.ts b/x-pack/plugins/searchprofiler/public/application/editor/x_json_highlight_rules.ts deleted file mode 100644 index 1e6e774db2e52..0000000000000 --- a/x-pack/plugins/searchprofiler/public/application/editor/x_json_highlight_rules.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ace from 'brace'; -const oop = ace.acequire('ace/lib/oop'); -const { JsonHighlightRules } = ace.acequire('ace/mode/json_highlight_rules'); -const { TextHighlightRules } = ace.acequire('ace/mode/text_highlight_rules'); - -/* - * The rules below were copied from ./src/legacy/core_plugins/console/public/src/sense_editor/mode/x_json_highlight_rules.js - * - * It is very likely that this code will move (or be removed) in future but for now - * it enables syntax highlight for extended json. - */ - -const xJsonRules = { - start: [ - { - token: [ - 'variable', - 'whitespace', - 'ace.punctuation.colon', - 'whitespace', - 'punctuation.start_triple_quote', - ], - regex: '("(?:[^"]*_)?script"|"inline"|"source")(\\s*?)(:)(\\s*?)(""")', - next: 'script-start', - merge: false, - push: true, - }, - { - token: 'variable', // single line - regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)', - }, - { - token: 'punctuation.start_triple_quote', - regex: '"""', - next: 'string_literal', - merge: false, - push: true, - }, - { - token: 'string', // single line - regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]', - }, - { - token: 'constant.numeric', // hex - regex: '0[xX][0-9a-fA-F]+\\b', - }, - { - token: 'constant.numeric', // float - regex: '[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b', - }, - { - token: 'constant.language.boolean', - regex: '(?:true|false)\\b', - }, - { - token: 'invalid.illegal', // single quoted strings are not allowed - regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']", - }, - { - token: 'invalid.illegal', // comments are not allowed - regex: '\\/\\/.*$', - }, - { - token: 'paren.lparen', - merge: false, - regex: '{', - next: 'start', - push: true, - }, - { - token: 'paren.lparen', - merge: false, - regex: '[[(]', - }, - { - token: 'paren.rparen', - merge: false, - regex: '[\\])]', - }, - { - token: 'paren.rparen', - regex: '}', - merge: false, - next: 'pop', - }, - { - token: 'punctuation.comma', - regex: ',', - }, - { - token: 'punctuation.colon', - regex: ':', - }, - { - token: 'whitespace', - regex: '\\s+', - }, - { - token: 'text', - regex: '.+?', - }, - ], - string_literal: [ - { - token: 'punctuation.end_triple_quote', - regex: '"""', - next: 'pop', - }, - { - token: 'multi_string', - regex: '.', - }, - ], -}; - -function XJsonHighlightRules(this: any) { - this.$rules = xJsonRules; -} - -oop.inherits(XJsonHighlightRules, JsonHighlightRules); - -export function getRules() { - const ruleset: any = new (XJsonHighlightRules as any)(); - ruleset.embedRules(TextHighlightRules, 'text-', [ - { - token: 'punctuation.end_triple_quote', - regex: '"""', - next: 'pop', - }, - ]); - ruleset.normalizeRules(); - return ruleset.getRules(); -} diff --git a/x-pack/plugins/searchprofiler/public/application/editor/x_json_mode.ts b/x-pack/plugins/searchprofiler/public/application/editor/x_json_mode.ts deleted file mode 100644 index 7ac1e6105d97f..0000000000000 --- a/x-pack/plugins/searchprofiler/public/application/editor/x_json_mode.ts +++ /dev/null @@ -1,54 +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. - */ - -// Copied and modified from src/legacy/core_plugins/console/public/src/sense_editor/mode/input.js - -import ace from 'brace'; - -import * as xJsonRules from './x_json_highlight_rules'; -import { workerModule } from './worker'; - -const oop = ace.acequire('ace/lib/oop'); -const { Mode: JSONMode } = ace.acequire('ace/mode/json'); -const { Tokenizer: AceTokenizer } = ace.acequire('ace/tokenizer'); -const { MatchingBraceOutdent } = ace.acequire('ace/mode/matching_brace_outdent'); -const { CstyleBehaviour } = ace.acequire('ace/mode/behaviour/cstyle'); -const { FoldMode: CStyleFoldMode } = ace.acequire('ace/mode/folding/cstyle'); -const { WorkerClient } = ace.acequire('ace/worker/worker_client'); - -function XJsonMode(this: any) { - this.$tokenizer = new AceTokenizer(xJsonRules.getRules()); - this.$outdent = new MatchingBraceOutdent(); - this.$behaviour = new CstyleBehaviour(); - this.foldingRules = new CStyleFoldMode(); -} - -// Order here matters here: - -// 1. We first inherit -oop.inherits(XJsonMode, JSONMode); - -// 2. Then clobber `createWorker` method to install our worker source. Per ace's wiki: https://github.com/ajaxorg/ace/wiki/Syntax-validation -XJsonMode.prototype.createWorker = function(session: ace.IEditSession) { - const xJsonWorker = new WorkerClient(['ace'], workerModule, 'JsonWorker'); - - xJsonWorker.attachToDocument(session.getDocument()); - - xJsonWorker.on('annotate', function(e: { data: any }) { - session.setAnnotations(e.data); - }); - - xJsonWorker.on('terminate', function() { - session.clearAnnotations(); - }); - - return xJsonWorker; -}; - -export function installXJsonMode(editor: ace.Editor) { - const session = editor.getSession(); - session.setMode(new (XJsonMode as any)()); -} diff --git a/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts b/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts index 4267fd0d2f901..99687de0f1440 100644 --- a/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts +++ b/x-pack/plugins/searchprofiler/public/application/utils/check_for_json_errors.ts @@ -4,12 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// Convert triple quotes into regular quotes and escape internal quotes. -function collapseLiteralStrings(data: string) { - return data.replace(/"""(?:\s*\r?\n)?((?:.|\r?\n)*?)(?:\r?\n\s*)?"""/g, function(match, literal) { - return JSON.stringify(literal); - }); -} +import { collapseLiteralStrings } from '../../../../../../src/plugins/es_ui_shared/console_lang/lib'; export function checkForParseErrors(json: string) { const sanitizedJson = collapseLiteralStrings(json); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap index 323629de7578d..2a00c7ca5c347 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap @@ -26,8 +26,6 @@ exports[`it renders without crashing 1`] = `

} - fullWidth={false} - gutterSize="l" title={

} - titleSize="xs" >

} - fullWidth={false} - gutterSize="l" title={

} - titleSize="xs" > renders without crashing 1`] = ` />

} - fullWidth={false} - gutterSize="l" title={

renders without crashing 1`] = ` />

} - titleSize="xs" > { +describe('#logout', () => { const mockGetItem = jest.fn().mockReturnValue(null); + const CURRENT_URL = '/foo/bar?baz=quz#quuz'; + const LOGOUT_URL = '/logout'; + const TENANT = '/some-basepath'; + + let newUrlPromise: Promise; beforeAll(() => { Object.defineProperty(window, 'sessionStorage', { @@ -19,69 +23,42 @@ describe('Session Expiration', () => { }); }); + beforeEach(() => { + window.history.pushState({}, '', CURRENT_URL); + mockGetItem.mockReset(); + newUrlPromise = new Promise(resolve => { + jest.spyOn(window.location, 'assign').mockImplementation(url => { + resolve(url); + }); + }); + }); + afterAll(() => { delete (window as any).sessionStorage; }); - describe('logout', () => { - const mockCurrentUrl = (url: string) => window.history.pushState({}, '', url); - const tenant = ''; - - it('redirects user to "/logout" when there is no basePath', async () => { - const { basePath } = coreMock.createSetup().http; - mockCurrentUrl('/foo/bar?baz=quz#quuz'); - const sessionExpired = new SessionExpired(basePath, tenant); - const newUrlPromise = new Promise(resolve => { - jest.spyOn(window.location, 'assign').mockImplementation(url => { - resolve(url); - }); - }); - - sessionExpired.logout(); + it(`redirects user to the logout URL with 'msg' and 'next' parameters`, async () => { + const sessionExpired = new SessionExpired(LOGOUT_URL, TENANT); + sessionExpired.logout(); - const url = await newUrlPromise; - expect(url).toBe( - `/logout?next=${encodeURIComponent('/foo/bar?baz=quz#quuz')}&msg=SESSION_EXPIRED` - ); - }); - - it('adds a provider parameter when an auth provider is saved in sessionStorage', async () => { - const { basePath } = coreMock.createSetup().http; - mockCurrentUrl('/foo/bar?baz=quz#quuz'); - const sessionExpired = new SessionExpired(basePath, tenant); - const newUrlPromise = new Promise(resolve => { - jest.spyOn(window.location, 'assign').mockImplementation(url => { - resolve(url); - }); - }); - mockGetItem.mockReturnValueOnce('basic'); - - sessionExpired.logout(); + const next = `&next=${encodeURIComponent(CURRENT_URL)}`; + await expect(newUrlPromise).resolves.toBe(`${LOGOUT_URL}?msg=SESSION_EXPIRED${next}`); + }); - const url = await newUrlPromise; - expect(url).toBe( - `/logout?next=${encodeURIComponent( - '/foo/bar?baz=quz#quuz' - )}&msg=SESSION_EXPIRED&provider=basic` - ); - }); + it(`adds 'provider' parameter when sessionStorage contains the provider name for this tenant`, async () => { + const providerName = 'basic'; + mockGetItem.mockReturnValueOnce(providerName); - it('redirects user to "/${basePath}/logout" and removes basePath from next parameter when there is a basePath', async () => { - const { basePath } = coreMock.createSetup({ basePath: '/foo' }).http; - mockCurrentUrl('/foo/bar?baz=quz#quuz'); - const sessionExpired = new SessionExpired(basePath, tenant); - const newUrlPromise = new Promise(resolve => { - jest.spyOn(window.location, 'assign').mockImplementation(url => { - resolve(url); - }); - }); + const sessionExpired = new SessionExpired(LOGOUT_URL, TENANT); + sessionExpired.logout(); - sessionExpired.logout(); + expect(mockGetItem).toHaveBeenCalledTimes(1); + expect(mockGetItem).toHaveBeenCalledWith(`${TENANT}/session_provider`); - const url = await newUrlPromise; - expect(url).toBe( - `/foo/logout?next=${encodeURIComponent('/bar?baz=quz#quuz')}&msg=SESSION_EXPIRED` - ); - }); + const next = `&next=${encodeURIComponent(CURRENT_URL)}`; + const provider = `&provider=${providerName}`; + await expect(newUrlPromise).resolves.toBe( + `${LOGOUT_URL}?msg=SESSION_EXPIRED${next}${provider}` + ); }); }); diff --git a/x-pack/plugins/security/public/session/session_expired.ts b/x-pack/plugins/security/public/session/session_expired.ts index a43da85526757..5866526b8851e 100644 --- a/x-pack/plugins/security/public/session/session_expired.ts +++ b/x-pack/plugins/security/public/session/session_expired.ts @@ -4,26 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from 'src/core/public'; - export interface ISessionExpired { logout(): void; } +const getNextParameter = () => { + const { location } = window; + const next = encodeURIComponent(`${location.pathname}${location.search}${location.hash}`); + return `&next=${next}`; +}; + +const getProviderParameter = (tenant: string) => { + const key = `${tenant}/session_provider`; + const providerName = sessionStorage.getItem(key); + return providerName ? `&provider=${encodeURIComponent(providerName)}` : ''; +}; + export class SessionExpired { - constructor(private basePath: HttpSetup['basePath'], private tenant: string) {} + constructor(private logoutUrl: string, private tenant: string) {} logout() { - const next = this.basePath.remove( - `${window.location.pathname}${window.location.search}${window.location.hash}` - ); - const key = `${this.tenant}/session_provider`; - const providerName = sessionStorage.getItem(key); - const provider = providerName ? `&provider=${encodeURIComponent(providerName)}` : ''; - window.location.assign( - this.basePath.prepend( - `/logout?next=${encodeURIComponent(next)}&msg=SESSION_EXPIRED${provider}` - ) - ); + const next = getNextParameter(); + const provider = getProviderParameter(this.tenant); + window.location.assign(`${this.logoutUrl}?msg=SESSION_EXPIRED${next}${provider}`); } } 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 ff2db01cb6c58..fba2a2ec98146 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 @@ -33,7 +33,7 @@ afterEach(() => { it(`logs out 401 responses`, async () => { const http = setupHttp('/foo'); - const sessionExpired = new SessionExpired(http.basePath, tenant); + const sessionExpired = new SessionExpired(`${http.basePath}/logout`, tenant); const logoutPromise = new Promise(resolve => { jest.spyOn(sessionExpired, 'logout').mockImplementation(() => resolve()); }); @@ -59,7 +59,7 @@ it(`ignores anonymous paths`, async () => { const http = setupHttp('/foo'); const { anonymousPaths } = http; anonymousPaths.register('/bar'); - const sessionExpired = new SessionExpired(http.basePath, tenant); + const sessionExpired = new SessionExpired(`${http.basePath}/logout`, tenant); const interceptor = new UnauthorizedResponseHttpInterceptor(sessionExpired, anonymousPaths); http.intercept(interceptor); fetchMock.mock('*', 401); @@ -70,7 +70,7 @@ it(`ignores anonymous paths`, async () => { it(`ignores errors which don't have a response, for example network connectivity issues`, async () => { const http = setupHttp('/foo'); - const sessionExpired = new SessionExpired(http.basePath, tenant); + const sessionExpired = new SessionExpired(`${http.basePath}/logout`, tenant); const interceptor = new UnauthorizedResponseHttpInterceptor(sessionExpired, http.anonymousPaths); http.intercept(interceptor); fetchMock.mock('*', new Promise((resolve, reject) => reject(new Error('Network is down')))); @@ -81,7 +81,7 @@ it(`ignores errors which don't have a response, for example network connectivity it(`ignores requests which omit credentials`, async () => { const http = setupHttp('/foo'); - const sessionExpired = new SessionExpired(http.basePath, tenant); + const sessionExpired = new SessionExpired(`${http.basePath}/logout`, tenant); const interceptor = new UnauthorizedResponseHttpInterceptor(sessionExpired, http.anonymousPaths); http.intercept(interceptor); fetchMock.mock('*', 401); diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index 4f1c25702ae97..db8c48f314d7c 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -41,7 +41,7 @@ export const ConfigSchema = schema.object( secureCookies: schema.boolean({ defaultValue: false }), authc: schema.object({ providers: schema.arrayOf(schema.string(), { defaultValue: ['basic'], minSize: 1 }), - oidc: providerOptionsSchema('oidc', schema.maybe(schema.object({ realm: schema.string() }))), + oidc: providerOptionsSchema('oidc', schema.object({ realm: schema.string() })), saml: providerOptionsSchema( 'saml', schema.object({ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 79b826bc4524f..a59a6dbf12566 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -77,7 +77,6 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント", - "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", "common.ui.directives.paginate.size.allDropDownOptionLabel": "すべて", "common.ui.dualRangeControl.mustSetBothErrorMessage": "下と上の値の両方を設定する必要があります", "common.ui.dualRangeControl.outsideOfRangeErrorMessage": "値は {min} と {max} の間でなければなりません", @@ -3946,7 +3945,6 @@ "xpack.apm.tracesTable.tracesPerMinuteColumnLabel": "1 分あたりのトレース", "xpack.apm.tracesTable.tracesPerMinuteUnitLabel": "1分あたりトランザクション数", "xpack.apm.transactionActionMenu.actionsButtonLabel": "アクション", - "xpack.apm.transactionActionMenu.actionsLabel": "アクション", "xpack.apm.transactionActionMenu.showContainerLogsLinkLabel": "コンテナーログを表示", "xpack.apm.transactionActionMenu.showContainerMetricsLinkLabel": "コンテナーメトリックを表示", "xpack.apm.transactionActionMenu.showHostLogsLinkLabel": "ホストログを表示", @@ -13176,4 +13174,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "フィールドを選択してください。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ce1c713adc4bc..dbc9cab4261d8 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -77,7 +77,6 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "所有文档", - "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", "common.ui.directives.paginate.size.allDropDownOptionLabel": "全部", "common.ui.dualRangeControl.mustSetBothErrorMessage": "下限值和上限值都须设置", "common.ui.dualRangeControl.outsideOfRangeErrorMessage": "值必须是在 {min} 到 {max} 的范围内", @@ -3946,7 +3945,6 @@ "xpack.apm.tracesTable.tracesPerMinuteColumnLabel": "每分钟追溯次数", "xpack.apm.tracesTable.tracesPerMinuteUnitLabel": "tpm", "xpack.apm.transactionActionMenu.actionsButtonLabel": "操作", - "xpack.apm.transactionActionMenu.actionsLabel": "操作", "xpack.apm.transactionActionMenu.showContainerLogsLinkLabel": "显示容器日志", "xpack.apm.transactionActionMenu.showContainerMetricsLinkLabel": "显示容器指标", "xpack.apm.transactionActionMenu.showHostLogsLinkLabel": "显示主机日志", @@ -13175,4 +13173,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "此字段必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts index 26be3421b534e..93b8cce153d3b 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import '../../../es_ui_shared/console_lang/mocks'; + import { act } from 'react-dom/test-utils'; import { setupEnvironment, pageHelpers, nextTick, wrapBodyResponse } from './helpers'; import { WatchCreateJsonTestBed } from './helpers/watch_create_json.helpers'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx index 431eb1cae0608..943233d3c14ed 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx @@ -3,6 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import '../../../es_ui_shared/console_lang/mocks'; + import React from 'react'; import { act } from 'react-dom/test-utils'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts index 545bfbdf7cbc2..51285a5786b00 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import '../../../es_ui_shared/console_lang/mocks'; + import { act } from 'react-dom/test-utils'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import axios from 'axios'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts index a0327c6dfa1db..3370e42b2417f 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import '../../../es_ui_shared/console_lang/mocks'; import { act } from 'react-dom/test-utils'; import * as fixtures from '../../test/fixtures'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts index 973c14893f342..20b7b526705c0 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import '../../../es_ui_shared/console_lang/mocks'; + import { act } from 'react-dom/test-utils'; import { setupEnvironment, pageHelpers, nextTick } from './helpers'; import { WatchStatusTestBed } from './helpers/watch_status.helpers'; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx index 91185ac604b34..b3a09d3bc0e65 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx @@ -20,6 +20,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; + import { serializeJsonWatch } from '../../../../../../common/lib/serialization'; import { ErrableFormRow, SectionError, Error as ServerError } from '../../../../components'; import { onWatchSave } from '../../watch_edit_actions'; @@ -28,6 +29,8 @@ import { goToWatchList } from '../../../../lib/navigation'; import { RequestFlyout } from '../request_flyout'; import { useAppContext } from '../../../../app_context'; +import { useXJsonMode } from './use_x_json_mode'; + export const JsonWatchEditForm = () => { const { links: { putWatchApiUrl }, @@ -35,6 +38,7 @@ export const JsonWatchEditForm = () => { } = useAppContext(); const { watch, setWatchProperty } = useContext(WatchContext); + const { xJsonMode, convertToJson, setXJson, xJson } = useXJsonMode(watch.watchString); const { errors } = watch.validate(); const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); @@ -160,9 +164,9 @@ export const JsonWatchEditForm = () => { errors={jsonErrors} > { defaultMessage: 'Code editor', } )} - value={watch.watchString} - onChange={(json: string) => { + value={xJson} + onChange={(xjson: string) => { if (validationError) { setValidationError(null); } - setWatchProperty('watchString', json); + setXJson(xjson); + // Keep the watch in sync with the editor content + setWatchProperty('watchString', convertToJson(xjson)); }} /> diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx index 8bb1770d2f44d..c906d05be64be 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx @@ -40,6 +40,8 @@ import { JsonWatchEditSimulateResults } from './json_watch_edit_simulate_results import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label'; import { useAppContext } from '../../../../app_context'; +import { useXJsonMode } from './use_x_json_mode'; + const actionModeOptions = Object.keys(ACTION_MODES).map(mode => ({ text: ACTION_MODES[mode], value: ACTION_MODES[mode], @@ -94,6 +96,8 @@ export const JsonWatchEditSimulate = ({ ignoreCondition, } = executeDetails; + const { setXJson, convertToJson, xJsonMode, xJson } = useXJsonMode(alternativeInput); + const columns = [ { field: 'actionId', @@ -294,7 +298,6 @@ export const JsonWatchEditSimulate = ({ {i18n.translate( @@ -323,7 +326,6 @@ export const JsonWatchEditSimulate = ({ } > {i18n.translate( @@ -361,7 +362,6 @@ export const JsonWatchEditSimulate = ({ > { + value={xJson} + onChange={(xjson: string) => { + setXJson(xjson); setExecuteDetails( new ExecuteDetails({ ...executeDetails, - alternativeInput: json, + alternativeInput: convertToJson(xjson), }) ); }} diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts new file mode 100644 index 0000000000000..7aefb0554e0e8 --- /dev/null +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/use_x_json_mode.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { useState } from 'react'; +import { XJsonMode } from '../../../../../../../es_ui_shared/console_lang'; +import { + collapseLiteralStrings, + expandLiteralStrings, +} from '../../../../../../../../../src/plugins/es_ui_shared/console_lang/lib'; + +export const xJsonMode = new XJsonMode(); + +export const useXJsonMode = (json: string) => { + const [xJson, setXJson] = useState(expandLiteralStrings(json)); + + return { + xJson, + setXJson, + xJsonMode, + convertToJson: collapseLiteralStrings, + }; +}; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx index c1ebcdc262863..b79f9eee01834 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx @@ -245,7 +245,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ mode="json" width="100%" height="200px" - theme="github" + theme="textmate" data-test-subj="webhookBodyEditor" aria-label={i18n.translate( 'xpack.watcher.sections.watchEdit.threshold.webhookAction.bodyCodeEditorAriaLabel', diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index d23bd2ac4646d..eb03aafc03d08 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -75,7 +75,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, '--xpack.alerting.enabled=true', - '--xpack.event_log.logEntries=true', + '--xpack.eventLog.logEntries=true', ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index 87280169c0960..5dcff8712a28d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -94,7 +94,7 @@ export default function slackTest({ getService }: FtrProviderContext) { name: 'A slack action', actionTypeId: '.slack', secrets: { - webhookUrl: 'http://slack.mynonexistent.com', + webhookUrl: 'http://slack.mynonexistent.com/other/stuff/in/the/path', }, }) .expect(400) @@ -103,7 +103,29 @@ export default function slackTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type secrets: error configuring slack action: target url "http://slack.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', + 'error validating action type secrets: error configuring slack action: target hostname "slack.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a slack action with a webhookUrl with no hostname', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A slack action', + actionTypeId: '.slack', + secrets: { + webhookUrl: 'fee-fi-fo-fum', + }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: error configuring slack action: unable to parse host name from webhookUrl', }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/common/config.ts b/x-pack/test/detection_engine_api_integration/common/config.ts index bf8e6982b545d..d2bfeeb6433d3 100644 --- a/x-pack/test/detection_engine_api_integration/common/config.ts +++ b/x-pack/test/detection_engine_api_integration/common/config.ts @@ -74,7 +74,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, '--xpack.alerting.enabled=true', - '--xpack.event_log.logEntries=true', + '--xpack.eventLog.logEntries=true', ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts index ca6ef5b6cede9..b8034fd92e988 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts @@ -25,5 +25,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./update_rules_bulk')); loadTestFile(require.resolve('./patch_rules_bulk')); loadTestFile(require.resolve('./patch_rules')); + loadTestFile(require.resolve('./query_signals')); + loadTestFile(require.resolve('./open_close_signals')); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts new file mode 100644 index 0000000000000..e9e3e4299d108 --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_SIGNALS_STATUS_URL } from '../../../../legacy/plugins/siem/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + createSignalsIndex, + deleteSignalsIndex, + setSignalStatus, + getSignalStatusEmptyResponse, +} from './utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('open_close_signals', () => { + describe('validation checks', () => { + it('should not give errors when querying and the signals index does not exist yet', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) + .set('kbn-xsrf', 'true') + .send(setSignalStatus({ signalIds: ['123'], status: 'open' })) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql(getSignalStatusEmptyResponse()); + }); + + it('should not give errors when querying and the signals index does exist and is empty', async () => { + await createSignalsIndex(supertest); + const { body } = await supertest + .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) + .set('kbn-xsrf', 'true') + .send(setSignalStatus({ signalIds: ['123'], status: 'open' })) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql(getSignalStatusEmptyResponse()); + + await deleteSignalsIndex(supertest); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/query_signals.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/query_signals.ts new file mode 100644 index 0000000000000..6fa62412ed467 --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/query_signals.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../legacy/plugins/siem/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { getSignalStatus, createSignalsIndex, deleteSignalsIndex } from './utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + + describe('query_signals_route', () => { + describe('validation checks', () => { + it('should not give errors when querying and the signals index does not exist yet', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getSignalStatus()) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql({ + timed_out: false, + _shards: { total: 0, successful: 0, skipped: 0, failed: 0 }, + hits: { total: { value: 0, relation: 'eq' }, max_score: 0, hits: [] }, + }); + }); + + it('should not give errors when querying and the signals index does exist and is empty', async () => { + await createSignalsIndex(supertest); + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getSignalStatus()) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql({ + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + statuses: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + }); + + await deleteSignalsIndex(supertest); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index b78073c0e737b..bef700d0409a5 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -53,6 +53,36 @@ export const getSimpleRule = (ruleId = 'rule-1'): Partial = query: 'user.name: root or user.name: admin', }); +export const getSignalStatus = () => ({ + aggs: { statuses: { terms: { field: 'signal.status', size: 10 } } }, +}); + +export const setSignalStatus = ({ + signalIds, + status, +}: { + signalIds: string[]; + status: 'open' | 'closed'; +}) => ({ + signal_ids: signalIds, + status, +}); + +export const getSignalStatusEmptyResponse = () => ({ + timed_out: false, + total: 0, + updated: 0, + deleted: 0, + batches: 0, + version_conflicts: 0, + noops: 0, + retries: { bulk: 0, search: 0 }, + throttled_millis: 0, + requests_per_second: -1, + throttled_until_millis: 0, + failures: [], +}); + /** * This is a typical simple rule for testing that is easy for most basic testing */ diff --git a/x-pack/test/functional/apps/endpoint/index.ts b/x-pack/test/functional/apps/endpoint/index.ts index 5fdf54b98cda6..0ea9344a67aba 100644 --- a/x-pack/test/functional/apps/endpoint/index.ts +++ b/x-pack/test/functional/apps/endpoint/index.ts @@ -12,5 +12,6 @@ export default function({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./landing_page')); loadTestFile(require.resolve('./management')); + loadTestFile(require.resolve('./policy_list')); }); } diff --git a/x-pack/test/functional/apps/endpoint/policy_list.ts b/x-pack/test/functional/apps/endpoint/policy_list.ts new file mode 100644 index 0000000000000..1fe2492bed5a0 --- /dev/null +++ b/x-pack/test/functional/apps/endpoint/policy_list.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['common', 'endpoint']); + const testSubjects = getService('testSubjects'); + + describe('Endpoint Policy List', function() { + this.tags(['ciGroup7']); + before(async () => { + await pageObjects.common.navigateToUrlWithBrowserHistory('endpoint', '/policy'); + }); + + it('loads the Policy List Page', async () => { + await testSubjects.existOrFail('policyListPage'); + }); + it('displays page title', async () => { + const policyTitle = await testSubjects.getVisibleText('policyViewTitle'); + expect(policyTitle).to.equal('Policies'); + }); + it('shows policy count total', async () => { + const policyTotal = await testSubjects.getVisibleText('policyTotalCount'); + expect(policyTotal).to.equal('0 Policies'); + }); + it('includes policy list table', async () => { + await testSubjects.existOrFail('policyTable'); + }); + it('has correct table headers', async () => { + const allHeaderCells = await pageObjects.endpoint.tableHeaderVisibleText('policyTable'); + expect(allHeaderCells).to.eql([ + 'Policy Name', + 'Total', + 'Pending', + 'Failed', + 'Created By', + 'Created', + 'Last Updated By', + 'Last Updated', + ]); + }); + }); +} diff --git a/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts b/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts index 066042896c122..b24c537d25085 100644 --- a/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts +++ b/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts @@ -20,7 +20,8 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); - describe('visualize', () => { + // FLAKY: https://github.com/elastic/kibana/issues/45244 + describe.skip('visualize', () => { before(async () => { await esArchiver.loadIfNeeded('logstash_functional'); }); diff --git a/x-pack/test/functional/page_objects/endpoint_page.ts b/x-pack/test/functional/page_objects/endpoint_page.ts index a306a855a83eb..54f537dd0e8c3 100644 --- a/x-pack/test/functional/page_objects/endpoint_page.ts +++ b/x-pack/test/functional/page_objects/endpoint_page.ts @@ -11,6 +11,25 @@ export function EndpointPageProvider({ getService }: FtrProviderContext) { const table = getService('table'); return { + /** + * Finds the Table with the given `selector` (test subject) and returns + * back an array containing the table's header column text + * + * @param selector + * @returns Promise + */ + async tableHeaderVisibleText(selector: string) { + const $ = await (await testSubjects.find('policyTable')).parseDomContent(); + return $('thead tr th') + .toArray() + .map(th => + $(th) + .text() + .replace(/ /g, '') + .trim() + ); + }, + async welcomeEndpointTitle() { return await testSubjects.getVisibleText('welcomeTitle'); }, diff --git a/x-pack/typings/@elastic/eui/index.d.ts b/x-pack/typings/@elastic/eui/index.d.ts index de9697f859fd7..688d1a2fa127d 100644 --- a/x-pack/typings/@elastic/eui/index.d.ts +++ b/x-pack/typings/@elastic/eui/index.d.ts @@ -7,7 +7,6 @@ // TODO: Remove once typescript definitions are in EUI declare module '@elastic/eui' { - export const EuiDescribedFormGroup: React.FC; export const EuiCodeEditor: React.FC; export const Query: any; } diff --git a/yarn.lock b/yarn.lock index da247ea90a397..41756a7addd45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1955,15 +1955,17 @@ tabbable "^1.1.0" uuid "^3.1.0" -"@elastic/eui@18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-18.3.0.tgz#e21c6246624f694e2ae1c7c1f1a11b612faf260a" - integrity sha512-Rkj1rTtDa6iZMUF7pxYRojku1sLXzTU0FK1D9i0XE3H//exy3VyTV6qUlbdkiKXjO7emrgQqfzKDeXT+ZYztgg== +"@elastic/eui@19.0.0": + version "19.0.0" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-19.0.0.tgz#cf7d644945c95997d442585cf614e853f173746e" + integrity sha512-8/USz56MYhu6bV4oecJct7tsdi0ktErOIFLobNmQIKdxDOni/KpttX6IHqxM7OuIWi1AEMXoIozw68+oyL/uKQ== dependencies: "@types/chroma-js" "^1.4.3" + "@types/enzyme" "^3.1.13" "@types/lodash" "^4.14.116" "@types/numeral" "^0.0.25" "@types/react-beautiful-dnd" "^10.1.0" + "@types/react-virtualized" "^9.18.7" chroma-js "^2.0.4" classnames "^2.2.5" highlight.js "^9.12.0" @@ -3994,6 +3996,11 @@ "@svgr/plugin-svgo" "^4.2.0" loader-utils "^1.2.3" +"@testim/chrome-version@^1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.0.7.tgz#0cd915785ec4190f08a3a6acc9b61fc38fb5f1a9" + integrity sha512-8UT/J+xqCYfn3fKtOznAibsHpiuDshCb0fwgWxRazTT19Igp9ovoXMPhXyLD6m3CKQGTMHgqoxaFfMWaL40Rnw== + "@testing-library/dom@^6.3.0": version "6.10.1" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-6.10.1.tgz#da5bf5065d3f9e484aef4cc495f4e1a5bea6df2e" @@ -4384,10 +4391,10 @@ resolved "https://registry.yarnpkg.com/@types/elasticsearch/-/elasticsearch-5.0.33.tgz#b0fd37dc674f498223b6d68c313bdfd71f4d812b" integrity sha512-n/g9pqJEpE4fyUE8VvHNGtl7E2Wv8TCroNwfgAeJKRV4ghDENahtrAo1KMsFNIejBD2gDAlEUa4CM4oEEd8p9Q== -"@types/enzyme@^3.9.0": - version "3.9.3" - resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.9.3.tgz#d1029c0edd353d7b00f3924803eb88216460beed" - integrity sha512-jDKoZiiMA3lGO3skSO7dfqEHNvmiTLLV+PHD9EBQVlJANJvpY6qq1zzjRI24ZOtG7F+CS7BVWDXKewRmN8PjHQ== +"@types/enzyme@^3.1.13", "@types/enzyme@^3.10.5": + version "3.10.5" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.5.tgz#fe7eeba3550369eed20e7fb565bfb74eec44f1f0" + integrity sha512-R+phe509UuUYy9Tk0YlSbipRpfVtIzb/9BHn5pTEtjJTF5LXvUjrIQcZvNyANNEyFrd2YGs196PniNT1fgvOQA== dependencies: "@types/cheerio" "*" "@types/react" "*" @@ -4573,7 +4580,7 @@ resolved "https://registry.yarnpkg.com/@types/hoek/-/hoek-4.1.3.tgz#d1982d48fb0d2a0e5d7e9d91838264d8e428d337" integrity sha1-0ZgtSPsNKg5dfp2Rg4Jk2OQo0zc= -"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0": +"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== @@ -4991,13 +4998,20 @@ dependencies: "@types/react" "*" -"@types/react-dom@*", "@types/react-dom@^16.9.4": +"@types/react-dom@*": version "16.9.4" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df" integrity sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw== dependencies: "@types/react" "*" +"@types/react-dom@^16.9.5": + version "16.9.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" + integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== + dependencies: + "@types/react" "*" + "@types/react-grid-layout@^0.16.7": version "0.16.7" resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-0.16.7.tgz#53d5f5034deb0c60e25a0fa578141e9a0982011f" @@ -5018,14 +5032,6 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react-redux@^6.0.6": - version "6.0.6" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.6.tgz#87f1d0a6ea901b93fcaf95fa57641ff64079d277" - integrity sha512-sD/QEn45h+CH0OAhCn6/9COlihZ94bzpP58QzYYCL3tOFta/WBhuvMoyLP8khJLfwQBx1PT70HP/1GnDws9YXQ== - dependencies: - "@types/react" "*" - redux "^4.0.0" - "@types/react-redux@^7.1.0": version "7.1.5" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.5.tgz#c7a528d538969250347aa53c52241051cf886bd3" @@ -5036,6 +5042,16 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" +"@types/react-redux@^7.1.7": + version "7.1.7" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.7.tgz#12a0c529aba660696947384a059c5c6e08185c7a" + integrity sha512-U+WrzeFfI83+evZE2dkZ/oF/1vjIYgqrb5dGgedkqVV8HEfDFujNgWCwHL89TDuWKb47U0nTBT6PLGq4IIogWg== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-resize-detector@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/react-resize-detector/-/react-resize-detector-4.0.1.tgz#cc8f012f5957e4826e69b8d2afd59baadcac556c" @@ -5096,10 +5112,10 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react@*", "@types/react@^16.8.23", "@types/react@^16.9.11", "@types/react@^16.9.13": - version "16.9.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.15.tgz#aeabb7a50f96c9e31a16079ada20ede9ed602977" - integrity sha512-WsmM1b6xQn1tG3X2Hx4F3bZwc2E82pJXt5OPs2YJgg71IzvUoKOSSSYOvLXYCg1ttipM+UuA4Lj3sfvqjVxyZw== +"@types/react@*", "@types/react@^16.8.23", "@types/react@^16.9.19": + version "16.9.19" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.19.tgz#c842aa83ea490007d29938146ff2e4d9e4360c40" + integrity sha512-LJV97//H+zqKWMms0kvxaKYJDG05U2TtQB3chRLF8MPNs+MQh/H1aGlyDUxjaHvu08EAGerdX2z4LTBc7ns77A== dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -5118,23 +5134,18 @@ dependencies: "@types/react" "*" -"@types/reduce-reducers@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@types/reduce-reducers/-/reduce-reducers-0.3.0.tgz#d86d88049c38bebbafa5baf121282d765fabbebf" - integrity sha512-S9Vi74p0UOlqf9dqiurBwNBp+ABAGZ7nJAZteFS6LS8y9u2fkGfvNk1gtauKoDG+BuB4vjp1+P/R0/r5rFxYDQ== +"@types/reduce-reducers@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/reduce-reducers/-/reduce-reducers-1.0.0.tgz#033120b109159f4b344210ee75310d1ec3fcc8ef" + integrity sha512-MWKF9QDH/HaMQZvGyQlrut1ttyrFVIrGZqhCXPBcl5LelhnfC7dIE2jK2qZjxFHUCeXgjKCk5hN+/GzA7GgqjQ== dependencies: - redux "^4.0.0" + reduce-reducers "*" "@types/redux-actions@^2.6.1": version "2.6.1" resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.6.1.tgz#0940e97fa35ad3004316bddb391d8e01d2efa605" integrity sha512-zKgK+ATp3sswXs6sOYo1tk8xdXTy4CTaeeYrVQlClCjeOpag5vzPo0ASWiiBJ7vsiQRAdb3VkuFLnDoBimF67g== -"@types/redux@^3.6.31": - version "3.6.31" - resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.31.tgz#40eafa7575db36b912ce0059b85de98c205b0708" - integrity sha1-QOr6dXXbNrkSzgBZuF3pjCBbBwg= - "@types/request@^2.48.2": version "2.48.2" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.2.tgz#936374cbe1179d7ed529fc02543deb4597450fed" @@ -6800,14 +6811,13 @@ array.prototype.find@^2.1.0: define-properties "^1.1.3" es-abstract "^1.13.0" -array.prototype.flat@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz#812db8f02cad24d3fab65dd67eabe3b8903494a4" - integrity sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw== +array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== dependencies: - define-properties "^1.1.2" - es-abstract "^1.10.0" - function-bind "^1.1.1" + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" array.prototype.flatmap@^1.2.1: version "1.2.1" @@ -7112,6 +7122,13 @@ axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" +axios@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" @@ -8953,7 +8970,7 @@ cheerio@0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -cheerio@^1.0.0-rc.2: +cheerio@^1.0.0-rc.3: version "1.0.0-rc.3" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6" integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA== @@ -9047,15 +9064,16 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@79.0.0: - version "79.0.0" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-79.0.0.tgz#1660ac29924dfcd847911025593d6b6746aeea35" - integrity sha512-DO29C7ntJfzu6q1vuoWwCON8E9x5xzopt7Q41A7Dr7hBKcdNpGw1l9DTt9b+l1qviOWiJLGsD+jHw21ptEHubA== +chromedriver@^80.0.1: + version "80.0.1" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-80.0.1.tgz#35c1642e2d864b9e8262f291003e455b0e422917" + integrity sha512-VfRtZUpBUIjeypS+xM40+VD9g4Drv7L2VibG/4+0zX3mMx4KayN6gfKETycPfO6JwQXTLSxEr58fRcrsa8r5xQ== dependencies: - del "^4.1.1" + "@testim/chrome-version" "^1.0.7" + axios "^0.19.2" + del "^5.1.0" extract-zip "^1.6.7" - mkdirp "^0.5.1" - request "^2.88.0" + mkdirp "^1.0.3" tcp-port-used "^1.0.1" ci-info@^1.0.0: @@ -12203,74 +12221,76 @@ env-variable@0.0.x: resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== -enzyme-adapter-react-16@^1.15.1: - version "1.15.1" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.1.tgz#8ad55332be7091dc53a25d7d38b3485fc2ba50d5" - integrity sha512-yMPxrP3vjJP+4wL/qqfkT6JAIctcwKF+zXO6utlGPgUJT2l4tzrdjMDWGd/Pp1BjHBcljhN24OzNEGRteibJhA== +enzyme-adapter-react-16@^1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.2.tgz#b16db2f0ea424d58a808f9df86ab6212895a4501" + integrity sha512-SkvDrb8xU3lSxID8Qic9rB8pvevDbLybxPK6D/vW7PrT0s2Cl/zJYuXvsd1EBTz0q4o3iqG3FJhpYz3nUNpM2Q== dependencies: - enzyme-adapter-utils "^1.12.1" - enzyme-shallow-equal "^1.0.0" + enzyme-adapter-utils "^1.13.0" + enzyme-shallow-equal "^1.0.1" has "^1.0.3" object.assign "^4.1.0" - object.values "^1.1.0" + object.values "^1.1.1" prop-types "^15.7.2" - react-is "^16.10.2" + react-is "^16.12.0" react-test-renderer "^16.0.0-0" semver "^5.7.0" -enzyme-adapter-utils@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.12.1.tgz#e828e0d038e2b1efa4b9619ce896226f85c9dd88" - integrity sha512-KWiHzSjZaLEoDCOxY8Z1RAbUResbqKN5bZvenPbfKtWorJFVETUw754ebkuCQ3JKm0adx1kF8JaiR+PHPiP47g== +enzyme-adapter-utils@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.13.0.tgz#01c885dde2114b4690bf741f8dc94cee3060eb78" + integrity sha512-YuEtfQp76Lj5TG1NvtP2eGJnFKogk/zT70fyYHXK2j3v6CtuHqc8YmgH/vaiBfL8K1SgVVbQXtTcgQZFwzTVyQ== dependencies: airbnb-prop-types "^2.15.0" - function.prototype.name "^1.1.1" + function.prototype.name "^1.1.2" object.assign "^4.1.0" - object.fromentries "^2.0.1" + object.fromentries "^2.0.2" prop-types "^15.7.2" - semver "^5.7.0" + semver "^5.7.1" -enzyme-shallow-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.0.tgz#d8e4603495e6ea279038eef05a4bf4887b55dc69" - integrity sha512-VUf+q5o1EIv2ZaloNQQtWCJM9gpeux6vudGVH6vLmfPXFLRuxl5+Aq3U260wof9nn0b0i+P5OEUXm1vnxkRpXQ== +enzyme-shallow-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.1.tgz#7afe03db3801c9b76de8440694096412a8d9d49e" + integrity sha512-hGA3i1so8OrYOZSM9whlkNmVHOicJpsjgTzC+wn2JMJXhq1oO4kA4bJ5MsfzSIcC71aLDKzJ6gZpIxrqt3QTAQ== dependencies: has "^1.0.3" - object-is "^1.0.1" + object-is "^1.0.2" -enzyme-to-json@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.4.3.tgz#ed4386f48768ed29e2d1a2910893542c34e7e0af" - integrity sha512-jqNEZlHqLdz7OTpXSzzghArSS3vigj67IU/fWkPyl1c0TCj9P5s6Ze0kRkYZWNEoCqCR79xlQbigYlMx5erh8A== +enzyme-to-json@^3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.4.4.tgz#b30726c59091d273521b6568c859e8831e94d00e" + integrity sha512-50LELP/SCPJJGic5rAARvU7pgE3m1YaNj7JLM+Qkhl5t7PAs6fiyc8xzc50RnkKPFQCv0EeFVjEWdIFRGPWMsA== dependencies: lodash "^4.17.15" + react-is "^16.12.0" -enzyme@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.10.0.tgz#7218e347c4a7746e133f8e964aada4a3523452f6" - integrity sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg== +enzyme@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.11.0.tgz#71d680c580fe9349f6f5ac6c775bc3e6b7a79c28" + integrity sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw== dependencies: - array.prototype.flat "^1.2.1" - cheerio "^1.0.0-rc.2" - function.prototype.name "^1.1.0" + array.prototype.flat "^1.2.3" + cheerio "^1.0.0-rc.3" + enzyme-shallow-equal "^1.0.1" + function.prototype.name "^1.1.2" has "^1.0.3" - html-element-map "^1.0.0" - is-boolean-object "^1.0.0" - is-callable "^1.1.4" - is-number-object "^1.0.3" - is-regex "^1.0.4" - is-string "^1.0.4" + html-element-map "^1.2.0" + is-boolean-object "^1.0.1" + is-callable "^1.1.5" + is-number-object "^1.0.4" + is-regex "^1.0.5" + is-string "^1.0.5" is-subset "^0.1.1" lodash.escape "^4.0.1" lodash.isequal "^4.5.0" - object-inspect "^1.6.0" - object-is "^1.0.1" + object-inspect "^1.7.0" + object-is "^1.0.2" object.assign "^4.1.0" - object.entries "^1.0.4" - object.values "^1.0.4" - raf "^3.4.0" + object.entries "^1.1.1" + object.values "^1.1.1" + raf "^3.4.1" rst-selector-parser "^2.2.3" - string.prototype.trim "^1.1.2" + string.prototype.trim "^1.2.1" errlop@^1.1.2: version "1.1.2" @@ -12320,26 +12340,44 @@ error@^7.0.0, error@^7.0.2: string-template "~0.2.1" xtend "~4.0.0" -es-abstract@^1.10.0, es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.13.0, es-abstract@^1.14.2, es-abstract@^1.15.0, es-abstract@^1.4.3, es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.7.0, es-abstract@^1.9.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" - integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== +es-abstract@^1.10.0, es-abstract@^1.11.0, es-abstract@^1.13.0, es-abstract@^1.14.2, es-abstract@^1.17.0-next.1, es-abstract@^1.4.3, es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.7.0, es-abstract@^1.9.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1" + integrity sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug== dependencies: - es-to-primitive "^1.2.0" + es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.0" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-inspect "^1.6.0" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-abstract@^1.15.0: + version "1.17.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" + integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" is-date-object "^1.0.1" @@ -14402,31 +14440,21 @@ function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327" - integrity sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - is-callable "^1.1.3" - -function.prototype.name@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.1.tgz#6d252350803085abc2ad423d4fe3be2f9cbda392" - integrity sha512-e1NzkiJuw6xqVH7YSdiW/qDHebcmMhPNe6w+4ZYYEg0VA+LaLzx37RimbPLuonHhYGFGPx1ME2nSi74JiaCr/Q== +function.prototype.name@^1.1.0, function.prototype.name@^1.1.1, function.prototype.name@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.2.tgz#5cdf79d7c05db401591dfde83e3b70c5123e9a45" + integrity sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" - functions-have-names "^1.1.1" - is-callable "^1.1.4" + es-abstract "^1.17.0-next.1" + functions-have-names "^1.2.0" functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -functions-have-names@^1.1.1: +functions-have-names@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.0.tgz#83da7583e4ea0c9ac5ff530f73394b033e0bf77d" integrity sha512-zKXyzksTeaCSw5wIX79iCA40YAa6CJMJgNg9wdkU/ERBrIdPSimPICYiLp65lRbSBqtiHql/HZfS2DyI/AH6tQ== @@ -15861,10 +15889,10 @@ has-symbol-support-x@^1.4.1: resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== has-to-string-tag-x@^1.2.0: version "1.4.1" @@ -16095,22 +16123,10 @@ hoek@6.x.x: resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.0.3.tgz#7884360426d927865a0a1251fc9c59313af5b798" integrity sha512-TU6RyZ/XaQCTWRLrdqZZtZqwxUVr6PDMfi6MlWNURZ7A6czanQqX4pFE1mdOUQR9FdPCsZ0UzL8jI/izZ+eBSQ== -hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0, hoist-non-react-statics@^2.5.5: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== - -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" - integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== - dependencies: - react-is "^16.7.0" - -hoist-non-react-statics@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" - integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== +hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0, hoist-non-react-statics@^2.5.5, hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== dependencies: react-is "^16.7.0" @@ -16141,10 +16157,10 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-element-map@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.0.1.tgz#3c4fcb4874ebddfe4283b51c8994e7713782b592" - integrity sha512-BZSfdEm6n706/lBfXKWa4frZRZcT5k1cOusw95ijZsHlI+GdgY0v95h6IzO3iIDf2ROwq570YTwqNPqHcNMozw== +html-element-map@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.2.0.tgz#dfbb09efe882806af63d990cf6db37993f099f22" + integrity sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw== dependencies: array-filter "^1.0.0" @@ -16952,7 +16968,7 @@ invariant@2.2.4, invariant@^2.1.0, invariant@^2.1.1, invariant@^2.2.3, invariant dependencies: loose-envify "^1.0.0" -invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2: +invariant@^2.2.1, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" integrity sha1-nh9WrArNtr8wMwbzOL47IErmA2A= @@ -17084,10 +17100,10 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93" - integrity sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M= +is-boolean-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" + integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ== is-buffer@^1.0.2, is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" @@ -17106,10 +17122,10 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-callable@^1.1.3, is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== is-ci@1.2.1: version "1.2.1" @@ -17359,10 +17375,10 @@ is-npm@^1.0.0: resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= -is-number-object@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799" - integrity sha1-8mWrian0RQNO9q/xWo8AsA9VF5k= +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== is-number@^0.1.1: version "0.1.1" @@ -17499,12 +17515,12 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= -is-regex@^1.0.3, is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= +is-regex@^1.0.3, is-regex@^1.0.4, is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== dependencies: - has "^1.0.1" + has "^1.0.3" is-regexp@^1.0.0: version "1.0.0" @@ -17572,10 +17588,10 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64" - integrity sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ= +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== is-subset@^0.1.1: version "0.1.1" @@ -17640,12 +17656,7 @@ is-whitespace-character@^1.0.0: resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.1.tgz#9ae0176f3282b65457a1992cdb084f8a5f833e3b" integrity sha1-muAXbzKCtlRXoZks2whPil+DPjs= -is-windows@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" - integrity sha1-MQ23D3QtJZoWo2kgK1GvhCMzENk= - -is-windows@^1.0.2: +is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== @@ -19463,7 +19474,7 @@ locutus@^2.0.5: resolved "https://registry.yarnpkg.com/locutus/-/locutus-2.0.10.tgz#f903619466a98a4ab76e8b87a5854b55a743b917" integrity sha512-AZg2kCqrquMJ5FehDsBidV0qHl98NrsYtseUClzjAQ3HFnsDBJTCwGVplSQ82t9/QfgahqvTjaKcZqZkHmS0wQ== -lodash-es@^4.17.11, lodash-es@^4.17.5, lodash-es@^4.2.1: +lodash-es@^4.17.11, lodash-es@^4.2.1: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== @@ -20793,6 +20804,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi dependencies: minimist "0.0.8" +mkdirp@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" + integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== + mocha-junit-reporter@^1.23.1: version "1.23.1" resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.1.tgz#ba11519c0b967f404e4123dd69bc4ba022ab0f12" @@ -21824,7 +21840,7 @@ object-identity-map@^1.0.2: dependencies: object.entries "^1.1.0" -object-inspect@^1.6.0: +object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== @@ -21839,10 +21855,10 @@ object-inspect@~1.6.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== -object-is@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" - integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= +object-is@^1.0.1, object-is@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4" + integrity sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.0.9, object-keys@^1.1.1: version "1.1.1" @@ -21888,13 +21904,13 @@ object.defaults@^1.0.0, object.defaults@^1.1.0: for-own "^1.0.0" isobject "^3.0.0" -object.entries@^1.0.4, object.entries@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" - integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== +object.entries@^1.0.4, object.entries@^1.1.0, object.entries@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" + integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== dependencies: define-properties "^1.1.3" - es-abstract "^1.12.0" + es-abstract "^1.17.0-next.1" function-bind "^1.1.1" has "^1.0.3" @@ -21918,6 +21934,16 @@ object.fromentries@^2.0.1: function-bind "^1.1.1" has "^1.0.3" +object.fromentries@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" + integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -21949,13 +21975,13 @@ object.reduce@^1.0.0: for-own "^1.0.0" make-iterator "^1.0.0" -object.values@^1.0.4, object.values@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" - integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== +object.values@^1.0.4, object.values@^1.1.0, object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== dependencies: define-properties "^1.1.3" - es-abstract "^1.12.0" + es-abstract "^1.17.0-next.1" function-bind "^1.1.1" has "^1.0.3" @@ -23906,14 +23932,7 @@ raf-schd@^4.0.2: resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0" integrity sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ== -raf@^3.1.0, raf@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" - integrity sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw== - dependencies: - performance-now "^2.1.0" - -raf@^3.4.0: +raf@^3.1.0, raf@^3.3.0, raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -24413,11 +24432,6 @@ react-intl@^2.8.0: intl-relativeformat "^2.1.0" invariant "^2.1.1" -react-is@^16.10.2, react-is@^16.9.0: - version "16.11.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" - integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== - react-is@^16.12.0, react-is@^16.3.1: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" @@ -24438,6 +24452,11 @@ react-is@^16.8.4: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.5.tgz#c54ac229dd66b5afe0de5acbe47647c3da692ff8" integrity sha512-sudt2uq5P/2TznPV4Wtdi+Lnq3yaYW8LfvPKLM9BKD8jJNBkxMVyB0C9/GmVhLw7Jbdmndk/73n7XQGeN9A3QQ== +react-is@^16.9.0: + version "16.11.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" + integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== + react-is@~16.3.0: version "16.3.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" @@ -24596,19 +24615,7 @@ react-reconciler@^0.22.1: prop-types "^15.6.2" scheduler "^0.16.2" -react-redux@^5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8" - integrity sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg== - dependencies: - hoist-non-react-statics "^2.5.0" - invariant "^2.0.0" - lodash "^4.17.5" - lodash-es "^4.17.5" - loose-envify "^1.1.0" - prop-types "^15.6.0" - -react-redux@^5.1.2: +react-redux@^5.0.7, react-redux@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57" integrity sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q== @@ -24621,7 +24628,7 @@ react-redux@^5.1.2: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-redux@^7.1.0, react-redux@^7.1.1: +react-redux@^7.1.0, react-redux@^7.1.1, react-redux@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.3.tgz#717a3d7bbe3a1b2d535c94885ce04cdc5a33fc79" integrity sha512-uI1wca+ECG9RoVkWQFF4jDMqmaw0/qnvaSvOoL/GA4dNxf6LoV8sUAcNDvE5NWKs4hFpn0t6wswNQnY3f7HT3w== @@ -25252,12 +25259,17 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +reduce-reducers@*, reduce-reducers@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-1.0.4.tgz#fb77e751a9eb0201760ac5a605ca8c9c2d0537f8" + integrity sha512-Mb2WZ2bJF597exiqX7owBzrqJ74DHLK3yOQjCyPAaNifRncE8OD0wFIuoMhXxTnHK07+8zZ2SJEKy/qtiyR7vw== + reduce-reducers@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c" integrity sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw== -redux-actions@2.6.5: +redux-actions@^2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.6.5.tgz#bdca548768ee99832a63910c276def85e821a27e" integrity sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw== @@ -25273,10 +25285,10 @@ redux-devtools-extension@^2.13.8: resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== -redux-observable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redux-observable/-/redux-observable-1.0.0.tgz#780ff2455493eedcef806616fe286b454fd15d91" - integrity sha512-6bXnpqWTBeLaLQjXHyN1giXq4nLxCmv+SUkdmiwBgvmVxvDbdmydvL1Z7DGo0WItyzI/kqXQKiucUuTxnrPRkA== +redux-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redux-observable/-/redux-observable-1.2.0.tgz#ff51b6c6be2598e9b5e89fc36639186bb0e669c7" + integrity sha512-yeR90RP2WzZzCxxnQPlh2uFzyfFLsfXu8ROh53jGDPXVqj71uNDMmvi/YKQkd9ofiVoO4OYb1snbowO49tCEMg== redux-saga@^0.16.0: version "0.16.2" @@ -25288,7 +25300,7 @@ redux-thunk@2.2.0: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" integrity sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU= -redux-thunk@2.3.0: +redux-thunk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== @@ -25308,7 +25320,7 @@ redux@3.7.2: loose-envify "^1.1.0" symbol-observable "^1.0.3" -redux@4.0.0, redux@^4.0.0: +redux@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.0.tgz#aa698a92b729315d22b34a0553d7e6533555cc03" integrity sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA== @@ -25332,6 +25344,14 @@ redux@^4.0.4: loose-envify "^1.4.0" symbol-observable "^1.2.0" +redux@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + reflect.ownkeys@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" @@ -25887,11 +25907,6 @@ requires-regex@^0.3.3: resolved "https://registry.yarnpkg.com/requires-regex/-/requires-regex-0.3.3.tgz#60309eaabbfd5ca8259e090b8b5a94b2144eb0dd" integrity sha1-YDCeqrv9XKglngkLi1qUshROsN0= -reselect@3.0.1, reselect@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" - integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= - reselect@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" @@ -26642,17 +26657,17 @@ semver-truncate@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= -"semver@2 || 3 || 4 || 5", semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== +"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@5.5.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.5.0: +semver@5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -semver@5.7.0, semver@^5.4.1, semver@^5.6.0, semver@^5.7.0: +semver@5.7.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== @@ -27878,13 +27893,13 @@ string.prototype.padstart@^3.0.0: es-abstract "^1.4.3" function-bind "^1.0.2" -string.prototype.trim@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz#75a729b10cfc1be439543dae442129459ce61e3d" - integrity sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg== +string.prototype.trim@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782" + integrity sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw== dependencies: define-properties "^1.1.3" - es-abstract "^1.13.0" + es-abstract "^1.17.0-next.1" function-bind "^1.1.1" string.prototype.trim@~1.1.2: @@ -27896,18 +27911,18 @@ string.prototype.trim@~1.1.2: es-abstract "^1.5.0" function-bind "^1.0.2" -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== dependencies: define-properties "^1.1.3" function-bind "^1.1.1" -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== dependencies: define-properties "^1.1.3" function-bind "^1.1.1" @@ -29834,17 +29849,15 @@ typedarray@^0.0.6, typedarray@~0.0.5: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-fsa-reducers@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/typescript-fsa-reducers/-/typescript-fsa-reducers-0.4.5.tgz#58fffb2f6eeca6817c2f656b7e7df2cb1c9d1f84" - integrity sha512-mBIpU4je365qpqp2XWKtNW3rGO/hA4OI+l8vkkXdHLUYukrp3wNeL+e3roUq1F6wa6Kcr0WaMblEQDsIdWHTEQ== - dependencies: - typescript-fsa "^2.0.0" +typescript-fsa-reducers@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/typescript-fsa-reducers/-/typescript-fsa-reducers-1.2.1.tgz#2af1a85f7b88fb0dfb9fa59d5da51a5d7ac6543f" + integrity sha512-Qgn7zEnAU5n3YEWEL5ooEmIWZl9B4QyXD4Y/0DqpUzF0YuTrcsLa7Lht0gFXZ+xqLJXQwo3fEiTfQTDF1fBnMg== -typescript-fsa@^2.0.0, typescript-fsa@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-2.5.0.tgz#1baec01b5e8f5f34c322679d1327016e9e294faf" - integrity sha1-G67AG16PXzTDImedEycBbp4pT68= +typescript-fsa@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-3.0.0.tgz#3ad1cb915a67338e013fc21f67c9b3e0e110c912" + integrity sha512-xiXAib35i0QHl/+wMobzPibjAH5TJLDj+qGq5jwVLG9qR4FUswZURBw2qihBm0m06tHoyb3FzpnJs1GRhRwVag== typescript@3.5.3, typescript@3.7.2, typescript@^3.0.1, typescript@^3.0.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.4.5, typescript@~3.7.2: version "3.7.2"