diff --git a/Jenkinsfile b/Jenkinsfile index 33d8d47f06e8f..08ccc879054bd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,6 +17,8 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a 'oss-ciGroup4': getOssCiGroupWorker(4), 'oss-ciGroup5': getOssCiGroupWorker(5), 'oss-ciGroup6': getOssCiGroupWorker(6), + ]), + 'kibana-oss-agent2': withWorkers('kibana-oss-tests2', { buildOss() }, [ 'oss-ciGroup7': getOssCiGroupWorker(7), 'oss-ciGroup8': getOssCiGroupWorker(8), 'oss-ciGroup9': getOssCiGroupWorker(9), @@ -32,6 +34,8 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a 'xpack-ciGroup3': getXpackCiGroupWorker(3), 'xpack-ciGroup4': getXpackCiGroupWorker(4), 'xpack-ciGroup5': getXpackCiGroupWorker(5), + ]), + 'kibana-xpack-agent2': withWorkers('kibana-xpack-tests2', { buildXpack() }, [ 'xpack-ciGroup6': getXpackCiGroupWorker(6), 'xpack-ciGroup7': getXpackCiGroupWorker(7), 'xpack-ciGroup8': getXpackCiGroupWorker(8), diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md index 63b3ead814f00..f4dee0f29af34 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md +++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.core.md @@ -18,5 +18,8 @@ core: { notifications: NotificationsStart; overlays: OverlayStart; uiSettings: UiSettingsClientContract; + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; }; ``` diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.md index c6541e3eca392..97d143d518f60 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountcontext.md +++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.md @@ -16,5 +16,5 @@ export interface AppMountContext | Property | Type | Description | | --- | --- | --- | -| [core](./kibana-plugin-public.appmountcontext.core.md) | {
application: Pick<ApplicationStart, 'capabilities' | 'navigateToApp'>;
chrome: ChromeStart;
docLinks: DocLinksStart;
http: HttpStart;
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
uiSettings: UiSettingsClientContract;
} | Core service APIs available to mounted applications. | +| [core](./kibana-plugin-public.appmountcontext.core.md) | {
application: Pick<ApplicationStart, 'capabilities' | 'navigateToApp'>;
chrome: ChromeStart;
docLinks: DocLinksStart;
http: HttpStart;
i18n: I18nStart;
notifications: NotificationsStart;
overlays: OverlayStart;
uiSettings: UiSettingsClientContract;
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
};
} | Core service APIs available to mounted applications. | diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.injectedmetadata.md b/docs/development/core/public/kibana-plugin-public.coresetup.injectedmetadata.md new file mode 100644 index 0000000000000..f9c1a283e3808 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.coresetup.injectedmetadata.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreSetup](./kibana-plugin-public.coresetup.md) > [injectedMetadata](./kibana-plugin-public.coresetup.injectedmetadata.md) + +## CoreSetup.injectedMetadata property + +> Warning: This API is now obsolete. +> +> + +exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. + +Signature: + +```typescript +injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; +``` diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.md b/docs/development/core/public/kibana-plugin-public.coresetup.md index 9b94e2db52831..f9335425fed4c 100644 --- a/docs/development/core/public/kibana-plugin-public.coresetup.md +++ b/docs/development/core/public/kibana-plugin-public.coresetup.md @@ -20,6 +20,7 @@ export interface CoreSetup | [context](./kibana-plugin-public.coresetup.context.md) | ContextSetup | [ContextSetup](./kibana-plugin-public.contextsetup.md) | | [fatalErrors](./kibana-plugin-public.coresetup.fatalerrors.md) | FatalErrorsSetup | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) | | [http](./kibana-plugin-public.coresetup.http.md) | HttpSetup | [HttpSetup](./kibana-plugin-public.httpsetup.md) | +| [injectedMetadata](./kibana-plugin-public.coresetup.injectedmetadata.md) | {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
} | exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. | | [notifications](./kibana-plugin-public.coresetup.notifications.md) | NotificationsSetup | [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | | [uiSettings](./kibana-plugin-public.coresetup.uisettings.md) | UiSettingsClientContract | [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) | diff --git a/docs/development/core/public/kibana-plugin-public.corestart.injectedmetadata.md b/docs/development/core/public/kibana-plugin-public.corestart.injectedmetadata.md new file mode 100644 index 0000000000000..9224b97bc4300 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.corestart.injectedmetadata.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [injectedMetadata](./kibana-plugin-public.corestart.injectedmetadata.md) + +## CoreStart.injectedMetadata property + +> Warning: This API is now obsolete. +> +> + +exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. + +Signature: + +```typescript +injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; +``` diff --git a/docs/development/core/public/kibana-plugin-public.corestart.md b/docs/development/core/public/kibana-plugin-public.corestart.md index 5c1626958c4df..47eba78bf43e4 100644 --- a/docs/development/core/public/kibana-plugin-public.corestart.md +++ b/docs/development/core/public/kibana-plugin-public.corestart.md @@ -21,6 +21,7 @@ export interface CoreStart | [docLinks](./kibana-plugin-public.corestart.doclinks.md) | DocLinksStart | [DocLinksStart](./kibana-plugin-public.doclinksstart.md) | | [http](./kibana-plugin-public.corestart.http.md) | HttpStart | [HttpStart](./kibana-plugin-public.httpstart.md) | | [i18n](./kibana-plugin-public.corestart.i18n.md) | I18nStart | [I18nStart](./kibana-plugin-public.i18nstart.md) | +| [injectedMetadata](./kibana-plugin-public.corestart.injectedmetadata.md) | {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
} | exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. | | [notifications](./kibana-plugin-public.corestart.notifications.md) | NotificationsStart | [NotificationsStart](./kibana-plugin-public.notificationsstart.md) | | [overlays](./kibana-plugin-public.corestart.overlays.md) | OverlayStart | [OverlayStart](./kibana-plugin-public.overlaystart.md) | | [savedObjects](./kibana-plugin-public.corestart.savedobjects.md) | SavedObjectsStart | [SavedObjectsStart](./kibana-plugin-public.savedobjectsstart.md) | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md index d8ff7b4c9e2ed..36eba99273997 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.exportSizeLimit property +the maximum number of objects to export. + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md index 1972cc6634b75..d721fc260eaf8 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.includeReferencesDeep property +flag to also include all related saved objects in the export response. + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md index 66f501a0f1433..0f1bd94d01552 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md @@ -16,10 +16,11 @@ export interface SavedObjectsExportOptions | Property | Type | Description | | --- | --- | --- | -| [exportSizeLimit](./kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md) | number | | -| [includeReferencesDeep](./kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md) | boolean | | -| [namespace](./kibana-plugin-server.savedobjectsexportoptions.namespace.md) | string | | -| [objects](./kibana-plugin-server.savedobjectsexportoptions.objects.md) | Array<{
id: string;
type: string;
}> | | -| [savedObjectsClient](./kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md) | SavedObjectsClientContract | | -| [types](./kibana-plugin-server.savedobjectsexportoptions.types.md) | string[] | | +| [exportSizeLimit](./kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md) | number | the maximum number of objects to export. | +| [includeReferencesDeep](./kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md) | boolean | flag to also include all related saved objects in the export response. | +| [namespace](./kibana-plugin-server.savedobjectsexportoptions.namespace.md) | string | optional namespace to override the namespace used by the savedObjectsClient. | +| [objects](./kibana-plugin-server.savedobjectsexportoptions.objects.md) | Array<{
id: string;
type: string;
}> | optional array of objects to export. | +| [savedObjectsClient](./kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md) | SavedObjectsClientContract | an instance of the SavedObjectsClient. | +| [search](./kibana-plugin-server.savedobjectsexportoptions.search.md) | string | optional query string to filter exported objects. | +| [types](./kibana-plugin-server.savedobjectsexportoptions.types.md) | string[] | optional array of saved object types. | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md index b5abfba7f6910..1a28cc92e6e7e 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.namespace property +optional namespace to override the namespace used by the savedObjectsClient. + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md index 46cb62841d46c..cd32f66c0f81e 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.objects property +optional array of objects to export. + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md index fc206d0f7e877..1e0dd6c6f164f 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.savedObjectsClient property +an instance of the SavedObjectsClient. + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md new file mode 100644 index 0000000000000..5e44486ee65e0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsExportOptions](./kibana-plugin-server.savedobjectsexportoptions.md) > [search](./kibana-plugin-server.savedobjectsexportoptions.search.md) + +## SavedObjectsExportOptions.search property + +optional query string to filter exported objects. + +Signature: + +```typescript +search?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md index 204402fe355e3..cf1eb676f7ab8 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md @@ -4,6 +4,8 @@ ## SavedObjectsExportOptions.types property +optional array of saved object types. + Signature: ```typescript diff --git a/package.json b/package.json index 15b5fb133f561..b90b1ec44a42b 100644 --- a/package.json +++ b/package.json @@ -247,7 +247,7 @@ "tslib": "^1.9.3", "type-detect": "^4.0.8", "ui-select": "0.19.8", - "url-loader": "2.1.0", + "url-loader": "2.2.0", "uuid": "3.3.2", "val-loader": "^1.1.1", "validate-npm-package-name": "2.2.2", @@ -256,8 +256,8 @@ "vega-schema-url-parser": "1.0.0", "vega-tooltip": "^0.9.14", "vision": "^5.3.3", - "webpack": "4.39.2", - "webpack-merge": "4.2.1", + "webpack": "4.41.0", + "webpack-merge": "4.2.2", "whatwg-fetch": "^3.0.0", "yauzl": "2.10.0" }, @@ -336,7 +336,7 @@ "@types/redux-actions": "^2.2.1", "@types/request": "^2.48.2", "@types/rimraf": "^2.0.2", - "@types/selenium-webdriver": "^3.0.16", + "@types/selenium-webdriver": "^4.0.3", "@types/semver": "^5.5.0", "@types/sinon": "^7.0.13", "@types/strip-ansi": "^3.0.0", @@ -344,6 +344,7 @@ "@types/supertest": "^2.0.5", "@types/type-detect": "^4.0.1", "@types/uuid": "^3.4.4", + "@types/vinyl-fs": "^2.4.11", "@types/zen-observable": "^0.8.0", "@typescript-eslint/eslint-plugin": "1.13.0", "@typescript-eslint/parser": "1.13.0", @@ -356,7 +357,7 @@ "chai": "3.5.0", "chance": "1.0.18", "cheerio": "0.22.0", - "chokidar": "3.0.2", + "chokidar": "3.2.1", "chromedriver": "^77.0.0", "classnames": "2.2.6", "dedent": "^0.7.0", @@ -395,6 +396,7 @@ "gulp-babel": "^8.0.0", "gulp-sourcemaps": "2.6.5", "has-ansi": "^3.0.0", + "iedriver": "^3.14.1", "image-diff": "1.6.3", "intl-messageformat-parser": "^1.4.0", "is-path-inside": "^2.1.0", @@ -433,7 +435,7 @@ "proxyquire": "1.8.0", "regenerate": "^1.4.0", "sass-lint": "^1.12.1", - "selenium-webdriver": "^4.0.0-alpha.4", + "selenium-webdriver": "^4.0.0-alpha.5", "simple-git": "1.116.0", "sinon": "^7.4.2", "strip-ansi": "^3.0.1", diff --git a/packages/kbn-es/package.json b/packages/kbn-es/package.json index 7c0b960d18093..5521d57c22e86 100644 --- a/packages/kbn-es/package.json +++ b/packages/kbn-es/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "private": true, "dependencies": { - "@elastic/elasticsearch": "^7.3.0", + "@elastic/elasticsearch": "^7.4.0", "@kbn/dev-utils": "1.0.0", "abort-controller": "^2.0.3", "chalk": "^2.4.2", diff --git a/packages/kbn-eslint-import-resolver-kibana/package.json b/packages/kbn-eslint-import-resolver-kibana/package.json index 14a9224924260..9fae27011767e 100755 --- a/packages/kbn-eslint-import-resolver-kibana/package.json +++ b/packages/kbn-eslint-import-resolver-kibana/package.json @@ -16,6 +16,6 @@ "glob-all": "^3.1.0", "lru-cache": "^4.1.5", "resolve": "^1.7.1", - "webpack": "^4.39.2" + "webpack": "^4.41.0" } } diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index ab382c1390ff7..3e152e29d8e08 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -30,8 +30,8 @@ "sass-loader": "^7.3.1", "style-loader": "0.23.1", "supports-color": "^5.5.0", - "url-loader": "2.1.0", - "webpack": "4.39.2", - "webpack-cli": "^3.3.7" + "url-loader": "2.2.0", + "webpack": "4.41.0", + "webpack-cli": "^3.3.9" } } diff --git a/packages/kbn-plugin-helpers/lib/index.d.ts b/packages/kbn-plugin-helpers/lib/index.d.ts new file mode 100644 index 0000000000000..1515bf6b84bfb --- /dev/null +++ b/packages/kbn-plugin-helpers/lib/index.d.ts @@ -0,0 +1,26 @@ +/* + * 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 function babelRegister(): void; +export function resolveKibanaPath(path: string): string; +export function readFtrConfigFile(path: string): any; +export function run( + task: 'build' | 'start' | 'testAll' | 'testBrowser' | 'testServer' | 'postinstall', + options: any +): Promise; diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index c72b3d2abed97..eca958d3860ee 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -21,7 +21,7 @@ "globby": "^8.0.1", "gulp-babel": "^8.0.0", "gulp-rename": "1.4.0", - "gulp-zip": "4.2.0", + "gulp-zip": "5.0.1", "inquirer": "^1.2.2", "minimatch": "^3.0.4", "node-sass": "^4.9.4", diff --git a/packages/kbn-plugin-helpers/tsconfig.json b/packages/kbn-plugin-helpers/tsconfig.json new file mode 100644 index 0000000000000..f5559aa7290c5 --- /dev/null +++ b/packages/kbn-plugin-helpers/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["lib/index.d.ts"] +} diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index 9f80600fddcb1..8480e74ceb3a2 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -51,7 +51,7 @@ "log-symbols": "^2.2.0", "ncp": "^2.0.0", "ora": "^1.4.0", - "prettier": "^1.14.3", + "prettier": "^1.18.2", "read-pkg": "^5.2.0", "rxjs": "^6.2.1", "spawn-sync": "^1.0.15", @@ -61,8 +61,8 @@ "tempy": "^0.3.0", "typescript": "3.5.3", "unlazy-loader": "^0.1.3", - "webpack": "^4.39.2", - "webpack-cli": "^3.3.7", + "webpack": "^4.41.0", + "webpack-cli": "^3.3.9", "wrap-ansi": "^3.0.1", "write-pkg": "^4.0.0" }, diff --git a/packages/kbn-spec-to-console/package.json b/packages/kbn-spec-to-console/package.json index e40ea4dcd4fff..0bc38fd402384 100644 --- a/packages/kbn-spec-to-console/package.json +++ b/packages/kbn-spec-to-console/package.json @@ -18,7 +18,7 @@ "homepage": "https://github.com/jbudz/spec-to-console#readme", "devDependencies": { "jest": "^24.9.0", - "prettier": "^1.14.3" + "prettier": "^1.18.2" }, "dependencies": { "commander": "^2.11.0", diff --git a/src/legacy/ui/public/persisted_log/recently_accessed.ts b/packages/kbn-test/index.d.ts similarity index 87% rename from src/legacy/ui/public/persisted_log/recently_accessed.ts rename to packages/kbn-test/index.d.ts index 6d984d155d551..aa55df9215c2f 100644 --- a/src/legacy/ui/public/persisted_log/recently_accessed.ts +++ b/packages/kbn-test/index.d.ts @@ -17,6 +17,4 @@ * under the License. */ -import { npStart } from '../new_platform'; - -export const recentlyAccessed = npStart.core.chrome.recentlyAccessed; +export * from './src/index'; diff --git a/packages/kbn-test/package.json b/packages/kbn-test/package.json index 6891f01bae2a9..d02b2cf41d3f8 100644 --- a/packages/kbn-test/package.json +++ b/packages/kbn-test/package.json @@ -21,7 +21,7 @@ "getopts": "^2.2.4", "glob": "^7.1.2", "rxjs": "^6.2.1", - "tar-fs": "^1.16.2", + "tar-fs": "^1.16.3", "tmp": "^0.1.0", "zlib": "^1.0.5" } diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts index d9cf282d8f4b6..52672d5f039fb 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts @@ -134,7 +134,7 @@ export const schema = Joi.object() browser: Joi.object() .keys({ type: Joi.string() - .valid('chrome', 'firefox') + .valid('chrome', 'firefox', 'ie') .default('chrome'), logPollingMs: Joi.number().default(100), diff --git a/packages/kbn-test/src/index.js b/packages/kbn-test/src/index.ts similarity index 86% rename from packages/kbn-test/src/index.js rename to packages/kbn-test/src/index.ts index e8cc694f5252e..7330789bb2352 100644 --- a/packages/kbn-test/src/index.js +++ b/packages/kbn-test/src/index.ts @@ -17,18 +17,26 @@ * under the License. */ +// @ts-ignore not typed yet export { runTestsCli, startServersCli } from './functional_tests/cli'; +// @ts-ignore not typed yet export { runTests, startServers } from './functional_tests/tasks'; +// @ts-ignore not typed yet export { OPTIMIZE_BUNDLE_DIR, KIBANA_ROOT } from './functional_tests/lib/paths'; +// @ts-ignore not typed yet export { esTestConfig, createEsTestCluster } from './es'; +// @ts-ignore not typed yet export { kbnTestConfig, kibanaServerTestUser, kibanaTestUser, adminTestUser } from './kbn'; +// @ts-ignore not typed yet export { setupUsers, DEFAULT_SUPERUSER_PASS } from './functional_tests/lib/auth'; +// @ts-ignore not typed yet export { readConfigFile } from './functional_test_runner/lib/config/read_config_file'; +// @ts-ignore not typed yet export { runFtrCli } from './functional_test_runner/cli'; diff --git a/packages/kbn-test/tsconfig.json b/packages/kbn-test/tsconfig.json index 83a0fe04a4b5f..fdb53de52687b 100644 --- a/packages/kbn-test/tsconfig.json +++ b/packages/kbn-test/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "include": [ "types/**/*", - "src/functional_test_runner/**/*" + "src/**/*", + "index.d.ts" ] } diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index bd9658934100d..cb4d2e3cadf95 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -37,7 +37,7 @@ "babel-loader": "^8.0.6", "brace": "0.11.1", "chalk": "^2.4.2", - "chokidar": "3.0.2", + "chokidar": "3.2.1", "core-js": "^3.2.1", "css-loader": "^2.1.1", "expose-loader": "^0.7.5", @@ -68,8 +68,8 @@ "sass-loader": "^7.3.1", "sinon": "^7.4.2", "style-loader": "^0.23.1", - "webpack": "^4.39.2", - "webpack-dev-server": "^3.8.0", + "webpack": "^4.41.0", + "webpack-dev-server": "^3.8.2", "yeoman-generator": "1.1.1", "yo": "2.0.6" } diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index b2d0aff26b8b0..5b1d4affe8840 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -114,6 +114,15 @@ export interface AppMountContext { overlays: OverlayStart; /** {@link UiSettingsClient} */ uiSettings: UiSettingsClientContract; + /** + * exposed temporarily until https://github.com/elastic/kibana/issues/41990 done + * use *only* to retrieve config values. There is no way to set injected values + * in the new platform. Use the legacy platform API instead. + * @deprecated + * */ + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; }; } diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 7b9ed50f09591..7a87f97208a7a 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -236,6 +236,7 @@ export class CoreSystem { notifications, overlays, uiSettings, + injectedMetadata: pick(injectedMetadata, ['getInjectedVar']), })); const core: InternalCoreStart = { diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 82b87a69b57d7..dfdd6f8797f27 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -146,6 +146,15 @@ export interface CoreSetup { notifications: NotificationsSetup; /** {@link UiSettingsClient} */ uiSettings: UiSettingsClientContract; + /** + * exposed temporarily until https://github.com/elastic/kibana/issues/41990 done + * use *only* to retrieve config values. There is no way to set injected values + * in the new platform. Use the legacy platform API instead. + * @deprecated + * */ + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; } /** @@ -176,6 +185,15 @@ export interface CoreStart { overlays: OverlayStart; /** {@link UiSettingsClient} */ uiSettings: UiSettingsClientContract; + /** + * exposed temporarily until https://github.com/elastic/kibana/issues/41990 done + * use *only* to retrieve config values. There is no way to set injected values + * in the new platform. Use the legacy platform API instead. + * @deprecated + * */ + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; } /** diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 7c99f69d6fd7a..8ce163fd59e14 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -28,6 +28,7 @@ import { overlayServiceMock } from './overlays/overlay_service.mock'; import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; import { savedObjectsMock } from './saved_objects/saved_objects_service.mock'; import { contextServiceMock } from './context/context_service.mock'; +import { injectedMetadataServiceMock } from './injected_metadata/injected_metadata_service.mock'; export { chromeServiceMock } from './chrome/chrome_service.mock'; export { docLinksServiceMock } from './doc_links/doc_links_service.mock'; @@ -48,6 +49,9 @@ function createCoreSetupMock() { http: httpServiceMock.createSetupContract(), notifications: notificationServiceMock.createSetupContract(), uiSettings: uiSettingsServiceMock.createSetupContract(), + injectedMetadata: { + getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar, + }, }; return mock; @@ -64,6 +68,9 @@ function createCoreStartMock() { overlays: overlayServiceMock.createStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), savedObjects: savedObjectsMock.createStartContract(), + injectedMetadata: { + getInjectedVar: injectedMetadataServiceMock.createStartContract().getInjectedVar, + }, }; return mock; diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index f4e25d27447bc..51bd118d280e3 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -86,6 +86,9 @@ export function createPluginSetupContext< http: deps.http, notifications: deps.notifications, uiSettings: deps.uiSettings, + injectedMetadata: { + getInjectedVar: deps.injectedMetadata.getInjectedVar, + }, }; } @@ -125,5 +128,8 @@ export function createPluginStartContext< overlays: deps.overlays, uiSettings: deps.uiSettings, savedObjects: deps.savedObjects, + injectedMetadata: { + getInjectedVar: deps.injectedMetadata.getInjectedVar, + }, }; } diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index d6411554e5f85..358bf71ac9188 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { omit } from 'lodash'; +import { omit, pick } from 'lodash'; import { MockedPluginInitializer, @@ -76,12 +76,12 @@ beforeEach(() => { context: contextServiceMock.createSetupContract(), fatalErrors: fatalErrorsServiceMock.createSetupContract(), http: httpServiceMock.createSetupContract(), - injectedMetadata: injectedMetadataServiceMock.createSetupContract(), + injectedMetadata: pick(injectedMetadataServiceMock.createStartContract(), 'getInjectedVar'), notifications: notificationServiceMock.createSetupContract(), uiSettings: uiSettingsServiceMock.createSetupContract(), }; mockSetupContext = { - ...omit(mockSetupDeps, 'injectedMetadata'), + ...mockSetupDeps, application: expect.any(Object), }; mockStartDeps = { @@ -90,14 +90,14 @@ beforeEach(() => { http: httpServiceMock.createStartContract(), chrome: chromeServiceMock.createStartContract(), i18n: i18nServiceMock.createStartContract(), - injectedMetadata: injectedMetadataServiceMock.createStartContract(), + injectedMetadata: pick(injectedMetadataServiceMock.createStartContract(), 'getInjectedVar'), notifications: notificationServiceMock.createStartContract(), overlays: overlayServiceMock.createStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), savedObjects: savedObjectsMock.createStartContract(), }; mockStartContext = { - ...omit(mockStartDeps, 'injectedMetadata'), + ...mockStartDeps, application: expect.any(Object), chrome: omit(mockStartDeps.chrome, 'getComponent'), }; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index e6c8f116e5782..0156cbaebb949 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -59,6 +59,9 @@ export interface AppMountContext { notifications: NotificationsStart; overlays: OverlayStart; uiSettings: UiSettingsClientContract; + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; }; } @@ -235,6 +238,10 @@ export interface CoreSetup { fatalErrors: FatalErrorsSetup; // (undocumented) http: HttpSetup; + // @deprecated + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; // (undocumented) notifications: NotificationsSetup; // (undocumented) @@ -253,6 +260,10 @@ export interface CoreStart { http: HttpStart; // (undocumented) i18n: I18nStart; + // @deprecated + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + }; // (undocumented) notifications: NotificationsStart; // (undocumented) diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts index ad2a0e469ddd8..df3bbe7c455e4 100644 --- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts +++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts @@ -96,29 +96,114 @@ describe('getSortedObjectsForExport()', () => { ] `); expect(savedObjectsClient.find).toMatchInlineSnapshot(` - [MockFunction] { - "calls": Array [ - Array [ + [MockFunction] { + "calls": Array [ + Array [ + Object { + "namespace": undefined, + "perPage": 500, + "search": undefined, + "sortField": "_id", + "sortOrder": "asc", + "type": Array [ + "index-pattern", + "search", + ], + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + } + `); + }); + + test('exports selected types with search string when present', async () => { + savedObjectsClient.find.mockResolvedValueOnce({ + total: 2, + saved_objects: [ + { + id: '2', + type: 'search', + attributes: {}, + references: [ + { + name: 'name', + type: 'index-pattern', + id: '1', + }, + ], + }, + { + id: '1', + type: 'index-pattern', + attributes: {}, + references: [], + }, + ], + per_page: 1, + page: 0, + }); + const exportStream = await getSortedObjectsForExport({ + savedObjectsClient, + exportSizeLimit: 500, + types: ['index-pattern', 'search'], + search: 'foo', + }); + + const response = await readStreamToCompletion(exportStream); + + expect(response).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ Object { - "namespace": undefined, - "perPage": 500, - "sortField": "_id", - "sortOrder": "asc", - "type": Array [ - "index-pattern", - "search", - ], + "id": "1", + "name": "name", + "type": "index-pattern", }, ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - } + "type": "search", + }, + ] `); + expect(savedObjectsClient.find).toMatchInlineSnapshot(` + [MockFunction] { + "calls": Array [ + Array [ + Object { + "namespace": undefined, + "perPage": 500, + "search": "foo", + "sortField": "_id", + "sortOrder": "asc", + "type": Array [ + "index-pattern", + "search", + ], + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + } + `); }); test('exports from the provided namespace when present', async () => { @@ -179,29 +264,30 @@ describe('getSortedObjectsForExport()', () => { ] `); expect(savedObjectsClient.find).toMatchInlineSnapshot(` - [MockFunction] { - "calls": Array [ - Array [ - Object { - "namespace": "foo", - "perPage": 500, - "sortField": "_id", - "sortOrder": "asc", - "type": Array [ - "index-pattern", - "search", - ], - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, + [MockFunction] { + "calls": Array [ + Array [ + Object { + "namespace": "foo", + "perPage": 500, + "search": undefined, + "sortField": "_id", + "sortOrder": "asc", + "type": Array [ + "index-pattern", + "search", ], - } - `); + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + } + `); }); test('export selected types throws error when exceeding exportSizeLimit', async () => { @@ -464,4 +550,17 @@ describe('getSortedObjectsForExport()', () => { `"Either \`type\` or \`objects\` are required."` ); }); + + test('rejects when both objects and search are passed in', () => { + const exportOpts = { + exportSizeLimit: 1, + savedObjectsClient, + objects: [{ type: 'index-pattern', id: '1' }], + search: 'foo', + }; + + expect(getSortedObjectsForExport(exportOpts)).rejects.toThrowErrorMatchingInlineSnapshot( + `"Can't specify both \\"search\\" and \\"objects\\" properties when exporting"` + ); + }); }); diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts index b4e7c2887fd3a..eca8fc0405300 100644 --- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts +++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts @@ -28,26 +28,38 @@ import { sortObjects } from './sort_objects'; * @public */ export interface SavedObjectsExportOptions { + /** optional array of saved object types. */ types?: string[]; + /** optional array of objects to export. */ objects?: Array<{ + /** the saved object id. */ id: string; + /** the saved object type. */ type: string; }>; + /** optional query string to filter exported objects. */ + search?: string; + /** an instance of the SavedObjectsClient. */ savedObjectsClient: SavedObjectsClientContract; + /** the maximum number of objects to export. */ exportSizeLimit: number; + /** flag to also include all related saved objects in the export response. */ includeReferencesDeep?: boolean; + /** optional namespace to override the namespace used by the savedObjectsClient. */ namespace?: string; } async function fetchObjectsToExport({ objects, types, + search, exportSizeLimit, savedObjectsClient, namespace, }: { objects?: SavedObjectsExportOptions['objects']; types?: string[]; + search?: string; exportSizeLimit: number; savedObjectsClient: SavedObjectsClientContract; namespace?: string; @@ -56,6 +68,9 @@ async function fetchObjectsToExport({ if (objects.length > exportSizeLimit) { throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`); } + if (typeof search === 'string') { + throw Boom.badRequest(`Can't specify both "search" and "objects" properties when exporting`); + } const bulkGetResult = await savedObjectsClient.bulkGet(objects, { namespace }); const erroredObjects = bulkGetResult.saved_objects.filter(obj => !!obj.error); if (erroredObjects.length) { @@ -69,6 +84,7 @@ async function fetchObjectsToExport({ } else if (types && types.length > 0) { const findResponse = await savedObjectsClient.find({ type: types, + search, sortField: '_id', sortOrder: 'asc', perPage: exportSizeLimit, @@ -86,6 +102,7 @@ async function fetchObjectsToExport({ export async function getSortedObjectsForExport({ types, objects, + search, savedObjectsClient, exportSizeLimit, includeReferencesDeep = false, @@ -94,6 +111,7 @@ export async function getSortedObjectsForExport({ const objectsToExport = await fetchObjectsToExport({ types, objects, + search, savedObjectsClient, exportSizeLimit, namespace, diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 6451e2b9b7153..79728ecc8fb98 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -820,20 +820,15 @@ export class SavedObjectsErrorHelpers { // @public export interface SavedObjectsExportOptions { - // (undocumented) exportSizeLimit: number; - // (undocumented) includeReferencesDeep?: boolean; - // (undocumented) namespace?: string; - // (undocumented) objects?: Array<{ id: string; type: string; }>; - // (undocumented) savedObjectsClient: SavedObjectsClientContract; - // (undocumented) + search?: string; types?: string[]; } diff --git a/src/dev/index.ts b/src/dev/index.ts new file mode 100644 index 0000000000000..4586cc2a2ff76 --- /dev/null +++ b/src/dev/index.ts @@ -0,0 +1,25 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore not typed yet +export { createAutoJUnitReporter } from './auto_junit_reporter'; +// @ts-ignore not typed yet +export { setupJUnitReportGeneration } from './junit_report_generation'; +// @ts-ignore not typed yet +export { runMochaCli } from './run_mocha_cli'; diff --git a/src/dev/mocha/index.js b/src/dev/mocha/index.js index 9f99f56831263..4586cc2a2ff76 100644 --- a/src/dev/mocha/index.js +++ b/src/dev/mocha/index.js @@ -17,6 +17,9 @@ * under the License. */ +// @ts-ignore not typed yet export { createAutoJUnitReporter } from './auto_junit_reporter'; +// @ts-ignore not typed yet export { setupJUnitReportGeneration } from './junit_report_generation'; +// @ts-ignore not typed yet export { runMochaCli } from './run_mocha_cli'; diff --git a/src/dev/notice/generate_notice_from_source.js b/src/dev/notice/generate_notice_from_source.ts similarity index 83% rename from src/dev/notice/generate_notice_from_source.js rename to src/dev/notice/generate_notice_from_source.ts index ba1492b9d8260..08384e1e159f3 100644 --- a/src/dev/notice/generate_notice_from_source.js +++ b/src/dev/notice/generate_notice_from_source.ts @@ -18,25 +18,30 @@ */ import vfs from 'vinyl-fs'; +import { ToolingLog } from '@kbn/dev-utils'; const NOTICE_COMMENT_RE = /\/\*[\s\n\*]*@notice([\w\W]+?)\*\//g; const NEWLINE_RE = /\r?\n/g; +interface Options { + /** + * Name to print at the top of the notice + */ + productName: string; + /** + * absolute path to the repo to search for @notice comments + */ + directory: string; + log: ToolingLog; +} + /** * Generates the text for the NOTICE.txt file at the root of the * repo which details the licenses for code that is copied/vendored * into the repository. - * - * @param {Object} options - * @property {string} options.productName Name to print at the top of the notice - * @property {ToolingLog} options.log - * @property {string} options.directory absolute path to the repo to search for @notice comments - * @return {string} */ -export async function generateNoticeFromSource({ productName, directory, log }) { - const globs = [ - '**/*.{js,less,css,ts}', - ]; +export async function generateNoticeFromSource({ productName, directory, log }: Options) { + const globs = ['**/*.{js,less,css,ts}']; const options = { cwd: directory, @@ -46,7 +51,7 @@ export async function generateNoticeFromSource({ productName, directory, log }) 'packages/*/{node_modules,build,target,dist}/**', 'x-pack/{node_modules,build,target,dist,optimize}/**', 'x-pack/packages/*/{node_modules,build,target,dist}/**', - ] + ], }; log.debug('vfs.src globs', globs); @@ -54,10 +59,10 @@ export async function generateNoticeFromSource({ productName, directory, log }) log.info(`Searching ${directory} for multi-line comments starting with @notice`); const files = vfs.src(globs, options); - const noticeComments = []; + const noticeComments: string[] = []; await new Promise((resolve, reject) => { files - .on('data', (file) => { + .on('data', file => { log.verbose(`Checking for @notice comments in ${file.relative}`); const source = file.contents.toString('utf8'); @@ -75,19 +80,19 @@ export async function generateNoticeFromSource({ productName, directory, log }) let noticeText = ''; noticeText += `${productName}\n`; - noticeText += `Copyright 2012-${(new Date()).getUTCFullYear()} Elasticsearch B.V.\n`; + noticeText += `Copyright 2012-${new Date().getUTCFullYear()} Elasticsearch B.V.\n`; for (const comment of noticeComments.sort()) { noticeText += '\n---\n'; noticeText += comment .split(NEWLINE_RE) - .map(line => ( + .map(line => line // trim whitespace .trim() // trim leading * and a single space .replace(/(^\* ?)/, '') - )) + ) .join('\n') .trim(); noticeText += '\n'; diff --git a/src/dev/notice/index.js b/src/dev/notice/index.ts similarity index 97% rename from src/dev/notice/index.js rename to src/dev/notice/index.ts index 17fbd20c22061..9f3fd61a9831e 100644 --- a/src/dev/notice/index.js +++ b/src/dev/notice/index.ts @@ -18,4 +18,5 @@ */ export { generateNoticeFromSource } from './generate_notice_from_source'; +// @ts-ignore not typed yet export { generateBuildNoticeText } from './generate_build_notice_text'; diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx index 90dec12fb814d..066adb1e3275e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx @@ -31,12 +31,13 @@ import { import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import classNames from 'classnames'; import React, { useState } from 'react'; -import { UiSettingsClientContract } from 'src/core/public'; +import { CoreStart } from 'src/core/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { IndexPattern } from '../../index_patterns'; import { FilterEditor } from './filter_editor'; import { FilterItem } from './filter_item'; import { FilterOptions } from './filter_options'; -import { useKibana } from '../../../../../../plugins/kibana_react/public'; +import { useKibana, KibanaContextProvider } from '../../../../../../plugins/kibana_react/public'; interface Props { filters: Filter[]; @@ -45,18 +46,45 @@ interface Props { indexPatterns: IndexPattern[]; intl: InjectedIntl; - // Only for directives! - uiSettings?: UiSettingsClientContract; + // TODO: Only for filter-bar directive! + uiSettings?: CoreStart['uiSettings']; + docLinks?: CoreStart['docLinks']; + pluginDataStart?: DataPublicPluginStart; } function FilterBarUI(props: Props) { const [isAddFilterPopoverOpen, setIsAddFilterPopoverOpen] = useState(false); const kibana = useKibana(); - let { uiSettings } = kibana.services; - if (!uiSettings) { - // Only for directives! - uiSettings = props.uiSettings; + const uiSettings = kibana.services.uiSettings || props.uiSettings; + if (!uiSettings) return null; + + function hasContext() { + return Boolean(kibana.services.uiSettings); + } + + function wrapInContextIfMissing(content: JSX.Element) { + // TODO: Relevant only as long as directives are used! + if (!hasContext()) { + if (props.docLinks && props.uiSettings && props.pluginDataStart) { + return ( + + {content} + + ); + } else { + throw new Error( + 'Rending filter bar requires providing sufficient context: uiSettings, docLinks and NP data plugin' + ); + } + } + return content; } function onFiltersUpdated(filters: Filter[]) { @@ -100,7 +128,7 @@ function FilterBarUI(props: Props) { ); - return ( + return wrapInContextIfMissing( setIsAddFilterPopoverOpen(false)} key={JSON.stringify(newFilter)} - uiSettings={uiSettings!} /> diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index 64487df5b22d4..5b295a759d694 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -36,7 +36,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { get } from 'lodash'; import React, { Component } from 'react'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; import { @@ -62,7 +61,6 @@ interface Props { onSubmit: (filter: Filter) => void; onCancel: () => void; intl: InjectedIntl; - uiSettings: UiSettingsClientContract; } interface State { @@ -343,7 +341,6 @@ class FilterEditorUI extends Component { value={this.state.params} onChange={this.onParamsChange} data-test-subj="phraseValueInput" - uiSettings={this.props.uiSettings} /> ); case 'phrases': @@ -353,7 +350,6 @@ class FilterEditorUI extends Component { field={this.state.selectedField} values={this.state.params} onChange={this.onParamsChange} - uiSettings={this.props.uiSettings} /> ); case 'range': diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx index 6b262c66402f2..9ef5f546c0be0 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx @@ -18,14 +18,17 @@ */ import { Component } from 'react'; -import { getSuggestions } from 'ui/value_suggestions'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; +import { IDataPluginServices } from '../../../types'; export interface PhraseSuggestorProps { + kibana: KibanaReactContextValue; indexPattern: IndexPattern; field?: Field; - uiSettings: UiSettingsClientContract; } export interface PhraseSuggestorState { @@ -38,10 +41,11 @@ export interface PhraseSuggestorState { * aggregatable), we pull out the common logic for requesting suggestions into this component * which both of them extend. */ -export class PhraseSuggestor extends Component< +export class PhraseSuggestorUI extends Component< T, PhraseSuggestorState > { + private services = this.props.kibana.services; public state: PhraseSuggestorState = { suggestions: [], isLoading: false, @@ -52,7 +56,7 @@ export class PhraseSuggestor extends Component< } protected isSuggestingValues() { - const shouldSuggestValues = this.props.uiSettings.get('filterEditor:suggestValues'); + const shouldSuggestValues = this.services.uiSettings.get('filterEditor:suggestValues'); const { field } = this.props; return shouldSuggestValues && field && field.aggregatable && field.type === 'string'; } @@ -67,7 +71,9 @@ export class PhraseSuggestor extends Component< return; } this.setState({ isLoading: true }); - const suggestions = await getSuggestions(indexPattern.title, field, value); + const suggestions = await this.services.data.getSuggestions(indexPattern.title, field, value); this.setState({ suggestions, isLoading: false }); } } + +export const PhraseSuggestor = withKibana(PhraseSuggestorUI); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx index 0696bacc568b5..7ef51f88ba57e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx @@ -22,8 +22,9 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; import { ValueInputType } from './value_input_type'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { value?: string; @@ -31,7 +32,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhraseValueInputUI extends PhraseSuggestor { +class PhraseValueInputUI extends PhraseSuggestorUI { public render() { return ( ) { return GenericComboBox(props); } -export const PhraseValueInput = injectI18n(PhraseValueInputUI); +export const PhraseValueInput = injectI18n(withKibana(PhraseValueInputUI)); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx index d35e49b6b07ce..f3b30e2ad5fd9 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx @@ -22,7 +22,8 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { values?: string[]; @@ -30,7 +31,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhrasesValuesInputUI extends PhraseSuggestor { +class PhrasesValuesInputUI extends PhraseSuggestorUI { public render() { const { suggestions } = this.state; const { values, intl, onChange } = this.props; @@ -64,4 +65,4 @@ function StringComboBox(props: GenericComboBoxProps) { return GenericComboBox(props); } -export const PhrasesValuesInput = injectI18n(PhrasesValuesInputUI); +export const PhrasesValuesInput = injectI18n(withKibana(PhrasesValuesInputUI)); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx index 250f6ad209fa7..21259cec51d3a 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx @@ -171,7 +171,6 @@ class FilterItemUI extends Component { indexPatterns={this.props.indexPatterns} onSubmit={this.onSubmit} onCancel={this.closePopover} - uiSettings={this.props.uiSettings} /> ), diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index a5aa55673cac6..7f2c92cb5c6fe 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -107,6 +107,7 @@ export class DataPlugin const timefilterService = this.timefilter.setup({ uiSettings, + store: __LEGACY.storage, }); this.setupApi = { indexPatterns: indexPatternsService, @@ -126,10 +127,10 @@ export class DataPlugin public start(core: CoreStart, { __LEGACY, data }: DataPluginStartDependencies) { const SearchBar = createSearchBar({ core, + data, store: __LEGACY.storage, timefilter: this.setupApi.timefilter, filterManager: this.setupApi.filter.filterManager, - autocomplete: data.autocomplete, }); return { diff --git a/src/legacy/ui/public/persisted_log/index.ts b/src/legacy/core_plugins/data/public/query/persisted_log/index.ts similarity index 88% rename from src/legacy/ui/public/persisted_log/index.ts rename to src/legacy/core_plugins/data/public/query/persisted_log/index.ts index 52de69b9c50bf..9b21c748da02d 100644 --- a/src/legacy/ui/public/persisted_log/index.ts +++ b/src/legacy/core_plugins/data/public/query/persisted_log/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { PersistedLog } from './persisted_log'; -export { recentlyAccessed } from './recently_accessed'; +export * from './persisted_log'; diff --git a/src/legacy/ui/public/persisted_log/persisted_log.test.ts b/src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.test.ts similarity index 100% rename from src/legacy/ui/public/persisted_log/persisted_log.test.ts rename to src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.test.ts diff --git a/src/legacy/ui/public/persisted_log/persisted_log.ts b/src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.ts similarity index 95% rename from src/legacy/ui/public/persisted_log/persisted_log.ts rename to src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.ts index 0824d17757311..e0e6a0d0c44e4 100644 --- a/src/legacy/ui/public/persisted_log/persisted_log.ts +++ b/src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.ts @@ -20,9 +20,7 @@ import _ from 'lodash'; import * as Rx from 'rxjs'; import { map } from 'rxjs/operators'; -import { Storage } from 'ui/storage'; - -const localStorage = new Storage(window.localStorage); +import { Storage } from '../../types'; const defaultIsDuplicate = (oldItem: any, newItem: any) => { return _.isEqual(oldItem, newItem); @@ -44,7 +42,7 @@ export class PersistedLog { private update$ = new Rx.BehaviorSubject(undefined); - constructor(name: string, options: PersistedLogOptions = {}, storage = localStorage) { + constructor(name: string, options: PersistedLogOptions = {}, storage: Storage) { this.name = name; this.maxLength = typeof options.maxLength === 'string' diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.mocks.ts b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.mocks.ts index 683ced28dba97..80ee38ea1b076 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.mocks.ts +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.mocks.ts @@ -45,7 +45,7 @@ export const mockFetchIndexPatterns = jest .fn() .mockReturnValue(Promise.resolve([mockIndexPattern])); -jest.mock('ui/persisted_log', () => ({ +jest.mock('../../persisted_log', () => ({ PersistedLog: mockPersistedLogFactory, })); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 3cdd8d4b9c40c..1b232128c744a 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -25,7 +25,6 @@ import { EuiFieldText, EuiOutsideClickDetector, PopoverAnchorPosition } from '@e import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { debounce, compact, isEqual } from 'lodash'; -import { PersistedLog } from 'ui/persisted_log'; import { AutocompleteSuggestion, @@ -36,11 +35,11 @@ import { KibanaReactContextValue, } from '../../../../../../../plugins/kibana_react/public'; import { IndexPattern, StaticIndexPattern } from '../../../index_patterns'; -import { Query } from '../index'; +import { Query, getQueryLog } from '../index'; import { fromUser, matchPairs, toUser } from '../lib'; import { QueryLanguageSwitcher } from './language_switcher'; import { SuggestionsComponent } from './typeahead/suggestions_component'; -import { getQueryLog } from '../lib/get_query_log'; +import { PersistedLog } from '../../persisted_log'; import { fetchIndexPatterns } from '../lib/fetch_index_patterns'; import { IDataPluginServices } from '../../../types'; @@ -135,8 +134,8 @@ export class QueryBarInputUI extends Component { const queryString = this.getQueryString(); const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); + const autocompleteProvider = this.services.data.autocomplete.getProvider(language); - const autocompleteProvider = this.services.autocomplete.getProvider(language); if ( !autocompleteProvider || !Array.isArray(this.state.indexPatterns) || @@ -392,6 +391,7 @@ export class QueryBarInputUI extends Component { }; public componentDidMount() { + const { uiSettings, store, appName } = this.services; const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); @@ -399,12 +399,13 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.services.uiSettings, this.services.appName, this.props.query.language); + : getQueryLog(uiSettings, store, appName, this.props.query.language); this.fetchIndexPatterns().then(this.updateSuggestions); } public componentDidUpdate(prevProps: Props) { + const { uiSettings, store, appName } = this.services; const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); @@ -412,7 +413,7 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.services.uiSettings, this.services.appName, this.props.query.language); + : getQueryLog(uiSettings, store, appName, this.props.query.language); if (!isEqual(prevProps.indexPatterns, this.props.indexPatterns)) { this.fetchIndexPatterns().then(this.updateSuggestions); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx index 6895c9ecd018c..716bb677b946f 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx @@ -22,7 +22,6 @@ import { doesKueryExpressionHaveLuceneSyntaxError } from '@kbn/es-query'; import classNames from 'classnames'; import React, { useState, useEffect } from 'react'; import { documentationLinks } from 'ui/documentation_links'; -import { PersistedLog } from 'ui/persisted_log'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLink, EuiSuperDatePicker } from '@elastic/eui'; // @ts-ignore @@ -34,10 +33,10 @@ import { useKibana } from '../../../../../../../plugins/kibana_react/public'; import { IndexPattern } from '../../../index_patterns'; import { QueryBarInput } from './query_bar_input'; -import { getQueryLog } from '../lib/get_query_log'; -import { Query } from '../index'; +import { Query, getQueryLog } from '../index'; import { TimeHistoryContract } from '../../../timefilter'; import { IDataPluginServices } from '../../../types'; +import { PersistedLog } from '../../persisted_log'; interface Props { query?: Query; @@ -72,7 +71,7 @@ function QueryBarTopRowUI(props: Props) { useEffect(() => { if (!props.query) return; - persistedLog = getQueryLog(uiSettings!, appName, props.query.language); + persistedLog = getQueryLog(uiSettings!, store, appName, props.query.language); }, [queryLanguage]); function onClickSubmitButton(event: React.MouseEvent) { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts b/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts index 70dc1d3fe700e..8b26e14c6ed7b 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts +++ b/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts @@ -17,16 +17,22 @@ * under the License. */ -import { PersistedLog } from 'ui/persisted_log'; import { UiSettingsClientContract } from 'src/core/public'; +import { PersistedLog } from '../../persisted_log'; +import { Storage } from '../../../types'; export function getQueryLog( uiSettings: UiSettingsClientContract, + store: Storage, appName: string, language: string ) { - return new PersistedLog(`typeahead:${appName}-${language}`, { - maxLength: uiSettings.get('history:limit'), - filterDuplicates: true, - }); + return new PersistedLog( + `typeahead:${appName}-${language}`, + { + maxLength: uiSettings.get('history:limit'), + filterDuplicates: true, + }, + store + ); } diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx index add49e47971d3..c84e460a1556c 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -20,8 +20,8 @@ import React from 'react'; import { Filter } from '@kbn/es-query'; import { CoreStart } from 'src/core/public'; -import { Storage } from 'ui/storage'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { Storage } from '../../../types'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { TimefilterSetup } from '../../../timefilter'; import { FilterManager, SearchBar } from '../../../'; @@ -29,10 +29,10 @@ import { SearchBarOwnProps } from '.'; interface StatefulSearchBarDeps { core: CoreStart; + data: DataPublicPluginStart; store: Storage; timefilter: TimefilterSetup; filterManager: FilterManager; - autocomplete: AutocompletePublicPluginStart; } export type StatetfulSearchBarProps = SearchBarOwnProps & { @@ -59,7 +59,7 @@ export function createSearchBar({ store, timefilter, filterManager, - autocomplete, + data, }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. @@ -71,7 +71,7 @@ export function createSearchBar({ void; // Query bar - should be in SearchBarInjectedDeps query?: Query; // Show when user has privileges to save diff --git a/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts index 126754388f13f..511482c6239fb 100644 --- a/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts +++ b/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts @@ -25,6 +25,7 @@ import { initLegacyModule } from './legacy_module'; /** @internal */ export interface LegacyDependenciesPluginSetup { savedObjectsClient: any; + storage: Storage; } export interface LegacyDependenciesPluginStart { @@ -37,6 +38,7 @@ export class LegacyDependenciesPlugin implements Plugin { return { savedObjectsClient: chrome.getSavedObjectsClient(), + storage: new Storage(window.localStorage), } as LegacyDependenciesPluginSetup; } diff --git a/src/legacy/core_plugins/data/public/shim/legacy_module.ts b/src/legacy/core_plugins/data/public/shim/legacy_module.ts index 4e81a5d4294e6..fea9409b2ec68 100644 --- a/src/legacy/core_plugins/data/public/shim/legacy_module.ts +++ b/src/legacy/core_plugins/data/public/shim/legacy_module.ts @@ -24,7 +24,7 @@ import { Filter } from '@kbn/es-query'; // @ts-ignore import { uiModules } from 'ui/modules'; -import { npSetup, npStart } from 'ui/new_platform'; +import { npStart } from 'ui/new_platform'; import { FilterBar, ApplyFiltersPopover } from '../filter'; import template from './apply_filter_directive.html'; @@ -49,14 +49,16 @@ export const initLegacyModule = once((): void => { } child.setAttribute('ui-settings', 'uiSettings'); - child.setAttribute('http', 'http'); + child.setAttribute('doc-links', 'docLinks'); + child.setAttribute('plugin-data-start', 'pluginDataStart'); // Append helper directive elem.append(child); const linkFn = ($scope: any) => { - $scope.uiSettings = npSetup.core.uiSettings; - $scope.http = npSetup.core.http; + $scope.uiSettings = npStart.core.uiSettings; + $scope.docLinks = npStart.core.docLinks; + $scope.pluginDataStart = npStart.plugins.data; }; return linkFn; @@ -66,11 +68,12 @@ export const initLegacyModule = once((): void => { .directive('filterBarHelper', (reactDirective: any) => { return reactDirective(wrapInI18nContext(FilterBar), [ ['uiSettings', { watchDepth: 'reference' }], - ['http', { watchDepth: 'reference' }], + ['docLinks', { watchDepth: 'reference' }], ['onFiltersUpdated', { watchDepth: 'reference' }], ['indexPatterns', { watchDepth: 'collection' }], ['filters', { watchDepth: 'collection' }], ['className', { watchDepth: 'reference' }], + ['pluginDataStart', { watchDepth: 'reference' }], ]); }) .directive('applyFiltersPopoverComponent', (reactDirective: any) => diff --git a/src/legacy/core_plugins/data/public/timefilter/time_history.ts b/src/legacy/core_plugins/data/public/timefilter/time_history.ts index 7dcd5843ae530..22778d1adea3c 100644 --- a/src/legacy/core_plugins/data/public/timefilter/time_history.ts +++ b/src/legacy/core_plugins/data/public/timefilter/time_history.ts @@ -19,12 +19,13 @@ import moment from 'moment'; import { TimeRange } from 'src/plugins/data/public'; -import { PersistedLog } from 'ui/persisted_log'; +import { PersistedLog } from '../query/persisted_log'; +import { Storage } from '../types'; export class TimeHistory { private history: PersistedLog; - constructor() { + constructor(store: Storage) { const historyOptions = { maxLength: 10, filterDuplicates: true, @@ -32,7 +33,7 @@ export class TimeHistory { return oldItem.from === newItem.from && oldItem.to === newItem.to; }, }; - this.history = new PersistedLog('kibana.timepicker.timeHistory', historyOptions); + this.history = new PersistedLog('kibana.timepicker.timeHistory', historyOptions, store); } add(time: TimeRange) { diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts b/src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts index 96c490a195d3d..cda9b93ef08aa 100644 --- a/src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts +++ b/src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts @@ -19,6 +19,7 @@ import { UiSettingsClientContract } from 'src/core/public'; import { TimeHistory, Timefilter, TimeHistoryContract, TimefilterContract } from './index'; +import { Storage } from '../types'; /** * Filter Service @@ -27,15 +28,16 @@ import { TimeHistory, Timefilter, TimeHistoryContract, TimefilterContract } from export interface TimeFilterServiceDependencies { uiSettings: UiSettingsClientContract; + store: Storage; } export class TimefilterService { - public setup({ uiSettings }: TimeFilterServiceDependencies): TimefilterSetup { + public setup({ uiSettings, store }: TimeFilterServiceDependencies): TimefilterSetup { const timefilterConfig = { timeDefaults: uiSettings.get('timepicker:timeDefaults'), refreshIntervalDefaults: uiSettings.get('timepicker:refreshIntervalDefaults'), }; - const history = new TimeHistory(); + const history = new TimeHistory(store); const timefilter = new Timefilter(timefilterConfig, history); return { diff --git a/src/legacy/core_plugins/data/public/types.ts b/src/legacy/core_plugins/data/public/types.ts index 4b7a5c1402ea7..2c02a9b764755 100644 --- a/src/legacy/core_plugins/data/public/types.ts +++ b/src/legacy/core_plugins/data/public/types.ts @@ -18,7 +18,14 @@ */ import { UiSettingsClientContract, CoreStart } from 'src/core/public'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; + +export interface Storage { + get: (key: string) => any; + set: (key: string, value: any) => void; + remove: (key: string) => any; + clear: () => void; +} export interface IDataPluginServices extends Partial { appName: string; @@ -27,5 +34,5 @@ export interface IDataPluginServices extends Partial { notifications: CoreStart['notifications']; http: CoreStart['http']; store: Storage; - autocomplete: AutocompletePublicPluginStart; + data: DataPublicPluginStart; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index 741931af11c7d..22f127d12c438 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -331,7 +331,8 @@ export class DashboardAppController { getDashboardTitle( dashboardStateManager.getTitle(), dashboardStateManager.getViewMode(), - dashboardStateManager.getIsDirty(timefilter) + dashboardStateManager.getIsDirty(timefilter), + dashboardStateManager.isNew() ); // Push breadcrumbs to new header navigation diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts index c1ce5b764f2f6..7c1fc771de349 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts @@ -229,6 +229,14 @@ export class DashboardStateManager { return this.appState.title; } + public isSaved() { + return !!this.savedDashboard.id; + } + + public isNew() { + return !this.isSaved(); + } + public getDescription() { return this.appState.description; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.ts index b7f9293539abd..d932116d08dc8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.ts @@ -27,22 +27,31 @@ import { ViewMode } from '../../../../../../src/plugins/embeddable/public'; * end of the title. * @returns {string} A title to display to the user based on the above parameters. */ -export function getDashboardTitle(title: string, viewMode: ViewMode, isDirty: boolean): string { +export function getDashboardTitle( + title: string, + viewMode: ViewMode, + isDirty: boolean, + isNew: boolean +): string { const isEditMode = viewMode === ViewMode.EDIT; let displayTitle: string; + const newDashboardTitle = i18n.translate('kbn.dashboard.savedDashboard.newDashboardTitle', { + defaultMessage: 'New Dashboard', + }); + const dashboardTitle = isNew ? newDashboardTitle : title; if (isEditMode && isDirty) { displayTitle = i18n.translate('kbn.dashboard.strings.dashboardUnsavedEditTitle', { defaultMessage: 'Editing {title} (unsaved)', - values: { title }, + values: { title: dashboardTitle }, }); } else if (isEditMode) { displayTitle = i18n.translate('kbn.dashboard.strings.dashboardEditTitle', { defaultMessage: 'Editing {title}', - values: { title }, + values: { title: dashboardTitle }, }); } else { - displayTitle = title; + displayTitle = dashboardTitle; } return displayTitle; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js index 36a083ef5a39c..fe9e7b18d5007 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js @@ -18,7 +18,6 @@ */ import angular from 'angular'; -import { i18n } from '@kbn/i18n'; import { uiModules } from 'ui/modules'; import { createDashboardEditUrl } from '../dashboard_constants'; import { createLegacyClass } from 'ui/utils/legacy_class'; @@ -50,7 +49,7 @@ module.factory('SavedDashboard', function (Private) { // default values that will get assigned if the doc is new defaults: { - title: i18n.translate('kbn.dashboard.savedDashboard.newDashboardTitle', { defaultMessage: 'New Dashboard' }), + title: '', hits: 0, description: '', panelsJSON: '[]', diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js index f7b7f06c2f502..8a7597421600f 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js @@ -19,6 +19,7 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { Query } from '@elastic/eui'; import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table'; import { Flyout } from '../components/flyout/'; @@ -44,8 +45,8 @@ jest.mock('../../../lib/fetch_export_objects', () => ({ fetchExportObjects: jest.fn(), })); -jest.mock('../../../lib/fetch_export_by_type', () => ({ - fetchExportByType: jest.fn(), +jest.mock('../../../lib/fetch_export_by_type_and_search', () => ({ + fetchExportByTypeAndSearch: jest.fn(), })); jest.mock('../../../lib/get_saved_object_counts', () => ({ @@ -305,7 +306,7 @@ describe('ObjectsTable', () => { }); it('should export all', async () => { - const { fetchExportByType } = require('../../../lib/fetch_export_by_type'); + const { fetchExportByTypeAndSearch } = require('../../../lib/fetch_export_by_type_and_search'); const { saveAs } = require('@elastic/filesaver'); const component = shallowWithIntl( { // Set up mocks const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' }); - fetchExportByType.mockImplementation(() => blob); + fetchExportByTypeAndSearch.mockImplementation(() => blob); await component.instance().onExportAll(); - expect(fetchExportByType).toHaveBeenCalledWith(POSSIBLE_TYPES, true); + expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, undefined, true); + expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson'); + expect(addSuccessMock).toHaveBeenCalledWith({ title: 'Your file is downloading in the background' }); + }); + + it('should export all, accounting for the current search criteria', async () => { + const { fetchExportByTypeAndSearch } = require('../../../lib/fetch_export_by_type_and_search'); + const { saveAs } = require('@elastic/filesaver'); + const component = shallowWithIntl( + + ); + + component.instance().onQueryChange({ + query: Query.parse('test') + }); + + // Ensure all promises resolve + await new Promise(resolve => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + + // Set up mocks + const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' }); + fetchExportByTypeAndSearch.mockImplementation(() => blob); + + await component.instance().onExportAll(); + + expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, 'test*', true); expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson'); expect(addSuccessMock).toHaveBeenCalledWith({ title: 'Your file is downloading in the background' }); }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js index d0c45f8a7ee08..3670028726f10 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js @@ -26,8 +26,8 @@ jest.mock('ui/chrome', () => ({ addBasePath: () => '' })); -jest.mock('../../../../../lib/fetch_export_by_type', () => ({ - fetchExportByType: jest.fn(), +jest.mock('../../../../../lib/fetch_export_by_type_and_search', () => ({ + fetchExportByTypeAndSearch: jest.fn(), })); jest.mock('../../../../../lib/fetch_export_objects', () => ({ diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js index 326c577ebe220..3e7e84d75bfe1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js @@ -58,7 +58,7 @@ import { getRelationships, getSavedObjectLabel, fetchExportObjects, - fetchExportByType, + fetchExportByTypeAndSearch, findObjects, } from '../../lib'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; @@ -303,7 +303,8 @@ class ObjectsTableUI extends Component { onExportAll = async () => { const { intl } = this.props; - const { exportAllSelectedOptions, isIncludeReferencesDeepChecked } = this.state; + const { exportAllSelectedOptions, isIncludeReferencesDeepChecked, activeQuery } = this.state; + const { queryText } = parseQuery(activeQuery); const exportTypes = Object.entries(exportAllSelectedOptions).reduce( (accum, [id, selected]) => { if (selected) { @@ -316,7 +317,7 @@ class ObjectsTableUI extends Component { let blob; try { - blob = await fetchExportByType(exportTypes, isIncludeReferencesDeepChecked); + blob = await fetchExportByTypeAndSearch(exportTypes, queryText ? `${queryText}*` : undefined, isIncludeReferencesDeepChecked); } catch (e) { toastNotifications.addDanger({ title: intl.formatMessage({ diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js similarity index 90% rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js rename to src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js index 71c022b9d3998..788a4635d8dac 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js @@ -19,12 +19,13 @@ import { kfetch } from 'ui/kfetch'; -export async function fetchExportByType(types, includeReferencesDeep = false) { +export async function fetchExportByTypeAndSearch(types, search, includeReferencesDeep = false) { return await kfetch({ method: 'POST', pathname: '/api/saved_objects/_export', body: JSON.stringify({ type: types, + search, includeReferencesDeep, }), }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js index 2818f0d8a6cb4..245812867f1de 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js @@ -17,7 +17,7 @@ * under the License. */ -export * from './fetch_export_by_type'; +export * from './fetch_export_by_type_and_search'; export * from './fetch_export_objects'; export * from './in_app_url'; export * from './get_relationships'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index 389a84babae87..3497a35f5c99d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -170,7 +170,7 @@ export class VisEditor extends Component { services={{ appName: APP_NAME, store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/legacy/server/saved_objects/routes/export.test.ts b/src/legacy/server/saved_objects/routes/export.test.ts index 6b6e6ac90a48c..491e3a9067611 100644 --- a/src/legacy/server/saved_objects/routes/export.test.ts +++ b/src/legacy/server/saved_objects/routes/export.test.ts @@ -62,12 +62,42 @@ describe('POST /api/saved_objects/_export', () => { jest.resetAllMocks(); }); + test('does not allow both "search" and "objects" to be specified', async () => { + const request = { + method: 'POST', + url: '/api/saved_objects/_export', + payload: { + search: 'search', + objects: [{ type: 'search', id: 'bar' }], + includeReferencesDeep: true, + }, + }; + + const { payload, statusCode } = await server.inject(request); + + expect(statusCode).toEqual(400); + expect(JSON.parse(payload)).toMatchInlineSnapshot(` + Object { + "error": "Bad Request", + "message": "\\"search\\" must not exist simultaneously with [objects]", + "statusCode": 400, + "validation": Object { + "keys": Array [ + "value", + ], + "source": "payload", + }, + } + `); + }); + test('formats successful response', async () => { const request = { method: 'POST', url: '/api/saved_objects/_export', payload: { type: 'search', + search: 'my search string', includeReferencesDeep: true, }, }; @@ -101,58 +131,59 @@ describe('POST /api/saved_objects/_export', () => { expect(headers).toHaveProperty('content-disposition', 'attachment; filename="export.ndjson"'); expect(headers).toHaveProperty('content-type', 'application/ndjson'); expect(objects).toMatchInlineSnapshot(` -Array [ - Object { - "attributes": Object {}, - "id": "1", - "references": Array [], - "type": "index-pattern", - }, - Object { - "attributes": Object {}, - "id": "2", - "references": Array [ - Object { - "id": "1", - "name": "ref_0", - "type": "index-pattern", - }, - ], - "type": "search", - }, -] -`); - expect(getSortedObjectsForExport).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - Object { - "exportSizeLimit": 10000, - "includeReferencesDeep": true, - "objects": undefined, - "savedObjectsClient": Object { - "bulkCreate": [MockFunction], - "bulkGet": [MockFunction], - "create": [MockFunction], - "delete": [MockFunction], - "errors": Object {}, - "find": [MockFunction], - "get": [MockFunction], - "update": [MockFunction], + Array [ + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", }, - "types": Array [ - "search", + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref_0", + "type": "index-pattern", + }, + ], + "type": "search", + }, + ] + `); + expect(getSortedObjectsForExport).toMatchInlineSnapshot(` + [MockFunction] { + "calls": Array [ + Array [ + Object { + "exportSizeLimit": 10000, + "includeReferencesDeep": true, + "objects": undefined, + "savedObjectsClient": Object { + "bulkCreate": [MockFunction], + "bulkGet": [MockFunction], + "create": [MockFunction], + "delete": [MockFunction], + "errors": Object {}, + "find": [MockFunction], + "get": [MockFunction], + "update": [MockFunction], + }, + "search": "my search string", + "types": Array [ + "search", + ], + }, + ], ], - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], -} -`); + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + } + `); }); }); diff --git a/src/legacy/server/saved_objects/routes/export.ts b/src/legacy/server/saved_objects/routes/export.ts index 32d655531ec74..fc120030a873c 100644 --- a/src/legacy/server/saved_objects/routes/export.ts +++ b/src/legacy/server/saved_objects/routes/export.ts @@ -41,6 +41,7 @@ interface ExportRequest extends Hapi.Request { type: string; id: string; }>; + search?: string; includeReferencesDeep: boolean; }; } @@ -70,9 +71,11 @@ export const createExportRoute = ( }) .max(server.config().get('savedObjects.maxImportExportSize')) .optional(), + search: Joi.string().optional(), includeReferencesDeep: Joi.boolean().default(false), }) .xor('type', 'objects') + .nand('search', 'objects') .default(), }, async handler(request: ExportRequest, h: Hapi.ResponseToolkit) { @@ -80,6 +83,7 @@ export const createExportRoute = ( const exportStream = await getSortedObjectsForExport({ savedObjectsClient, types: request.payload.type, + search: request.payload.search, objects: request.payload.objects, exportSizeLimit: server.config().get('savedObjects.maxImportExportSize'), includeReferencesDeep: request.payload.includeReferencesDeep, diff --git a/src/legacy/ui/public/agg_types/buckets/filters.js b/src/legacy/ui/public/agg_types/buckets/filters.js index 9b7795d8fd9fa..19be75ccf8c1e 100644 --- a/src/legacy/ui/public/agg_types/buckets/filters.js +++ b/src/legacy/ui/public/agg_types/buckets/filters.js @@ -24,6 +24,7 @@ import { BucketAggType } from './_bucket_agg_type'; import { createFilterFilters } from './create_filter/filters'; import { FiltersParamEditor } from '../../vis/editors/default/controls/filters'; import { i18n } from '@kbn/i18n'; +import { Storage } from 'ui/storage'; import chrome from 'ui/chrome'; import { buildEsQuery } from '@kbn/es-query'; @@ -31,6 +32,7 @@ import { setup as data } from '../../../../core_plugins/data/public/legacy'; const { getQueryLog } = data.query.helpers; const config = chrome.getUiSettingsClient(); +const storage = new Storage(window.localStorage); export const filtersBucketAgg = new BucketAggType({ name: 'filters', @@ -50,7 +52,7 @@ export const filtersBucketAgg = new BucketAggType({ if (!_.size(inFilters)) return; inFilters.forEach((filter) => { - const persistedLog = getQueryLog(config, 'filtersAgg', filter.input.language); + const persistedLog = getQueryLog(config, storage, 'filtersAgg', filter.input.language); persistedLog.add(filter.input.query); }); diff --git a/src/legacy/ui/public/directives/field_name/__snapshots__/field_name_icon.test.tsx.snap b/src/legacy/ui/public/directives/field_name/__snapshots__/field_name_icon.test.tsx.snap deleted file mode 100644 index ef231622f7cd8..0000000000000 --- a/src/legacy/ui/public/directives/field_name/__snapshots__/field_name_icon.test.tsx.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FieldNameIcon renders a blackwhite icon for a string 1`] = ` - -`; - -exports[`FieldNameIcon renders a colored icon for a number 1`] = ` - -`; - -exports[`FieldNameIcon renders an icon for an unknown type 1`] = ` - -`; diff --git a/src/legacy/ui/public/directives/field_name/field_name.tsx b/src/legacy/ui/public/directives/field_name/field_name.tsx index 855caa8d0b96e..0340ce9cb5d1b 100644 --- a/src/legacy/ui/public/directives/field_name/field_name.tsx +++ b/src/legacy/ui/public/directives/field_name/field_name.tsx @@ -20,7 +20,7 @@ import React from 'react'; import classNames from 'classnames'; // @ts-ignore import { shortenDottedString } from '../../../../core_plugins/kibana/common/utils/shorten_dotted_string'; -import { FieldNameIcon } from './field_name_icon'; +import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public'; import { getFieldTypeName } from './field_type_name'; // property field is provided at discover's field chooser @@ -53,7 +53,7 @@ export function FieldName({ field, fieldName, fieldType, useShortDots }: Props) return ( - + {displayName} ); diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 29868dc9767dc..bbfa8bd329c65 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -65,7 +65,9 @@ export const npStart = { registerRenderer: sinon.fake(), registerType: sinon.fake(), }, - data: {}, + data: { + getSuggestions: sinon.fake(), + }, inspector: { isAvailable: () => false, open: () => ({ diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index cceaf86b5d85c..2c0a2b6be37f8 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -95,7 +95,7 @@ function FilterRow({ services={{ appName: 'filtersAgg', store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/legacy/ui/public/vislib/lib/axis/axis_labels.js b/src/legacy/ui/public/vislib/lib/axis/axis_labels.js index 5669b255e5dbb..5db747f8a76ba 100644 --- a/src/legacy/ui/public/vislib/lib/axis/axis_labels.js +++ b/src/legacy/ui/public/vislib/lib/axis/axis_labels.js @@ -105,7 +105,7 @@ export class AxisLabels { selection.selectAll('.tick text') .text(function (d) { const par = d3.select(this.parentNode).node(); - const myPos = scaleStartPad + self.axisScale.scale(d); + const myPos = scaleStartPad + (config.isHorizontal() ? self.axisScale.scale(d) : maxSize - self.axisScale.scale(d)); const mySize = (config.isHorizontal() ? par.getBBox().width : par.getBBox().height) * padding; const halfSize = mySize / 2; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index df5b68ac409a0..b2d311912b982 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -38,6 +38,7 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const startContract: Start = { autocomplete: autocompleteMock as Start['autocomplete'], + getSuggestions: jest.fn(), }; return startContract; }; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index eb31647767360..a3fa8005560ae 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -20,6 +20,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { AutocompleteProviderRegister } from './autocomplete_provider'; import { DataPublicPluginSetup, DataPublicPluginStart } from './types'; +import { getSuggestionsProvider } from './suggestions_provider'; export class DataPublicPlugin implements Plugin { private readonly autocomplete = new AutocompleteProviderRegister(); @@ -35,6 +36,7 @@ export class DataPublicPlugin implements Plugin any; diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts similarity index 83% rename from src/legacy/ui/public/value_suggestions/value_suggestions.test.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index d6d0a7dc003e6..13ccbbd9f3dde 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -17,21 +17,23 @@ * under the License. */ +// TODO: remove when index patterns are moved here. jest.mock('ui/new_platform'); jest.mock('ui/index_patterns'); import { mockFields, mockIndexPattern } from 'ui/index_patterns'; import { getSuggestionsProvider } from './value_suggestions'; +import { UiSettingsClientContract } from 'kibana/public'; describe('getSuggestions', () => { let getSuggestions: any; - let fetch: any; + let http: any; describe('with value suggestions disabled', () => { beforeEach(() => { - const config = { get: () => false }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => false } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return an empty array', async () => { @@ -40,15 +42,15 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); }); describe('with value suggestions enabled', () => { beforeEach(() => { - const config = { get: () => true }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => true } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return true/false for boolean fields', async () => { @@ -57,7 +59,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([true, false]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field type is not a string or boolean', async () => { @@ -66,7 +68,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field is not aggregatable', async () => { @@ -75,7 +77,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should otherwise request suggestions', async () => { @@ -85,7 +87,7 @@ describe('getSuggestions', () => { ); const query = ''; await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalled(); + expect(http.fetch).toHaveBeenCalled(); }); it('should cache results if using the same index/field/query/filter', async () => { @@ -96,7 +98,7 @@ describe('getSuggestions', () => { const query = ''; await getSuggestions(index, field, query); await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalledTimes(1); + expect(http.fetch).toHaveBeenCalledTimes(1); }); it('should cache results for only one minute', async () => { @@ -113,7 +115,7 @@ describe('getSuggestions', () => { await getSuggestions(index, field, query); Date.now = now; - expect(fetch).toHaveBeenCalledTimes(2); + expect(http.fetch).toHaveBeenCalledTimes(2); }); it('should not cache results if using a different index/field/query', async () => { @@ -128,7 +130,7 @@ describe('getSuggestions', () => { await getSuggestions('logstash-*', fields[0], 'query'); await getSuggestions('logstash-*', fields[1], ''); await getSuggestions('logstash-*', fields[1], 'query'); - expect(fetch).toHaveBeenCalledTimes(8); + expect(http.fetch).toHaveBeenCalledTimes(8); }); }); }); diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts similarity index 82% rename from src/legacy/ui/public/value_suggestions/value_suggestions.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.ts index 31e42e9945ede..03eaa5d9594d2 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts @@ -18,16 +18,17 @@ */ import { memoize } from 'lodash'; -import { Field } from 'ui/index_patterns'; + +import { UiSettingsClientContract, HttpServiceBase } from 'src/core/public'; +import { IGetSuggestions, Field } from './types'; export function getSuggestionsProvider( - config: { get: (key: string) => any }, - fetch: (...options: any[]) => any -) { + uiSettings: UiSettingsClientContract, + http: HttpServiceBase +): IGetSuggestions { const requestSuggestions = memoize( (index: string, field: Field, query: string, boolFilter: any = []) => { - return fetch({ - pathname: `/api/kibana/suggestions/values/${index}`, + return http.fetch(`/api/kibana/suggestions/values/${index}`, { method: 'POST', body: JSON.stringify({ query, field: field.name, boolFilter }), }); @@ -36,7 +37,7 @@ export function getSuggestionsProvider( ); return async (index: string, field: Field, query: string, boolFilter?: any) => { - const shouldSuggestValues = config.get('filterEditor:suggestValues'); + const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues'); if (field.type === 'boolean') { return [true, false]; } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 23308304b8ff8..70406b4dc0c0a 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -20,10 +20,14 @@ export * from './autocomplete_provider/types'; import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.'; +import { IGetSuggestions } from './suggestions_provider/types'; export interface DataPublicPluginSetup { autocomplete: AutocompletePublicPluginSetup; } export interface DataPublicPluginStart { autocomplete: AutocompletePublicPluginStart; + getSuggestions: IGetSuggestions; } + +export { IGetSuggestions } from './suggestions_provider/types'; diff --git a/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap b/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap new file mode 100644 index 0000000000000..5abce10c5be61 --- /dev/null +++ b/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FieldIcon renders a blackwhite icon for a string 1`] = ` + +`; + +exports[`FieldIcon renders a colored icon for a number 1`] = ` + +`; + +exports[`FieldIcon renders an icon for an unknown type 1`] = ` + +`; + +exports[`FieldIcon renders with className if provided 1`] = ` + +`; diff --git a/src/legacy/ui/public/directives/field_name/field_name_icon.test.tsx b/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx similarity index 60% rename from src/legacy/ui/public/directives/field_name/field_name_icon.test.tsx rename to src/plugins/kibana_react/public/field_icon/field_icon.test.tsx index 2fce3d2c0ce95..90a858e31b4f3 100644 --- a/src/legacy/ui/public/directives/field_name/field_name_icon.test.tsx +++ b/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx @@ -18,19 +18,24 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import { FieldNameIcon } from './field_name_icon'; +import { FieldIcon } from './field_icon'; -test('FieldNameIcon renders a blackwhite icon for a string', () => { - const component = shallow(); +test('FieldIcon renders a blackwhite icon for a string', () => { + const component = shallow(); expect(component).toMatchSnapshot(); }); -test('FieldNameIcon renders a colored icon for a number', () => { - const component = shallow(); +test('FieldIcon renders a colored icon for a number', () => { + const component = shallow(); expect(component).toMatchSnapshot(); }); -test('FieldNameIcon renders an icon for an unknown type', () => { - const component = shallow(); +test('FieldIcon renders an icon for an unknown type', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); +}); + +test('FieldIcon renders with className if provided', () => { + const component = shallow(); expect(component).toMatchSnapshot(); }); diff --git a/src/legacy/ui/public/directives/field_name/field_name_icon.tsx b/src/plugins/kibana_react/public/field_icon/field_icon.tsx similarity index 87% rename from src/legacy/ui/public/directives/field_name/field_name_icon.tsx rename to src/plugins/kibana_react/public/field_icon/field_icon.tsx index a0b2f97fb4fcc..f9bdf3a25adaa 100644 --- a/src/legacy/ui/public/directives/field_name/field_name_icon.tsx +++ b/src/plugins/kibana_react/public/field_icon/field_icon.tsx @@ -24,7 +24,7 @@ interface IconMapEntry { icon: string; color: string; } -interface FieldNameIconProps { +interface FieldIconProps { type: | 'boolean' | 'conflict' @@ -37,9 +37,10 @@ interface FieldNameIconProps { | '_source' | 'string' | string; - label: string; + label?: string; size?: IconSize; useColor?: boolean; + className?: string; } const { colors } = palettes.euiPaletteColorBlind; @@ -47,7 +48,7 @@ const { colors } = palettes.euiPaletteColorBlind; // defaultIcon => a unknown datatype const defaultIcon = { icon: 'questionInCircle', color: colors[0] }; -const typeToEuiIconMap: Partial> = { +export const typeToEuiIconMap: Partial> = { boolean: { icon: 'invert', color: colors[5] }, // icon for an index pattern mapping conflict in discover conflict: { icon: 'alert', color: colors[8] }, @@ -63,9 +64,15 @@ const typeToEuiIconMap: Partial> = { }; /** - * Field icon displayed in discover doc_viewer + side bar + * Field icon used across the app */ -export function FieldNameIcon({ type, label, size = 's', useColor = false }: FieldNameIconProps) { +export function FieldIcon({ + type, + label, + size = 's', + useColor = false, + className = undefined, +}: FieldIconProps) { const euiIcon = typeToEuiIconMap[type] || defaultIcon; return ( @@ -74,6 +81,7 @@ export function FieldNameIcon({ type, label, size = 's', useColor = false }: Fie aria-label={label || type} size={size as IconSize} color={useColor || type === 'conflict' ? euiIcon.color : undefined} + className={className} /> ); } diff --git a/src/plugins/kibana_react/public/field_icon/index.ts b/src/plugins/kibana_react/public/field_icon/index.ts new file mode 100644 index 0000000000000..e1bb15bfd9194 --- /dev/null +++ b/src/plugins/kibana_react/public/field_icon/index.ts @@ -0,0 +1,19 @@ +/* + * 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 * from './field_icon'; diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index 0e98d68988488..cd2ae89b05b5d 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -22,3 +22,4 @@ export * from './exit_full_screen_button'; export * from './context'; export * from './overlays'; export * from './ui_settings'; +export * from './field_icon'; diff --git a/test/api_integration/apis/saved_objects/export.js b/test/api_integration/apis/saved_objects/export.js index 0564c095faa88..e39749aa48159 100644 --- a/test/api_integration/apis/saved_objects/export.js +++ b/test/api_integration/apis/saved_objects/export.js @@ -94,6 +94,27 @@ export default function ({ getService }) { }); }); + it('should support including dependencies when exporting by type and search', async () => { + await supertest + .post('/api/saved_objects/_export') + .send({ + includeReferencesDeep: true, + type: ['dashboard'], + search: 'Requests*' + }) + .expect(200) + .then((resp) => { + const objects = resp.text.split('\n').map(JSON.parse); + expect(objects).to.have.length(3); + expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); + expect(objects[0]).to.have.property('type', 'index-pattern'); + expect(objects[1]).to.have.property('id', 'dd7caf20-9efd-11e7-acb3-3dab96693fab'); + expect(objects[1]).to.have.property('type', 'visualization'); + expect(objects[2]).to.have.property('id', 'be3733a0-9efe-11e7-acb3-3dab96693fab'); + expect(objects[2]).to.have.property('type', 'dashboard'); + }); + }); + it(`should throw error when object doesn't exist`, async () => { await supertest .post('/api/saved_objects/_export') diff --git a/test/functional/apps/console/_console.ts b/test/functional/apps/console/_console.ts index cdf2d3bf61f53..642314d1fb7f1 100644 --- a/test/functional/apps/console/_console.ts +++ b/test/functional/apps/console/_console.ts @@ -46,7 +46,11 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { it('should show the default request', async () => { // collapse the help pane because we only get the VISIBLE TEXT, not the part that is scrolled - await PageObjects.console.collapseHelp(); + // on IE11, the dialog that says 'Your browser does not meet the security requirements for Kibana.' + // blocks the close help button for several seconds so just retry until we can click it. + await retry.try(async () => { + await PageObjects.console.collapseHelp(); + }); await retry.try(async () => { const actualRequest = await PageObjects.console.getRequest(); log.debug(actualRequest); diff --git a/test/functional/apps/home/_navigation.js b/test/functional/apps/home/_navigation.js index 7582e45f74a34..12ce0e6afd03f 100644 --- a/test/functional/apps/home/_navigation.js +++ b/test/functional/apps/home/_navigation.js @@ -26,6 +26,7 @@ export default function ({ getService, getPageObjects }) { const appsMenu = getService('appsMenu'); const esArchiver = getService('esArchiver'); const retry = getService('retry'); + const kibanaServer = getService('kibanaServer'); const fromTime = '2015-09-19 06:31:44.000'; const toTime = '2015-09-23 18:31:44.000'; @@ -33,8 +34,15 @@ export default function ({ getService, getPageObjects }) { before(async () => { await esArchiver.loadIfNeeded('makelogs'); - await browser.refresh(); - await PageObjects.header.awaitKibanaChrome(); + if (browser.isInternetExplorer) { + await kibanaServer.uiSettings.replace({ 'state:storeInSessionStorage': false }); + } + }); + + after(async () => { + if (browser.isInternetExplorer) { + await kibanaServer.uiSettings.replace({ 'state:storeInSessionStorage': true }); + } }); // FLAKY: https://github.com/elastic/kibana/issues/33468 diff --git a/test/functional/apps/visualize/_chart_types.js b/test/functional/apps/visualize/_chart_types.js index 6f868b6df464f..79ea326ad982a 100644 --- a/test/functional/apps/visualize/_chart_types.js +++ b/test/functional/apps/visualize/_chart_types.js @@ -26,7 +26,7 @@ export default function ({ getService, getPageObjects }) { describe('chart types', function () { before(function () { log.debug('navigateToApp visualize'); - return PageObjects.common.navigateToUrl('visualize', 'new'); + return PageObjects.visualize.navigateToNewVisualization(); }); it('should show the correct chart types', async function () { diff --git a/test/functional/config.ie.js b/test/functional/config.ie.js new file mode 100644 index 0000000000000..6a7af00777c54 --- /dev/null +++ b/test/functional/config.ie.js @@ -0,0 +1,54 @@ +/* + * 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 default async function ({ readConfigFile }) { + const defaultConfig = await readConfigFile(require.resolve('./config')); + + return { + ...defaultConfig.getAll(), + + browser: { + type: 'ie', + }, + + junit: { + reportName: 'Internet Explorer UI Functional Tests' + }, + + uiSettings: { + defaults: { + 'accessibility:disableAnimations': true, + 'dateFormat:tz': 'UTC', + 'telemetry:optIn': false, + 'state:storeInSessionStorage': true, + 'notifications:lifetime:info': 10000, + }, + }, + + + kbnTestServer: { + ...defaultConfig.get('kbnTestServer'), + serverArgs: [ + ...defaultConfig.get('kbnTestServer.serverArgs'), + ], + }, + + + }; +} diff --git a/test/functional/page_objects/time_picker.js b/test/functional/page_objects/time_picker.js index b5b22f4285358..054c3edd567e1 100644 --- a/test/functional/page_objects/time_picker.js +++ b/test/functional/page_objects/time_picker.js @@ -25,7 +25,7 @@ export function TimePickerPageProvider({ getService, getPageObjects }) { const find = getService('find'); const browser = getService('browser'); const testSubjects = getService('testSubjects'); - const PageObjects = getPageObjects(['header']); + const PageObjects = getPageObjects(['header', 'common']); class TimePickerPage { @@ -48,18 +48,6 @@ export function TimePickerPageProvider({ getService, getPageObjects }) { await find.waitForElementStale(panelElement); } - async setAbsoluteStart(startTime) { - await this.showStartEndTimes(); - - await testSubjects.click('superDatePickerstartDatePopoverButton'); - const panel = await this.getTimePickerPanel(); - await testSubjects.click('superDatePickerAbsoluteTab'); - await this.inputValue('superDatePickerAbsoluteDateInput', startTime); - await testSubjects.click('superDatePickerstartDatePopoverButton'); - await this.waitPanelIsGone(panel); - await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); - } - /** * @param {String} commonlyUsedOption 'superDatePickerCommonlyUsed_This_week' */ @@ -73,6 +61,13 @@ export function TimePickerPageProvider({ getService, getPageObjects }) { const input = await testSubjects.find(dataTestsubj); await input.clearValue(); await input.type(value); + } else if (browser.isInternetExplorer) { + const input = await testSubjects.find(dataTestsubj); + const currentValue = await input.getAttribute('value'); + await input.type((browser.keys.ARROW_RIGHT).repeat(currentValue.length)); + await input.type((browser.keys.BACK_SPACE).repeat(currentValue.length)); + await input.type(value); + await input.click(); } else { await testSubjects.setValue(dataTestsubj, value); } @@ -90,14 +85,16 @@ export function TimePickerPageProvider({ getService, getPageObjects }) { await testSubjects.click('superDatePickerendDatePopoverButton'); let panel = await this.getTimePickerPanel(); await testSubjects.click('superDatePickerAbsoluteTab'); + await testSubjects.click('superDatePickerAbsoluteDateInput'); await this.inputValue('superDatePickerAbsoluteDateInput', toTime); - + await PageObjects.common.sleep(500); // set from time await testSubjects.click('superDatePickerstartDatePopoverButton'); await this.waitPanelIsGone(panel); panel = await this.getTimePickerPanel(); await testSubjects.click('superDatePickerAbsoluteTab'); + await testSubjects.click('superDatePickerAbsoluteDateInput'); await this.inputValue('superDatePickerAbsoluteDateInput', fromTime); const superDatePickerApplyButtonExists = await testSubjects.exists('superDatePickerApplyTimeButton'); @@ -148,6 +145,7 @@ export function TimePickerPageProvider({ getService, getPageObjects }) { if (isShowDatesButton) { await testSubjects.click('superDatePickerShowDatesButton'); } + await testSubjects.exists('superDatePickerstartDatePopoverButton'); } async getRefreshConfig(keepQuickSelectOpen = false) { diff --git a/test/functional/page_objects/visualize_page.js b/test/functional/page_objects/visualize_page.js index e40ce93dd5401..c1d9446febf9f 100644 --- a/test/functional/page_objects/visualize_page.js +++ b/test/functional/page_objects/visualize_page.js @@ -718,8 +718,9 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli log.debug('Click Save Visualization button'); await testSubjects.click('confirmSaveSavedObjectButton'); + // if we wait for this, the success toast message could be gone :-() // wait for save to complete before completion - await PageObjects.header.waitUntilLoadingHasFinished(); + // await PageObjects.header.waitUntilLoadingHasFinished(); } async saveVisualizationExpectSuccess(vizName, { saveAsNew = false } = {}) { @@ -834,7 +835,7 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli // by a bunch of 'L'ines from that point to the next. Those points are // the values we're going to use to calculate the data values we're testing. // So git rid of the one 'M' and split the rest on the 'L's. - const tempArray = data.replace('M', '').split('L'); + const tempArray = data.replace('M ', '').replace('M', '').replace(/ L /g, 'L').replace(/ /g, ',').split('L'); const chartSections = tempArray.length / 2; // log.debug('chartSections = ' + chartSections + ' height = ' + yAxisHeight + ' yAxisLabel = ' + yAxisLabel); const chartData = []; @@ -888,7 +889,7 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli // 1). get the range/pixel ratio const yAxisRatio = await this.getChartYAxisRatio(axis); // 3). get the visWrapper__chart elements - const svg = await find.byCssSelector('div.chart > svg'); + const svg = await find.byCssSelector('div.chart'); const $ = await svg.parseDomContent(); const chartData = $(`g > g.series > rect[data-label="${dataLabel}"]`).toArray().map(chart => { const barHeight = $(chart).attr('height'); diff --git a/test/functional/services/browser.ts b/test/functional/services/browser.ts index 25f87b794edd0..5cf879e460402 100644 --- a/test/functional/services/browser.ts +++ b/test/functional/services/browser.ts @@ -18,10 +18,12 @@ */ import { cloneDeep } from 'lodash'; -import { IKey, logging } from 'selenium-webdriver'; +import { logging, Key, Origin } from 'selenium-webdriver'; +// @ts-ignore internal modules are not typed +import { LegacyActionSequence } from 'selenium-webdriver/lib/actions'; import { takeUntil } from 'rxjs/operators'; -import Jimp, { Bitmap } from 'jimp'; +import Jimp from 'jimp'; import { modifyUrl } from '../../../src/core/utils'; import { WebElementWrapper } from './lib/web_element_wrapper'; import { FtrProviderContext } from '../ftr_provider_context'; @@ -32,9 +34,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { const log = getService('log'); const config = getService('config'); const lifecycle = getService('lifecycle'); - const { driver, Key, LegacyActionSequence, browserType } = await getService( - '__webdriver__' - ).init(); + const { driver, browserType } = await getService('__webdriver__').init(); const isW3CEnabled = (driver as any).executor_.w3c === true; @@ -57,7 +57,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { /** * Keyboard events */ - public readonly keys: IKey = Key; + public readonly keys = Key; /** * Browser name @@ -68,6 +68,8 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { public readonly isFirefox: boolean = browserType === Browsers.Firefox; + public readonly isInternetExplorer: boolean = browserType === Browsers.InternetExplorer; + /** * Is WebDriver instance W3C compatible */ @@ -77,10 +79,8 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * Returns instance of Actions API based on driver w3c flag * https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebDriver.html#actions */ - public getActions(): any { - return this.isW3CEnabled - ? (driver as any).actions() - : (driver as any).actions({ bridge: true }); + public getActions() { + return this.isW3CEnabled ? driver.actions() : driver.actions({ bridge: true }); } /** @@ -102,7 +102,10 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @return {Promise<{height: number, width: number, x: number, y: number}>} */ public async getWindowSize(): Promise<{ height: number; width: number; x: number; y: number }> { - return await (driver.manage().window() as any).getRect(); + return await driver + .manage() + .window() + .getRect(); } /** @@ -113,18 +116,19 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {number} height * @return {Promise} */ - public async setWindowSize(width: number, height: number): Promise; - public async setWindowSize(...args: number[]): Promise; - public async setWindowSize(...args: unknown[]): Promise { - await (driver.manage().window() as any).setRect({ width: args[0], height: args[1] }); + public async setWindowSize(width: number, height: number) { + await driver + .manage() + .window() + .setRect({ width, height }); } /** * Gets a screenshot of the focused window and returns it as a Bitmap object */ - public async getScreenshotAsBitmap(): Promise { + public async getScreenshotAsBitmap() { const screenshot = await this.takeScreenshot(); - const buffer = Buffer.from(screenshot.toString(), 'base64'); + const buffer = Buffer.from(screenshot, 'base64'); const session = (await Jimp.read(buffer)).clone(); return session.bitmap; } @@ -136,7 +140,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {number} height * @return {Promise} */ - public async setScreenshotSize(width: number, height: number): Promise { + public async setScreenshotSize(width: number, height: number) { log.debug(`======browser======== setWindowSize ${width} ${height}`); // We really want to set the Kibana app to a specific size without regard to the browser chrome (borders) // But that means we first need to figure out the display scaling factor. @@ -179,9 +183,14 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async getCurrentUrl(): Promise { + public async getCurrentUrl() { // strip _t=Date query param when url is read - const current = await driver.getCurrentUrl(); + let current: string; + if (this.isInternetExplorer) { + current = await driver.executeScript('return window.document.location.href'); + } else { + current = await driver.getCurrentUrl(); + } const currentWithoutTime = modifyUrl(current, parsed => { delete (parsed.query as any)._t; return void 0; @@ -197,7 +206,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {boolean} insertTimestamp Optional * @return {Promise} */ - public async get(url: string, insertTimestamp: boolean = true): Promise { + public async get(url: string, insertTimestamp: boolean = true) { if (insertTimestamp) { const urlWithTime = modifyUrl(url, parsed => { (parsed.query as any)._t = Date.now(); @@ -223,12 +232,12 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { .move({ x: 0, y: 0 }) .perform(); await this.getActions() - .move({ x: point.x, y: point.y, origin: 'pointer' }) + .move({ x: point.x, y: point.y, origin: Origin.POINTER }) .perform(); } else { await this.getActions() .pause(this.getActions().mouse) - .move({ x: point.x, y: point.y, origin: 'pointer' }) + .move({ x: point.x, y: point.y, origin: Origin.POINTER }) .perform(); } } @@ -253,7 +262,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { } return data.location instanceof WebElementWrapper ? { x: data.offset.x || 0, y: data.offset.y || 0, origin: data.location._webElement } - : { x: data.location.x, y: data.location.y, origin: 'pointer' }; + : { x: data.location.x, y: data.location.y, origin: Origin.POINTER }; }; const startPoint = getW3CPoint(from); @@ -278,7 +287,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { return await this.getActions() .move({ origin: from.location._webElement }) .press() - .move({ x: to.location.x, y: to.location.y, origin: 'pointer' }) + .move({ x: to.location.x, y: to.location.y, origin: Origin.POINTER }) .release() .perform(); } else { @@ -298,7 +307,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async refresh(): Promise { + public async refresh() { await driver.navigate().refresh(); } @@ -308,10 +317,18 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async goBack(): Promise { + public async goBack() { await driver.navigate().back(); } + /** + * Moves forwards in the browser history. + * https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_Navigation.html#forward + */ + public async goForward() { + await driver.navigate().forward(); + } + /** * Sends a sequance of keyboard keys. For each key, this will record a pair of keyDown and keyUp actions * https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#sendKeys @@ -337,19 +354,19 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {x: number, y: number} point on browser page * @return {Promise} */ - public async clickMouseButton(point: { x: number; y: number }): Promise { + public async clickMouseButton(point: { x: number; y: number }) { if (this.isW3CEnabled) { await this.getActions() .move({ x: 0, y: 0 }) .perform(); await this.getActions() - .move({ x: point.x, y: point.y, origin: 'pointer' }) + .move({ x: point.x, y: point.y, origin: Origin.POINTER }) .click() .perform(); } else { await this.getActions() .pause(this.getActions().mouse) - .move({ x: point.x, y: point.y, origin: 'pointer' }) + .move({ x: point.x, y: point.y, origin: Origin.POINTER }) .click() .perform(); } @@ -362,7 +379,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async getPageSource(): Promise { + public async getPageSource() { return await driver.getPageSource(); } @@ -372,7 +389,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async takeScreenshot(): Promise { + public async takeScreenshot() { return await driver.takeScreenshot(); } @@ -382,7 +399,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {WebElementWrapper} element * @return {Promise} */ - public async doubleClick(): Promise { + public async doubleClick() { await this.getActions() .doubleClick() .perform(); @@ -396,10 +413,8 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * @param {string} handle * @return {Promise} */ - public async switchToWindow(handle: string): Promise; - public async switchToWindow(...args: string[]): Promise; - public async switchToWindow(...args: string[]): Promise { - await (driver.switchTo() as any).window(...args); + public async switchToWindow(nameOrHandle: string) { + await driver.switchTo().window(nameOrHandle); } /** @@ -408,7 +423,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async getAllWindowHandles(): Promise { + public async getAllWindowHandles() { return await driver.getAllWindowHandles(); } @@ -434,7 +449,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { * * @return {Promise} */ - public async closeCurrentWindow(): Promise { + public async closeCurrentWindow() { await driver.close(); } @@ -473,18 +488,18 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { ); } - public async getScrollTop(): Promise { + public async getScrollTop() { const scrollSize = await driver.executeScript('return document.body.scrollTop'); return parseInt(scrollSize, 10); } - public async getScrollLeft(): Promise { + public async getScrollLeft() { const scrollSize = await driver.executeScript('return document.body.scrollLeft'); return parseInt(scrollSize, 10); } // return promise with REAL scroll position - public async setScrollTop(scrollSize: number | string): Promise { + public async setScrollTop(scrollSize: number | string) { await driver.executeScript('document.body.scrollTop = ' + scrollSize); return this.getScrollTop(); } diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index e04d9a4eb303b..d2a03e43fe5de 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -75,7 +75,7 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont return; } - comboBoxElement.scrollIntoViewIfNecessary(); + await comboBoxElement.scrollIntoViewIfNecessary(); await this.setFilterValue(comboBoxElement, value); await this.openOptionsList(comboBoxElement); diff --git a/test/functional/services/find.ts b/test/functional/services/find.ts index 9723e3b745502..ec602e2df03a1 100644 --- a/test/functional/services/find.ts +++ b/test/functional/services/find.ts @@ -149,7 +149,7 @@ export async function FindProvider({ getService }: FtrProviderContext) { elements = []; } // Force isStale checks for all the retrieved elements. - await Promise.all(elements.map(async (element: any) => await element.isEnabled())); + await Promise.all(elements.map(async element => await element.isEnabled())); await this._withTimeout(defaultFindTimeout); return elements; }); @@ -330,7 +330,7 @@ export async function FindProvider({ getService }: FtrProviderContext) { log.debug(`Find.clickByPartialLinkText('${linkText}') with timeout=${timeout}`); await retry.try(async () => { const element = await this.byPartialLinkText(linkText, timeout); - await (element as any).moveMouseTo(); + await element.moveMouseTo(); await element.click(); }); } @@ -342,7 +342,7 @@ export async function FindProvider({ getService }: FtrProviderContext) { log.debug(`Find.clickByLinkText('${linkText}') with timeout=${timeout}`); await retry.try(async () => { const element = await this.byLinkText(linkText, timeout); - await (element as any).moveMouseTo(); + await element.moveMouseTo(); await element.click(); }); } @@ -478,7 +478,7 @@ export async function FindProvider({ getService }: FtrProviderContext) { private async _withTimeout(timeout: number) { if (timeout !== this.currentWait) { this.currentWait = timeout; - await (driver.manage() as any).setTimeouts({ implicit: timeout }); + await driver.manage().setTimeouts({ implicit: timeout }); } } } diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts index 74fc250438635..ce61530246eea 100644 --- a/test/functional/services/inspector.ts +++ b/test/functional/services/inspector.ts @@ -63,7 +63,7 @@ export function InspectorProvider({ getService }: FtrProviderContext) { if (!isOpen) { await retry.try(async () => { await testSubjects.click('openInspectorButton'); - await testSubjects.find('inspectorPanel'); + await testSubjects.exists('inspectorPanel'); }); } } diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts index ee35ca9e1de79..ec382306aaa9f 100644 --- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts +++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts @@ -18,7 +18,7 @@ */ import { delay } from 'bluebird'; -import { WebElement, WebDriver, By, IKey, until } from 'selenium-webdriver'; +import { WebElement, WebDriver, By, Key, until } from 'selenium-webdriver'; import { PNG } from 'pngjs'; // @ts-ignore not supported yet import cheerio from 'cheerio'; @@ -32,9 +32,7 @@ import { Browsers } from '../../remote/browsers'; interface Driver { driver: WebDriver; By: typeof By; - Key: IKey; until: typeof until; - LegacyActionSequence: any; } interface TypeOptions { @@ -53,10 +51,9 @@ const RETRY_CLICK_RETRY_ON_ERRORS = [ ]; export class WebElementWrapper { - private By: typeof By = this.webDriver.By; - private Keys: IKey = this.webDriver.Key; + private By = this.webDriver.By; private driver: WebDriver = this.webDriver.driver; - public LegacyAction: any = this.webDriver.LegacyActionSequence; + private Keys = Key; public isW3CEnabled: boolean = (this.webDriver.driver as any).executor_.w3c === true; public static create( @@ -98,11 +95,11 @@ export class WebElementWrapper { timeout?: number ) { if (timeout && timeout !== this.timeout) { - await (this.driver.manage() as any).setTimeouts({ implicit: timeout }); + await this.driver.manage().setTimeouts({ implicit: timeout }); } const elements = await findFunction(); if (timeout && timeout !== this.timeout) { - await (this.driver.manage() as any).setTimeouts({ implicit: this.timeout }); + await this.driver.manage().setTimeouts({ implicit: this.timeout }); } return elements; } @@ -149,10 +146,8 @@ export class WebElementWrapper { } } - private getActions(): any { - return this.isW3CEnabled - ? (this.driver as any).actions() - : (this.driver as any).actions({ bridge: true }); + private getActions() { + return this.isW3CEnabled ? this.driver.actions() : this.driver.actions({ bridge: true }); } /** @@ -233,6 +228,9 @@ export class WebElementWrapper { * @default { withJS: false } */ async clearValue(options: ClearOptions = { withJS: false }) { + if (this.browserType === Browsers.InternetExplorer) { + return this.clearValueWithKeyboard(); + } await this.retryCall(async function clearValue(wrapper) { if (wrapper.browserType === Browsers.Chrome || options.withJS) { // https://bugs.chromium.org/p/chromedriver/issues/detail?id=2702 @@ -249,6 +247,16 @@ export class WebElementWrapper { * @default { charByChar: false } */ async clearValueWithKeyboard(options: TypeOptions = { charByChar: false }) { + if (this.browserType === Browsers.InternetExplorer) { + const value = await this.getAttribute('value'); + // For IE testing, the text field gets clicked in the middle so + // first go HOME and then DELETE all chars + await this.pressKeys(this.Keys.HOME); + for (let i = 0; i <= value.length; i++) { + await this.pressKeys(this.Keys.DELETE); + } + return; + } if (options.charByChar === true) { const value = await this.getAttribute('value'); for (let i = 0; i <= value.length; i++) { @@ -309,7 +317,7 @@ export class WebElementWrapper { * @param {string|string[]} keys * @return {Promise} */ - public async pressKeys(keys: T | T[]): Promise; + public async pressKeys(keys: T | T[]): Promise; public async pressKeys(keys: T | T[]): Promise; public async pressKeys(keys: string): Promise { await this.retryCall(async function pressKeys(wrapper) { @@ -390,7 +398,7 @@ export class WebElementWrapper { */ public async getPosition(): Promise<{ height: number; width: number; x: number; y: number }> { return await this.retryCall(async function getPosition(wrapper) { - return await (wrapper._webElement as any).getRect(); + return await wrapper._webElement.getRect(); }); } @@ -403,7 +411,7 @@ export class WebElementWrapper { */ public async getSize(): Promise<{ height: number; width: number; x: number; y: number }> { return await this.retryCall(async function getSize(wrapper) { - return await (wrapper._webElement as any).getRect(); + return await wrapper._webElement.getRect(); }); } @@ -443,7 +451,7 @@ export class WebElementWrapper { * @param { xOffset: 0, yOffset: 0 } options Optional * @return {Promise} */ - public async clickMouseButton(options = { xOffset: 0, yOffset: 0 }): Promise { + public async clickMouseButton(options = { xOffset: 0, yOffset: 0 }) { await this.retryCall(async function clickMouseButton(wrapper) { await wrapper.scrollIntoViewIfNecessary(); if (wrapper.isW3CEnabled) { @@ -473,7 +481,7 @@ export class WebElementWrapper { * @param {WebElementWrapper} element * @return {Promise} */ - public async doubleClick(): Promise { + public async doubleClick() { await this.retryCall(async function clickMouseButton(wrapper) { await wrapper.scrollIntoViewIfNecessary(); await wrapper @@ -679,7 +687,7 @@ export class WebElementWrapper { * @return {Promise} */ public async waitForDeletedByCssSelector(selector: string): Promise { - await (this.driver.manage() as any).setTimeouts({ implicit: 1000 }); + await this.driver.manage().setTimeouts({ implicit: 1000 }); await this.driver.wait( async () => { const found = await this._webElement.findElements(this.By.css(selector)); @@ -688,7 +696,7 @@ export class WebElementWrapper { this.timeout, `The element with ${selector} selector was still present after ${this.timeout} sec.` ); - await (this.driver.manage() as any).setTimeouts({ implicit: this.timeout }); + await this.driver.manage().setTimeouts({ implicit: this.timeout }); } /** @@ -744,7 +752,7 @@ export class WebElementWrapper { */ public async takeScreenshot(): Promise { const screenshot = await this.driver.takeScreenshot(); - const buffer = Buffer.from(screenshot.toString(), 'base64'); + const buffer = Buffer.from(screenshot, 'base64'); const { width, height, x, y } = await this.getPosition(); const windowWidth: number = await this.driver.executeScript( 'return window.document.body.clientWidth' diff --git a/test/functional/services/remote/browsers.ts b/test/functional/services/remote/browsers.ts index 7fb07046a3636..46d81f1737a55 100644 --- a/test/functional/services/remote/browsers.ts +++ b/test/functional/services/remote/browsers.ts @@ -20,4 +20,5 @@ export enum Browsers { Chrome = 'chrome', Firefox = 'firefox', + InternetExplorer = 'ie', } diff --git a/test/functional/services/remote/remote.ts b/test/functional/services/remote/remote.ts index bbfe929187036..30e6a55c79627 100644 --- a/test/functional/services/remote/remote.ts +++ b/test/functional/services/remote/remote.ts @@ -27,7 +27,7 @@ export async function RemoteProvider({ getService }: FtrProviderContext) { const config = getService('config'); const browserType: Browsers = config.get('browser.type'); - const { driver, By, Key, until, LegacyActionSequence } = await initWebDriver(log, browserType); + const { driver, By, until } = await initWebDriver(log, browserType); const isW3CEnabled = (driver as any).executor_.w3c; const caps = await driver.getCapabilities(); @@ -44,24 +44,35 @@ export async function RemoteProvider({ getService }: FtrProviderContext) { lifecycle.on('beforeTests', async () => { // hard coded default, can be overridden per suite using `browser.setWindowSize()` // and will be automatically reverted after each suite - await (driver.manage().window() as any).setRect({ width: 1600, height: 1000 }); + await driver + .manage() + .window() + .setRect({ width: 1600, height: 1000 }); }); const windowSizeStack: Array<{ width: number; height: number }> = []; lifecycle.on('beforeTestSuite', async () => { - windowSizeStack.unshift(await (driver.manage().window() as any).getRect()); + windowSizeStack.unshift( + await driver + .manage() + .window() + .getRect() + ); }); lifecycle.on('beforeEachTest', async () => { - await (driver.manage() as any).setTimeouts({ implicit: config.get('timeouts.find') }); + await driver.manage().setTimeouts({ implicit: config.get('timeouts.find') }); }); lifecycle.on('afterTestSuite', async () => { const { width, height } = windowSizeStack.shift()!; - await (driver.manage().window() as any).setRect({ width, height }); + await driver + .manage() + .window() + .setRect({ width, height }); }); lifecycle.on('cleanup', async () => await driver.quit()); - return { driver, By, Key, until, LegacyActionSequence, browserType }; + return { driver, By, until, browserType }; } diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 6377d97dad28b..09213ab14f834 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -22,18 +22,17 @@ import { delay } from 'bluebird'; import chromeDriver from 'chromedriver'; // @ts-ignore types not available import geckoDriver from 'geckodriver'; -import { Builder, Capabilities, By, Key, logging, until } from 'selenium-webdriver'; -// @ts-ignore types not available +import { Builder, Capabilities, By, logging, until } from 'selenium-webdriver'; import chrome from 'selenium-webdriver/chrome'; -// @ts-ignore types not available import firefox from 'selenium-webdriver/firefox'; -// @ts-ignore internal modules are not typed -import { LegacyActionSequence } from 'selenium-webdriver/lib/actions'; +// @ts-ignore types not available +import ie from 'selenium-webdriver/ie'; // @ts-ignore internal modules are not typed import { Executor } from 'selenium-webdriver/lib/http'; // @ts-ignore internal modules are not typed import { getLogger } from 'selenium-webdriver/lib/logging'; +import { resolve, delimiter } from 'path'; import { preventParallelCalls } from './prevent_parallel_calls'; import { Browsers } from './browsers'; @@ -89,17 +88,42 @@ async function attemptToCreateCommand(log: ToolingLog, browserType: Browsers) { .withCapabilities(chromeCapabilities) .setChromeService(new chrome.ServiceBuilder(chromeDriver.path).enableVerboseLogging()) .build(); + case 'firefox': const firefoxOptions = new firefox.Options(); if (headlessBrowser === '1') { // See: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode - firefoxOptions.addArguments('-headless'); + firefoxOptions.headless(); } return new Builder() .forBrowser(browserType) .setFirefoxOptions(firefoxOptions) .setFirefoxService(new firefox.ServiceBuilder(geckoDriver.path).enableVerboseLogging()) .build(); + + case 'ie': + // https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/ie_exports_Options.html + const driverPath = resolve( + __dirname, + '..\\..\\..\\..\\node_modules\\iedriver\\lib\\iedriver' + ); + process.env.PATH = driverPath + delimiter + process.env.PATH; + + const ieCapabilities = Capabilities.ie(); + ieCapabilities.set('se:ieOptions', { + 'ie.ensureCleanSession': true, + ignoreProtectedModeSettings: true, + ignoreZoomSetting: false, // requires us to have 100% zoom level + nativeEvents: true, // need this for values to stick but it requires 100% scaling and window focus + requireWindowFocus: true, + logLevel: 'TRACE', + }); + + return new Builder() + .forBrowser(browserType) + .withCapabilities(ieCapabilities) + .build(); + default: throw new Error(`${browserType} is not supported yet`); } @@ -123,7 +147,7 @@ async function attemptToCreateCommand(log: ToolingLog, browserType: Browsers) { return; } // abort - return { driver: session, By, Key, until, LegacyActionSequence }; + return { driver: session, By, until }; } export async function initWebDriver(log: ToolingLog, browserType: Browsers) { diff --git a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx index f9285fbe4eaaf..627fd05404b24 100644 --- a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx @@ -23,6 +23,7 @@ import { CorePluginAPluginSetup } from '../../core_plugin_a/public/plugin'; declare global { interface Window { corePluginB?: string; + hasAccessToInjectedMetadata?: boolean; } } @@ -34,6 +35,7 @@ export class CorePluginBPlugin implements Plugin { public setup(core: CoreSetup, deps: CorePluginBDeps) { window.corePluginB = `Plugin A said: ${deps.core_plugin_a.getGreeting()}`; + window.hasAccessToInjectedMetadata = 'getInjectedVar' in core.injectedMetadata; core.application.register({ id: 'bar', diff --git a/test/plugin_functional/test_suites/core_plugins/ui_plugins.js b/test/plugin_functional/test_suites/core_plugins/ui_plugins.js index 3b46b60368bb1..df855f243d403 100644 --- a/test/plugin_functional/test_suites/core_plugins/ui_plugins.js +++ b/test/plugin_functional/test_suites/core_plugins/ui_plugins.js @@ -23,14 +23,26 @@ export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects(['common']); const browser = getService('browser'); - describe('ui plugin loading', function describeIndexTests() { - before(async () => { - await PageObjects.common.navigateToApp('settings'); + describe('ui plugins', function () { + describe('loading', function describeIndexTests() { + before(async () => { + await PageObjects.common.navigateToApp('settings'); + }); + + it('should attach string to window.corePluginB', async () => { + const corePluginB = await browser.execute('return window.corePluginB'); + expect(corePluginB).to.equal(`Plugin A said: Hello from Plugin A!`); + }); }); + describe('have injectedMetadata service provided', function describeIndexTests() { + before(async () => { + await PageObjects.common.navigateToApp('bar'); + }); - it('should attach string to window.corePluginB', async () => { - const corePluginB = await browser.execute('return window.corePluginB'); - expect(corePluginB).to.equal(`Plugin A said: Hello from Plugin A!`); + it('should attach string to window.corePluginB', async () => { + const hasAccessToInjectedMetadata = await browser.execute('return window.hasAccessToInjectedMetadata'); + expect(hasAccessToInjectedMetadata).to.equal(true); + }); }); }); } diff --git a/x-pack/gulpfile.js b/x-pack/gulpfile.js index edf8d3c59c3b7..74e24692f59f6 100644 --- a/x-pack/gulpfile.js +++ b/x-pack/gulpfile.js @@ -4,36 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -require('@kbn/plugin-helpers').babelRegister(); -require('dotenv').config({ silent: true }); +require('../src/setup_node_env'); -const path = require('path'); -const gulp = require('gulp'); -const mocha = require('gulp-mocha'); -const multiProcess = require('gulp-multi-process'); -const fancyLog = require('fancy-log'); -const pkg = require('./package.json'); +const { buildTask } = require('./tasks/build'); +const { devTask } = require('./tasks/dev'); +const { testTask, testBrowserTask, testBrowserDevTask, testServerTask } = require('./tasks/test'); +const { prepareTask } = require('./tasks/prepare'); -const buildDir = path.resolve(__dirname, 'build'); -const buildTarget = path.resolve(buildDir, 'plugin'); -const packageDir = path.resolve(buildDir, 'distributions'); -const coverageDir = path.resolve(__dirname, 'coverage'); - -const gulpHelpers = { - buildDir, - buildTarget, - coverageDir, - log: fancyLog, - mocha, - multiProcess, - packageDir, - pkg, +// export the tasks that are runnable from the CLI +module.exports = { + build: buildTask, + dev: devTask, + prepare: prepareTask, + test: testTask, + testserver: testServerTask, + testbrowser: testBrowserTask, + 'testbrowser-dev': testBrowserDevTask, }; - -require('./tasks/build')(gulp, gulpHelpers); -require('./tasks/clean')(gulp, gulpHelpers); -require('./tasks/dev')(gulp, gulpHelpers); -require('./tasks/prepare')(gulp, gulpHelpers); -require('./tasks/report')(gulp, gulpHelpers); -require('./tasks/test')(gulp, gulpHelpers); -require('./legacy/plugins/canvas/tasks')(gulp, gulpHelpers); diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index bba0051e31e08..856143c693954 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -110,6 +110,7 @@ describe('create()', () => { retryAt: null, state: {}, params: {}, + ownerId: null, }); savedObjectsClient.update.mockResolvedValueOnce({ id: '1', @@ -491,6 +492,7 @@ describe('create()', () => { retryAt: null, state: {}, params: {}, + ownerId: null, }); savedObjectsClient.update.mockResolvedValueOnce({ id: '1', @@ -568,6 +570,7 @@ describe('enable()', () => { taskType: '', startedAt: null, retryAt: null, + ownerId: null, }); await alertsClient.enable({ id: '1' }); @@ -643,6 +646,7 @@ describe('enable()', () => { taskType: '', startedAt: null, retryAt: null, + ownerId: null, }); alertsClientParams.createAPIKey.mockResolvedValueOnce({ created: true, diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts index 2490a187ee458..8875e964ef58e 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_create_task_runner_function.test.ts @@ -33,6 +33,7 @@ beforeAll(() => { params: { alertId: '1', }, + ownerId: null, }; }); diff --git a/x-pack/legacy/plugins/canvas/tasks/helpers/babelhook.js b/x-pack/legacy/plugins/canvas/tasks/helpers/babelhook.js deleted file mode 100644 index dea18db918fcd..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/helpers/babelhook.js +++ /dev/null @@ -1,51 +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. - */ - -const { resolve } = require('path'); -const register = require('@babel/register'); -const options = { - babelrc: false, - presets: [require.resolve('@kbn/babel-preset/node_preset')], - sourceMaps: false, - plugins: [ - [ - 'mock-imports', - [ - { - pattern: 'ui/chrome', - location: resolve(__dirname, '..', 'mocks', 'uiChrome'), - }, - { - pattern: 'ui/notify', - location: resolve(__dirname, '..', 'mocks', 'uiNotify'), - }, - { - pattern: 'ui/storage', - location: resolve(__dirname, '..', 'mocks', 'uiStorage'), - }, - { - pattern: 'ui/url/absolute_to_parsed_url', - location: resolve(__dirname, '..', 'mocks', 'absoluteToParsedUrl'), - }, - { - // ugly hack so that importing non-js files works, required for the function docs - pattern: '.(less|png|svg)$', - location: resolve(__dirname, '..', 'mocks', 'noop'), - }, - { - pattern: 'plugins/canvas/apps', - location: resolve(__dirname, '..', 'mocks', 'noop'), - }, - { - pattern: '/state/store', - location: resolve(__dirname, '..', 'mocks', 'stateStore'), - }, - ], - ], - ], -}; - -register(options); diff --git a/x-pack/legacy/plugins/canvas/tasks/helpers/dom_setup.js b/x-pack/legacy/plugins/canvas/tasks/helpers/dom_setup.js deleted file mode 100644 index bbc8cc52d6a68..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/helpers/dom_setup.js +++ /dev/null @@ -1,23 +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 { JSDOM } from 'jsdom'; -import { APP_ROUTE } from '../../common/lib/constants'; -import chrome from '../mocks/uiChrome'; - -const basePath = chrome.getBasePath(); -const basename = `${basePath}${APP_ROUTE}`; - -const { window } = new JSDOM('', { - url: `http://localhost:5601/${basename}`, - pretendToBeVisual: true, -}); - -global.window = window; -global.document = window.document; -global.navigator = window.navigator; -global.requestAnimationFrame = window.requestAnimationFrame; -global.HTMLElement = window.HTMLElement; diff --git a/x-pack/legacy/plugins/canvas/tasks/helpers/enzyme_setup.js b/x-pack/legacy/plugins/canvas/tasks/helpers/enzyme_setup.js deleted file mode 100644 index 290e3d220aa4b..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/helpers/enzyme_setup.js +++ /dev/null @@ -1,10 +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 { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -configure({ adapter: new Adapter() }); diff --git a/x-pack/legacy/plugins/canvas/tasks/index.js b/x-pack/legacy/plugins/canvas/tasks/index.js deleted file mode 100644 index 48ff275877836..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/index.js +++ /dev/null @@ -1,11 +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 test from './test'; - -export default function canvasTasks(gulp, gulpHelpers) { - test(gulp, gulpHelpers); -} diff --git a/x-pack/legacy/plugins/canvas/tasks/mocks/absoluteToParsedUrl.js b/x-pack/legacy/plugins/canvas/tasks/mocks/absoluteToParsedUrl.js deleted file mode 100644 index d73885ef0cc28..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/mocks/absoluteToParsedUrl.js +++ /dev/null @@ -1,10 +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 const absoluteToParsedUrl = () => { - getAbsoluteUrl: () => - 'http://localhost:5601/kbp/app/canvas#/workpad/workpad-24d56dad-ae70-42b8-9ef1-c5350ecd426c/page/1'; -}; // noop diff --git a/x-pack/legacy/plugins/canvas/tasks/mocks/stateStore.js b/x-pack/legacy/plugins/canvas/tasks/mocks/stateStore.js deleted file mode 100644 index 9d3df08fffe09..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/mocks/stateStore.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export function getState() { - return { - assets: { - yay: { value: 'here is your image' }, - }, - }; -} diff --git a/x-pack/legacy/plugins/canvas/tasks/test.js b/x-pack/legacy/plugins/canvas/tasks/test.js deleted file mode 100644 index 9857e9c774e06..0000000000000 --- a/x-pack/legacy/plugins/canvas/tasks/test.js +++ /dev/null @@ -1,66 +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 { resolve, join } from 'path'; - -export default function testTasks(gulp, { mocha }) { - const canvasRoot = resolve(__dirname, '..'); - - function runMocha(globs, { withEnzyme = false, withDOM = false } = {}) { - const requires = [join(canvasRoot, 'tasks/helpers/babelhook')]; - - if (withDOM) { - requires.push(join(canvasRoot, 'tasks/helpers/dom_setup')); - } - if (withEnzyme) { - requires.push(join(canvasRoot, 'tasks/helpers/enzyme_setup')); - } - - return gulp.src(globs, { read: false }).pipe( - mocha({ - ui: 'bdd', - require: requires, - }) - ); - } - - const getTestGlobs = rootPath => [ - join(canvasRoot, `${rootPath}/**/__tests__/**/*.js`), - join(canvasRoot, `!${rootPath}/**/__tests__/fixtures/**/*.js`), - ]; - - const getRootGlobs = rootPath => [join(canvasRoot, `${rootPath}/**/*.js`)]; - - gulp.task('canvas:test:common', () => { - return runMocha(getTestGlobs('common'), { withDOM: true }); - }); - - gulp.task('canvas:test:server', () => { - return runMocha(getTestGlobs('server')); - }); - - gulp.task('canvas:test:browser', () => { - return runMocha(getTestGlobs('public'), { withEnzyme: true, withDOM: true }); - }); - - gulp.task('canvas:test:plugins', () => { - return runMocha(getTestGlobs('canvas_plugin_src')); - }); - - gulp.task('canvas:test', [ - 'canvas:test:plugins', - 'canvas:test:common', - 'canvas:test:server', - 'canvas:test:browser', - ]); - - gulp.task('canvas:test:dev', () => { - gulp.watch(getRootGlobs('common'), ['canvas:test:common']); - gulp.watch(getRootGlobs('server'), ['canvas:test:server']); - gulp.watch(getRootGlobs('public'), ['canvas:test:browser']); - gulp.watch(getRootGlobs('canvas_plugin_src'), ['canvas:test:plugins']); - }); -} diff --git a/x-pack/legacy/plugins/graph/public/angular/templates/index.html b/x-pack/legacy/plugins/graph/public/angular/templates/index.html index 9e9356f30642e..e291271bb1d6c 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -17,7 +17,7 @@ is-initialized="workspaceInitialized || savedWorkspace.id" initial-query="initialQuery" on-fill-workspace="fillWorkspace" - autocomplete-start="autocompleteStart" + plugin-data-start="pluginDataStart" core-start="coreStart" store="store" > diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 2cd3e13013d9a..4e33d0995cbc8 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -106,9 +106,10 @@ app.directive('graphApp', function (reactDirective) { ['onQuerySubmit', { watchDepth: 'reference' }], ['initialQuery', { watchDepth: 'reference' }], ['confirmWipeWorkspace', { watchDepth: 'reference' }], - ['autocompleteStart', { watchDepth: 'reference' }], ['coreStart', { watchDepth: 'reference' }], - ['reduxStore', { watchDepth: 'reference' }] + ['pluginDataStart', { watchDepth: 'reference' }], + ['store', { watchDepth: 'reference' }], + ['reduxStore', { watchDepth: 'reference' }], ]); }); @@ -321,9 +322,9 @@ app.controller('graphuiPlugin', function ( chrome, }); + $scope.pluginDataStart = npStart.plugins.data; $scope.store = new Storage(window.localStorage); $scope.coreStart = npStart.core; - $scope.autocompleteStart = npStart.plugins.data.autocomplete; $scope.loading = false; $scope.spymode = 'request'; diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index efc8c1bfcc00a..56b1c9563bece 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -5,12 +5,13 @@ */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { Provider } from 'react-redux'; import React, { useState } from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { Storage } from 'ui/storage'; import { CoreStart } from 'kibana/public'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; import { FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; import { GraphStore } from '../state_management'; @@ -20,7 +21,8 @@ import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_reac export interface GraphAppProps extends SearchBarProps { coreStart: CoreStart; - autocompleteStart: AutocompletePublicPluginStart; + // This is not named dataStart because of Angular treating data- prefix differently + pluginDataStart: DataPublicPluginStart; store: Storage; reduxStore: GraphStore; isInitialized: boolean; @@ -29,16 +31,16 @@ export interface GraphAppProps extends SearchBarProps { export function GraphApp(props: GraphAppProps) { const [pickerOpen, setPickerOpen] = useState(false); - const { coreStart, autocompleteStart, store, reduxStore, ...searchBarProps } = props; + const { coreStart, pluginDataStart, store, reduxStore, ...searchBarProps } = props; return ( diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx index 519e41e846051..2279873762251 100644 --- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx +++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx @@ -29,7 +29,7 @@ import classNames from 'classnames'; import { WorkspaceField } from '../../types'; import { iconChoices } from '../../helpers/style_choices'; import { LegacyIcon } from '../legacy_icon'; -import { FieldIcon } from './field_icon'; +import { FieldIcon } from '../../../../../../../src/plugins/kibana_react/public'; import { UpdateableFieldProperties } from './field_manager'; import { isEqual } from '../helpers'; @@ -216,7 +216,7 @@ export function FieldEditor({ const { type, label } = option; return ( - {' '} + {' '} {label} ); diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx index 8ef566e881989..5df94ac873bc1 100644 --- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx +++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx @@ -9,8 +9,7 @@ import { EuiPopover, EuiSelectable, EuiBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import classNames from 'classnames'; import { WorkspaceField } from '../../types'; - -import { FieldIcon } from './field_icon'; +import { FieldIcon } from '../../../../../../../src/plugins/kibana_react/public'; export interface FieldPickerProps { fieldMap: Record; @@ -121,7 +120,7 @@ function toOptions( ): Array<{ label: string; checked?: 'on' | 'off'; prepend?: ReactNode }> { return fields.map(field => ({ label: field.name, - prepend: , + prepend: , checked: field.selected ? 'on' : undefined, })); } diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx index 3c37c77e6d450..6dfa6b9796e52 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx @@ -17,6 +17,7 @@ import { I18nProvider } from '@kbn/i18n/react'; jest.mock('ui/new_platform'); import { openSourceModal } from '../services/source_modal'; + import { GraphStore, setDatasource } from '../state_management'; import { ReactWrapper } from 'enzyme'; import { createMockGraphStore } from '../state_management/mocks'; @@ -40,6 +41,9 @@ function wrapSearchBarInContext(testProps: OuterSearchBarProps) { notifications: {} as CoreStart['notifications'], http: {} as CoreStart['http'], overlays: {} as CoreStart['overlays'], + store: { + get: () => {}, + }, }; return ( @@ -79,6 +83,7 @@ describe('search_bar', () => { function mountSearchBar() { jest.clearAllMocks(); const wrappedSearchBar = wrapSearchBarInContext({ ...defaultProps }); + instance = mountWithIntl({wrappedSearchBar}); } diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx index ae0d32cd5f686..11e5d353cadaf 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx @@ -18,6 +18,7 @@ import { IndexPattern, } from '../../../../../../src/legacy/core_plugins/data/public'; import { openSourceModal } from '../services/source_modal'; + import { GraphState, datasourceSelector, @@ -31,6 +32,7 @@ export interface OuterSearchBarProps { isLoading: boolean; initialQuery?: string; onQuerySubmit: (query: string) => void; + confirmWipeWorkspace: (onConfirm: () => void) => void; indexPatternProvider: IndexPatternProvider; } diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts index 2dcaf35cc41d9..3af07980910b8 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts @@ -6,13 +6,7 @@ import * as rt from 'io-ts'; -import { - badRequestErrorRT, - conflictErrorRT, - forbiddenErrorRT, - metricStatisticsRT, - timeRangeRT, -} from '../../shared'; +import { badRequestErrorRT, conflictErrorRT, forbiddenErrorRT, timeRangeRT } from '../../shared'; export const LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH = '/api/infra/log_analysis/results/log_entry_rate'; @@ -43,12 +37,15 @@ export const logEntryRateAnomaly = rt.type({ typicalLogEntryRate: rt.number, }); -export const logEntryRateHistogramBucket = rt.type({ +export const logEntryRateDataSetRT = rt.type({ + analysisBucketCount: rt.number, anomalies: rt.array(logEntryRateAnomaly), - duration: rt.number, - logEntryRateStats: metricStatisticsRT, - modelLowerBoundStats: metricStatisticsRT, - modelUpperBoundStats: metricStatisticsRT, + averageActualLogEntryRate: rt.number, + dataSetId: rt.string, +}); + +export const logEntryRateHistogramBucket = rt.type({ + dataSets: rt.array(logEntryRateDataSetRT), startTime: rt.number, }); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/get_log_entry_rate.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/get_log_entry_rate.ts new file mode 100644 index 0000000000000..471a00d40984c --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/get_log_entry_rate.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 { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { identity } from 'fp-ts/lib/function'; +import { kfetch } from 'ui/kfetch'; + +import { + getLogEntryRateRequestPayloadRT, + getLogEntryRateSuccessReponsePayloadRT, + LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, +} from '../../../../../common/http_api/log_analysis'; +import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; + +export const callGetLogEntryRateAPI = async ( + sourceId: string, + startTime: number, + endTime: number, + bucketDuration: number +) => { + const response = await kfetch({ + method: 'POST', + pathname: LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, + body: JSON.stringify( + getLogEntryRateRequestPayloadRT.encode({ + data: { + sourceId, + timeRange: { + startTime, + endTime, + }, + bucketDuration, + }, + }) + ), + }); + return pipe( + getLogEntryRateSuccessReponsePayloadRT.decode(response), + fold(throwErrors(createPlainError), identity) + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_graph_data/log_entry_rate.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_graph_data/log_entry_rate.tsx deleted file mode 100644 index f54402a1a8707..0000000000000 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_graph_data/log_entry_rate.tsx +++ /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. - */ - -import { useMemo } from 'react'; -import { GetLogEntryRateSuccessResponsePayload } from '../../../../../common/http_api/log_analysis'; - -interface LogRateAreaSeriesDataPoint { - x: number; - min: number | null; - max: number | null; -} -type LogRateAreaSeries = LogRateAreaSeriesDataPoint[]; -type LogRateLineSeriesDataPoint = [number, number | null]; -type LogRateLineSeries = LogRateLineSeriesDataPoint[]; -type LogRateAnomalySeriesDataPoint = [number, number]; -type LogRateAnomalySeries = LogRateAnomalySeriesDataPoint[]; - -export const useLogEntryRateGraphData = ({ - data, -}: { - data: GetLogEntryRateSuccessResponsePayload['data'] | null; -}) => { - const areaSeries: LogRateAreaSeries = useMemo(() => { - if (!data || (data && data.histogramBuckets && !data.histogramBuckets.length)) { - return []; - } - return data.histogramBuckets.reduce((acc: any, bucket) => { - acc.push({ - x: bucket.startTime, - min: bucket.modelLowerBoundStats.min, - max: bucket.modelUpperBoundStats.max, - }); - return acc; - }, []); - }, [data]); - - const lineSeries: LogRateLineSeries = useMemo(() => { - if (!data || (data && data.histogramBuckets && !data.histogramBuckets.length)) { - return []; - } - return data.histogramBuckets.reduce((acc: any, bucket) => { - acc.push([bucket.startTime, bucket.logEntryRateStats.avg]); - return acc; - }, []); - }, [data]); - - const anomalySeries: LogRateAnomalySeries = useMemo(() => { - if (!data || (data && data.histogramBuckets && !data.histogramBuckets.length)) { - return []; - } - return data.histogramBuckets.reduce((acc: any, bucket) => { - if (bucket.anomalies.length > 0) { - bucket.anomalies.forEach(anomaly => { - acc.push([anomaly.startTime, anomaly.actualLogEntryRate]); - }); - return acc; - } else { - return acc; - } - }, []); - }, [data]); - - return { - areaSeries, - lineSeries, - anomalySeries, - }; -}; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx index 4e7a6647a9579..8b21a7e829894 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx @@ -5,19 +5,10 @@ */ import { useMemo, useState } from 'react'; -import { kfetch } from 'ui/kfetch'; -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { - getLogEntryRateRequestPayloadRT, - getLogEntryRateSuccessReponsePayloadRT, - GetLogEntryRateSuccessResponsePayload, - LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, -} from '../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../common/runtime_types'; +import { GetLogEntryRateSuccessResponsePayload } from '../../../../common/http_api/log_analysis'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; +import { callGetLogEntryRateAPI } from './api/get_log_entry_rate'; type LogEntryRateResults = GetLogEntryRateSuccessResponsePayload['data']; @@ -38,30 +29,10 @@ export const useLogEntryRate = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await kfetch({ - method: 'POST', - pathname: LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, - body: JSON.stringify( - getLogEntryRateRequestPayloadRT.encode({ - data: { - sourceId, - timeRange: { - startTime, - endTime, - }, - bucketDuration, - }, - }) - ), - }); + return await callGetLogEntryRateAPI(sourceId, startTime, endTime, bucketDuration); }, onResolve: response => { - const { data } = pipe( - getLogEntryRateSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); - - setLogEntryRate(data); + setLogEntryRate(response.data); }, }, [sourceId, startTime, endTime, bucketDuration] diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/chart_helpers/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/chart_helpers/index.tsx deleted file mode 100644 index df0eca449bb9f..0000000000000 --- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/chart_helpers/index.tsx +++ /dev/null @@ -1,20 +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 chrome from 'ui/chrome'; -import { SpecId, Theme, LIGHT_THEME, DARK_THEME } from '@elastic/charts'; - -export const getColorsMap = (color: string, specId: SpecId) => { - const map = new Map(); - map.set({ colorValues: [], specId }, color); - return map; -}; - -export const isDarkMode = () => chrome.getUiSettingsClient().get('theme:darkMode'); - -export const getChartTheme = (): Theme => { - return isDarkMode() ? DARK_THEME : LIGHT_THEME; -}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx index 3629413d6d30c..aaf24c22594e5 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx @@ -6,7 +6,6 @@ import datemath from '@elastic/datemath'; import { - EuiBadge, EuiFlexGroup, EuiFlexItem, EuiPage, @@ -17,7 +16,6 @@ import { EuiSuperDatePicker, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import moment from 'moment'; import React, { useCallback, useMemo, useState } from 'react'; @@ -122,21 +120,6 @@ export const AnalysisResultsContent = ({ [setAutoRefresh] ); - const anomaliesDetected = useMemo(() => { - if (!logEntryRate) { - return null; - } else { - if (logEntryRate.histogramBuckets && logEntryRate.histogramBuckets.length) { - return logEntryRate.histogramBuckets.reduce( - (acc, bucket) => acc + bucket.anomalies.length, - 0 - ); - } else { - return null; - } - } - }, [logEntryRate]); - return ( <> {isLoading && !logEntryRate ? ( @@ -150,29 +133,8 @@ export const AnalysisResultsContent = ({ - - - - {anomaliesDetected !== null ? ( - - - {anomaliesDetected} - - ), - number: anomaliesDetected, - }} - /> - - ) : null} - - - - + + void; + timeRange: TimeRange; +}> = ({ bucketDuration, histogramBuckets, setTimeRange, timeRange }) => { + const [dateFormat] = useKibanaUiSetting('dateFormat'); + const [isDarkMode] = useKibanaUiSetting('theme:darkMode'); + + const chartDateFormatter = useMemo( + () => niceTimeFormatter([timeRange.startTime, timeRange.endTime]), + [timeRange] + ); + + const logEntryRateSeries = useMemo( + () => + histogramBuckets + ? histogramBuckets.reduce>( + (buckets, bucket) => { + return [ + ...buckets, + ...bucket.dataSets.map(dataSet => ({ + group: dataSet.dataSetId === '' ? 'unknown' : dataSet.dataSetId, + time: bucket.startTime, + value: dataSet.averageActualLogEntryRate, + })), + ]; + }, + [] + ) + : [], + [histogramBuckets] + ); + + const logEntryRateAnomalyAnnotations = useMemo( + () => + histogramBuckets + ? histogramBuckets.reduce((annotatedBuckets, bucket) => { + const anomalies = bucket.dataSets.reduce( + (accumulatedAnomalies, dataSet) => [...accumulatedAnomalies, ...dataSet.anomalies], + [] + ); + if (anomalies.length <= 0) { + return annotatedBuckets; + } + return [ + ...annotatedBuckets, + { + coordinates: { + x0: bucket.startTime, + x1: bucket.startTime + bucketDuration, + }, + details: i18n.translate( + 'xpack.infra.logs.analysis.logRateSectionAnomalyCountTooltipLabel', + { + defaultMessage: `{anomalyCount, plural, one {# anomaly} other {# anomalies}}`, + values: { + anomalyCount: anomalies.length, + }, + } + ), + }, + ]; + }, []) + : [], + [histogramBuckets] + ); + + const logEntryRateSpecId = getSpecId('averageValues'); + const logEntryRateAnomalyAnnotationsId = getAnnotationId('anomalies'); + + const tooltipProps = useMemo( + () => ({ + headerFormatter: (tooltipData: TooltipValue) => + moment(tooltipData.value).format(dateFormat || 'Y-MM-DD HH:mm:ss.SSS'), + }), + [dateFormat] + ); + + const handleBrushEnd = useCallback( + (startTime: number, endTime: number) => { + setTimeRange({ + endTime, + startTime, + }); + }, + [setTimeRange] + ); + + return ( +
+ + + Number(value).toFixed(0)} + /> + + + + +
+ ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/chart.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/chart.tsx deleted file mode 100644 index 0d703420e7412..0000000000000 --- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/chart.tsx +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useMemo, useCallback, useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import moment from 'moment'; -import { - Axis, - Chart, - getAxisId, - getSpecId, - AreaSeries, - LineSeries, - niceTimeFormatter, - Settings, - TooltipValue, -} from '@elastic/charts'; -import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; -import { getColorsMap, isDarkMode, getChartTheme } from '../../chart_helpers'; -import { GetLogEntryRateSuccessResponsePayload } from '../../../../../../common/http_api/log_analysis/results/log_entry_rate'; -import { useLogEntryRateGraphData } from '../../../../../containers/logs/log_analysis/log_analysis_graph_data/log_entry_rate'; -import { useKibanaUiSetting } from '../../../../../utils/use_kibana_ui_setting'; -import { TimeRange } from '../../../../../../common/http_api/shared/time_range'; - -const areaSeriesColour = 'rgb(224, 237, 255)'; -const lineSeriesColour = 'rgb(49, 133, 252)'; - -interface Props { - data: GetLogEntryRateSuccessResponsePayload['data'] | null; - setTimeRange: (timeRange: TimeRange) => void; - timeRange: TimeRange; -} - -export const ChartView = ({ data, setTimeRange, timeRange }: Props) => { - const { areaSeries, lineSeries, anomalySeries } = useLogEntryRateGraphData({ data }); - - const dateFormatter = useMemo( - () => - lineSeries.length > 0 - ? niceTimeFormatter([timeRange.startTime, timeRange.endTime]) - : (value: number) => `${value}`, - [lineSeries, timeRange] - ); - - const areaSpecId = getSpecId('modelBounds'); - const lineSpecId = getSpecId('averageValues'); - const anomalySpecId = getSpecId('anomalies'); - - const [dateFormat] = useKibanaUiSetting('dateFormat'); - - const tooltipProps = useMemo( - () => ({ - headerFormatter: (tooltipData: TooltipValue) => - moment(tooltipData.value).format(dateFormat || 'Y-MM-DD HH:mm:ss.SSS'), - }), - [dateFormat] - ); - - const [isShowingModelBounds, setIsShowingModelBounds] = useState(true); - - const handleBrushEnd = useCallback( - (startTime: number, endTime: number) => { - setTimeRange({ - endTime, - startTime, - }); - }, - [setTimeRange] - ); - - return ( - <> - - - { - setIsShowingModelBounds(e.target.checked); - }} - /> - - -
- - - Number(value).toFixed(0)} - /> - {isShowingModelBounds ? ( - - ) : null} - - - - -
- - ); -}; - -const showModelBoundsLabel = i18n.translate( - 'xpack.infra.logs.analysis.logRateSectionModelBoundsCheckboxLabel', - { defaultMessage: 'Show model bounds' } -); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx index c03a4817e4d4c..1f01af33e33c4 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx @@ -16,8 +16,8 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { GetLogEntryRateSuccessResponsePayload } from '../../../../../../common/http_api/log_analysis/results/log_entry_rate'; -import { ChartView } from './chart'; import { TimeRange } from '../../../../../../common/http_api/shared/time_range'; +import { LogEntryRateBarChart } from './bar_chart'; export const LogRateResults = ({ isLoading, @@ -70,7 +70,12 @@ export const LogRateResults = ({ } /> ) : ( - + )} ); diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_analysis.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_analysis.ts index ac7f7b6df8d62..31d9c5403e2d2 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_analysis.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_analysis.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as rt from 'io-ts'; - import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; @@ -13,8 +11,14 @@ import { getJobId } from '../../../common/log_analysis'; import { throwErrors, createPlainError } from '../../../common/runtime_types'; import { InfraBackendFrameworkAdapter, InfraFrameworkRequest } from '../adapters/framework'; import { NoLogRateResultsIndexError } from './errors'; +import { + logRateModelPlotResponseRT, + createLogEntryRateQuery, + LogRateModelPlotBucket, + CompositeTimestampDataSetKey, +} from './queries'; -const ML_ANOMALY_INDEX_PREFIX = '.ml-anomalies-'; +const COMPOSITE_AGGREGATION_BATCH_SIZE = 1000; export class InfraLogAnalysis { constructor( @@ -38,168 +42,95 @@ export class InfraLogAnalysis { ) { const logRateJobId = this.getJobIds(request, sourceId).logEntryRate; - const mlModelPlotResponse = await this.libs.framework.callWithRequest(request, 'search', { - allowNoIndices: true, - body: { - query: { - bool: { - filter: [ - { - range: { - timestamp: { - gte: startTime, - lt: endTime, - }, - }, - }, - { - terms: { - result_type: ['model_plot', 'record'], - }, - }, - { - term: { - detector_index: { - value: 0, - }, - }, - }, - ], - }, - }, - aggs: { - timestamp_buckets: { - date_histogram: { - field: 'timestamp', - fixed_interval: `${bucketDuration}ms`, - }, - aggs: { - filter_model_plot: { - filter: { - term: { - result_type: 'model_plot', - }, - }, - aggs: { - stats_model_lower: { - stats: { - field: 'model_lower', - }, - }, - stats_model_upper: { - stats: { - field: 'model_upper', - }, - }, - stats_actual: { - stats: { - field: 'actual', - }, - }, - }, - }, - filter_records: { - filter: { - term: { - result_type: 'record', - }, - }, - aggs: { - top_hits_record: { - top_hits: { - _source: Object.keys(logRateMlRecordRT.props), - size: 100, - sort: [ - { - timestamp: 'asc', - }, - ], - }, - }, - }, - }, - }, - }, - }, - }, - ignoreUnavailable: true, - index: `${ML_ANOMALY_INDEX_PREFIX}${logRateJobId}`, - size: 0, - trackScores: false, - trackTotalHits: false, - }); + let mlModelPlotBuckets: LogRateModelPlotBucket[] = []; + let afterLatestBatchKey: CompositeTimestampDataSetKey | undefined; - if (mlModelPlotResponse._shards.total === 0) { - throw new NoLogRateResultsIndexError( - `Failed to find ml result index for job ${logRateJobId}.` + while (true) { + const mlModelPlotResponse = await this.libs.framework.callWithRequest( + request, + 'search', + createLogEntryRateQuery( + logRateJobId, + startTime, + endTime, + bucketDuration, + COMPOSITE_AGGREGATION_BATCH_SIZE, + afterLatestBatchKey + ) ); - } - const mlModelPlotBuckets = pipe( - logRateModelPlotResponseRT.decode(mlModelPlotResponse), - map(response => response.aggregations.timestamp_buckets.buckets), - fold(throwErrors(createPlainError), identity) - ); + if (mlModelPlotResponse._shards.total === 0) { + throw new NoLogRateResultsIndexError( + `Failed to find ml result index for job ${logRateJobId}.` + ); + } - return mlModelPlotBuckets.map(bucket => ({ - anomalies: bucket.filter_records.top_hits_record.hits.hits.map(({ _source: record }) => ({ - actualLogEntryRate: record.actual[0], - anomalyScore: record.record_score, - duration: record.bucket_span * 1000, - startTime: record.timestamp, - typicalLogEntryRate: record.typical[0], - })), - duration: bucketDuration, - logEntryRateStats: bucket.filter_model_plot.stats_actual, - modelLowerBoundStats: bucket.filter_model_plot.stats_model_lower, - modelUpperBoundStats: bucket.filter_model_plot.stats_model_upper, - startTime: bucket.key, - })); - } -} + const { after_key: afterKey, buckets: latestBatchBuckets } = pipe( + logRateModelPlotResponseRT.decode(mlModelPlotResponse), + map(response => response.aggregations.timestamp_data_set_buckets), + fold(throwErrors(createPlainError), identity) + ); -const logRateMlRecordRT = rt.type({ - actual: rt.array(rt.number), - bucket_span: rt.number, - record_score: rt.number, - timestamp: rt.number, - typical: rt.array(rt.number), -}); + mlModelPlotBuckets = [...mlModelPlotBuckets, ...latestBatchBuckets]; + afterLatestBatchKey = afterKey; -const logRateStatsAggregationRT = rt.type({ - avg: rt.union([rt.number, rt.null]), - count: rt.number, - max: rt.union([rt.number, rt.null]), - min: rt.union([rt.number, rt.null]), - sum: rt.number, -}); + if (latestBatchBuckets.length < COMPOSITE_AGGREGATION_BATCH_SIZE) { + break; + } + } -const logRateModelPlotResponseRT = rt.type({ - aggregations: rt.type({ - timestamp_buckets: rt.type({ - buckets: rt.array( - rt.type({ - key: rt.number, - filter_records: rt.type({ - doc_count: rt.number, - top_hits_record: rt.type({ - hits: rt.type({ - hits: rt.array( - rt.type({ - _source: logRateMlRecordRT, - }) - ), - }), - }), - }), - filter_model_plot: rt.type({ - doc_count: rt.number, - stats_actual: logRateStatsAggregationRT, - stats_model_lower: logRateStatsAggregationRT, - stats_model_upper: logRateStatsAggregationRT, - }), - }) - ), - }), - }), -}); + return mlModelPlotBuckets.reduce< + Array<{ + dataSets: Array<{ + analysisBucketCount: number; + anomalies: Array<{ + actualLogEntryRate: number; + anomalyScore: number; + duration: number; + startTime: number; + typicalLogEntryRate: number; + }>; + averageActualLogEntryRate: number; + dataSetId: string; + }>; + startTime: number; + }> + >((histogramBuckets, timestampDataSetBucket) => { + const previousHistogramBucket = histogramBuckets[histogramBuckets.length - 1]; + const dataSet = { + analysisBucketCount: timestampDataSetBucket.filter_model_plot.doc_count, + anomalies: timestampDataSetBucket.filter_records.top_hits_record.hits.hits.map( + ({ _source: record }) => ({ + actualLogEntryRate: record.actual[0], + anomalyScore: record.record_score, + duration: record.bucket_span * 1000, + startTime: record.timestamp, + typicalLogEntryRate: record.typical[0], + }) + ), + averageActualLogEntryRate: timestampDataSetBucket.filter_model_plot.average_actual.value, + dataSetId: timestampDataSetBucket.key.data_set, + }; + if ( + previousHistogramBucket && + previousHistogramBucket.startTime === timestampDataSetBucket.key.timestamp + ) { + return [ + ...histogramBuckets.slice(0, -1), + { + ...previousHistogramBucket, + dataSets: [...previousHistogramBucket.dataSets, dataSet], + }, + ]; + } else { + return [ + ...histogramBuckets, + { + dataSets: [dataSet], + startTime: timestampDataSetBucket.key.timestamp, + }, + ]; + } + }, []); + } +} diff --git a/x-pack/legacy/plugins/canvas/tasks/mocks/noop.js b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/index.ts old mode 100755 new mode 100644 similarity index 87% rename from x-pack/legacy/plugins/canvas/tasks/mocks/noop.js rename to x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/index.ts index 8d6abb810be9b..1749421277719 --- a/x-pack/legacy/plugins/canvas/tasks/mocks/noop.js +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export default function() {} +export * from './log_entry_rate'; diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_rate.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_rate.ts new file mode 100644 index 0000000000000..b10b1fe04db24 --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_rate.ts @@ -0,0 +1,170 @@ +/* + * 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 * as rt from 'io-ts'; + +const ML_ANOMALY_INDEX_PREFIX = '.ml-anomalies-'; + +export const createLogEntryRateQuery = ( + logRateJobId: string, + startTime: number, + endTime: number, + bucketDuration: number, + size: number, + afterKey?: CompositeTimestampDataSetKey +) => ({ + allowNoIndices: true, + body: { + query: { + bool: { + filter: [ + { + range: { + timestamp: { + gte: startTime, + lt: endTime, + }, + }, + }, + { + terms: { + result_type: ['model_plot', 'record'], + }, + }, + { + term: { + detector_index: { + value: 0, + }, + }, + }, + ], + }, + }, + aggs: { + timestamp_data_set_buckets: { + composite: { + after: afterKey, + size, + sources: [ + { + timestamp: { + date_histogram: { + field: 'timestamp', + fixed_interval: `${bucketDuration}ms`, + order: 'asc', + }, + }, + }, + { + data_set: { + terms: { + field: 'partition_field_value', + order: 'asc', + }, + }, + }, + ], + }, + aggs: { + filter_model_plot: { + filter: { + term: { + result_type: 'model_plot', + }, + }, + aggs: { + average_actual: { + avg: { + field: 'actual', + }, + }, + }, + }, + filter_records: { + filter: { + term: { + result_type: 'record', + }, + }, + aggs: { + top_hits_record: { + top_hits: { + _source: Object.keys(logRateMlRecordRT.props), + size: 100, + sort: [ + { + timestamp: 'asc', + }, + ], + }, + }, + }, + }, + }, + }, + }, + }, + ignoreUnavailable: true, + index: `${ML_ANOMALY_INDEX_PREFIX}${logRateJobId}`, + size: 0, + trackScores: false, + trackTotalHits: false, +}); + +const logRateMlRecordRT = rt.type({ + actual: rt.array(rt.number), + bucket_span: rt.number, + record_score: rt.number, + timestamp: rt.number, + typical: rt.array(rt.number), +}); + +const metricAggregationRT = rt.type({ + value: rt.number, +}); + +const compositeTimestampDataSetKeyRT = rt.type({ + data_set: rt.string, + timestamp: rt.number, +}); + +export type CompositeTimestampDataSetKey = rt.TypeOf; + +export const logRateModelPlotBucketRT = rt.type({ + key: compositeTimestampDataSetKeyRT, + filter_records: rt.type({ + doc_count: rt.number, + top_hits_record: rt.type({ + hits: rt.type({ + hits: rt.array( + rt.type({ + _source: logRateMlRecordRT, + }) + ), + }), + }), + }), + filter_model_plot: rt.type({ + doc_count: rt.number, + average_actual: metricAggregationRT, + }), +}); + +export type LogRateModelPlotBucket = rt.TypeOf; + +export const logRateModelPlotResponseRT = rt.type({ + aggregations: rt.type({ + timestamp_data_set_buckets: rt.intersection([ + rt.type({ + buckets: rt.array(logRateModelPlotBucketRT), + }), + rt.partial({ + after_key: compositeTimestampDataSetKeyRT, + }), + ]), + }), +}); diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js deleted file mode 100644 index 8524b1c890f5f..0000000000000 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js +++ /dev/null @@ -1,103 +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 expect from '@kbn/expect'; -import sinon from 'sinon'; -import fetchMock from 'fetch-mock'; -import { getSuggestionsProvider } from '../value'; -import indexPatternResponse from '../__fixtures__/index_pattern_response.json'; - -describe('Kuery value suggestions', function () { - let config; - let indexPatterns; - let getSuggestions; - - const mockValues = ['foo', 'bar']; - const fetchUrlMatcher = /\/api\/kibana\/suggestions\/values\/*/; - - beforeEach(() => fetchMock.post(fetchUrlMatcher, mockValues)); - afterEach(() => fetchMock.restore()); - - beforeEach(() => { - config = getConfigStub(true); - indexPatterns = [indexPatternResponse]; - getSuggestions = getSuggestionsProvider({ config, indexPatterns }); - }); - - it('should return a function', function () { - expect(typeof getSuggestions).to.be('function'); - }); - - it('should return boolean suggestions for boolean fields', async () => { - const fieldName = 'ssl'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.map(({ text }) => text)).to.eql(['true ', 'false ']); - }); - - it('should filter boolean suggestions for boolean fields', async () => { - const fieldName = 'ssl'; - const prefix = 'fa'; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.map(({ text }) => text)).to.eql(['false ']); - }); - - it('should not make a request for non-aggregatable fields', async () => { - const fieldName = 'non-sortable'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(fetchMock.called(fetchUrlMatcher)).to.be(false); - expect(suggestions).to.eql([]); - }); - - it('should not make a request for non-string fields', async () => { - const fieldName = 'bytes'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(fetchMock.called(fetchUrlMatcher)).to.be(false); - expect(suggestions).to.eql([]); - }); - - it('should make a request for string fields', async () => { - const fieldName = 'machine.os.raw'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - - const lastCall = fetchMock.lastCall(fetchUrlMatcher, 'POST'); - - expect(lastCall.request._bodyInit, '{"query":"","field":"machine.os.raw","boolFilter":[]}'); - expect(lastCall[0]).to.match(/\/api\/kibana\/suggestions\/values\/logstash-\*/); - expect(lastCall[1]).to.eql({ - method: 'POST', - headers: { - 'content-type': 'application/json', - 'kbn-version': '1.2.3', - }, - }); - expect(suggestions.map(({ text }) => text)).to.eql(['"foo" ', '"bar" ']); - }); - - it('should not have descriptions', async () => { - const fieldName = 'ssl'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.length).to.be.greaterThan(0); - suggestions.forEach(suggestion => { - expect(suggestion.description).to.not.be.ok(); - }); - }); -}); - -function getConfigStub(suggestValues) { - const get = sinon.stub().returns(suggestValues); - return { get }; -} diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js index 36fb77a30acd0..66e62e884e9b3 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js @@ -6,7 +6,7 @@ import { flatten } from 'lodash'; import { escapeQuotes } from './escape_kuery'; -import { getSuggestions } from 'ui/value_suggestions'; +import { npStart } from 'ui/new_platform'; const type = 'value'; @@ -29,6 +29,7 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { }) { const fields = allFields.filter(field => field.name === fieldName); const query = `${prefix}${suffix}`; + const { getSuggestions } = npStart.plugins.data; const suggestionsByField = fields.map(field => { return getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js new file mode 100644 index 0000000000000..c59917ebdc3bf --- /dev/null +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getSuggestionsProvider } from './value'; +import indexPatternResponse from './__fixtures__/index_pattern_response.json'; + +import { npStart } from 'ui/new_platform'; + +jest.mock('ui/new_platform', () => ({ + npStart: { + plugins: { + data: { + getSuggestions: (_, field) => { + let res; + if (field.type === 'boolean') { + res = [true, false]; + } else if (field.name === 'machine.os') { + res = ['Windo"ws', 'Mac\'', 'Linux']; + } else { + res = []; + } + return Promise.resolve(res); + } + }, + } + } +})); + + +describe('Kuery value suggestions', function () { + let indexPatterns; + let getSuggestions; + + beforeEach(() => { + indexPatterns = [indexPatternResponse]; + getSuggestions = getSuggestionsProvider({ indexPatterns }); + jest.clearAllMocks(); + }); + + test('should return a function', function () { + expect(typeof getSuggestions).toBe('function'); + }); + + test('should not search for non existing field', async () => { + const fieldName = 'i_dont_exist'; + const prefix = ''; + const suffix = ''; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.map(({ text }) => text)).toEqual([]); + expect(spy).toHaveBeenCalledTimes(0); + }); + + + test('should format suggestions', async () => { + const fieldName = 'ssl'; // Has results with quotes in mock + const prefix = ''; + const suffix = ''; + const start = 1; + const end = 5; + const suggestions = await getSuggestions({ fieldName, prefix, suffix, start, end }); + expect(suggestions[0].type).toEqual('value'); + expect(suggestions[0].start).toEqual(start); + expect(suggestions[0].end).toEqual(end); + }); + + describe('Boolean suggestions', function () { + test('should stringify boolean fields', async () => { + const fieldName = 'ssl'; + const prefix = ''; + const suffix = ''; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.map(({ text }) => text)).toEqual(['true ', 'false ']); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test('should filter out boolean suggestions', async () => { + const fieldName = 'ssl'; // Has results with quotes in mock + const prefix = 'fa'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(1); + }); + + }); + + + describe('String suggestions', function () { + test('should merge prefix and suffix', async () => { + const fieldName = 'machine.os.raw'; + const prefix = 'he'; + const suffix = 'llo'; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + await getSuggestions({ fieldName, prefix, suffix }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toBeCalledWith(expect.any(String), expect.any(Object), prefix + suffix, undefined); + }); + + test('should escape quotes in suggestions', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = ''; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions[0].text).toEqual('"Windo\\"ws" '); + expect(suggestions[1].text).toEqual('"Mac\'" '); + expect(suggestions[2].text).toEqual('"Linux" '); + }); + + test('should filter out string suggestions', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = 'banana'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(0); + }); + + test('should partially filter out string suggestions - case insensitive', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = 'ma'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(1); + }); + }); + + +}); diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 103697ef9148a..9c4b0fa737428 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -13,6 +13,10 @@ import { EditorFrameInstance } from '../types'; import { Storage } from 'ui/storage'; import { Document, SavedObjectStore } from '../persistence'; import { mount } from 'enzyme'; + +import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; +const dataStartMock = dataPluginMock.createStartContract(); + import { TopNavMenu, TopNavMenuData, @@ -68,8 +72,9 @@ describe('Lens App', () => { function makeDefaultArgs(): jest.Mocked<{ editorFrame: EditorFrameInstance; + data: typeof dataStartMock; core: typeof core; - data: DataStart; + dataShim: DataStart; store: Storage; docId?: string; docStorage: SavedObjectStore; @@ -87,7 +92,7 @@ describe('Lens App', () => { }, }, }, - data: { + dataShim: { indexPatterns: { indexPatterns: { get: jest.fn(id => { @@ -110,8 +115,9 @@ describe('Lens App', () => { redirectTo: jest.fn(id => {}), } as unknown) as jest.Mocked<{ editorFrame: EditorFrameInstance; + data: typeof dataStartMock; core: typeof core; - data: DataStart; + dataShim: DataStart; store: Storage; docId?: string; docStorage: SavedObjectStore; @@ -224,7 +230,7 @@ describe('Lens App', () => { await waitForPromises(); expect(args.docStorage.load).toHaveBeenCalledWith('1234'); - expect(args.data.indexPatterns.indexPatterns.get).toHaveBeenCalledWith('1'); + expect(args.dataShim.indexPatterns.indexPatterns.get).toHaveBeenCalledWith('1'); expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', @@ -492,7 +498,7 @@ describe('Lens App', () => { const instance = mount(); - args.data.filter.filterManager.setFilters([ + args.dataShim.filter.filterManager.setFilters([ buildExistsFilter({ name: 'myfield' }, { id: 'index1' }), ]); @@ -623,7 +629,7 @@ describe('Lens App', () => { query: { query: 'new', language: 'lucene' }, }); - args.data.filter.filterManager.setFilters([ + args.dataShim.filter.filterManager.setFilters([ buildExistsFilter({ name: 'myfield' }, { id: 'index1' }), ]); instance.update(); diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index 3ee901d201aa5..4746b1cac3ecd 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -9,6 +9,8 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { Storage } from 'ui/storage'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; + import { CoreStart, NotificationsStart } from 'src/core/public'; import { DataStart, @@ -43,6 +45,7 @@ interface State { export function App({ editorFrame, data, + dataShim, core, store, docId, @@ -50,8 +53,9 @@ export function App({ redirectTo, }: { editorFrame: EditorFrameInstance; + data: DataPublicPluginStart; core: CoreStart; - data: DataStart; + dataShim: DataStart; store: Storage; docId?: string; docStorage: SavedObjectStore; @@ -77,9 +81,9 @@ export function App({ const lastKnownDocRef = useRef(undefined); useEffect(() => { - const subscription = data.filter.filterManager.getUpdates$().subscribe({ + const subscription = dataShim.filter.filterManager.getUpdates$().subscribe({ next: () => { - setState(s => ({ ...s, filters: data.filter.filterManager.getFilters() })); + setState(s => ({ ...s, filters: dataShim.filter.filterManager.getFilters() })); }, }); return () => { @@ -112,7 +116,7 @@ export function App({ .then(doc => { getAllIndexPatterns( doc.state.datasourceMetaData.filterableIndexPatterns, - data.indexPatterns.indexPatterns, + dataShim.indexPatterns.indexPatterns, core.notifications ) .then(indexPatterns => { @@ -164,6 +168,7 @@ export function App({ ({ ...s, savedQuery })); }} onSavedQueryUpdated={savedQuery => { - data.filter.filterManager.setFilters( + dataShim.filter.filterManager.setFilters( savedQuery.attributes.filters || state.filters ); setState(s => ({ @@ -245,7 +250,7 @@ export function App({ })); }} onClearSavedQuery={() => { - data.filter.filterManager.removeAll(); + dataShim.filter.filterManager.removeAll(); setState(s => ({ ...s, savedQuery: undefined, @@ -290,7 +295,7 @@ export function App({ ) { getAllIndexPatterns( filterableIndexPatterns, - data.indexPatterns.indexPatterns, + dataShim.indexPatterns.indexPatterns, core.notifications ).then(indexPatterns => { if (indexPatterns) { diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx index 3b3b12533d74b..2668946fec47b 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx @@ -11,8 +11,9 @@ import chrome from 'ui/chrome'; import { Storage } from 'ui/storage'; import { CoreSetup, CoreStart } from 'src/core/public'; import { npSetup, npStart } from 'ui/new_platform'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { DataStart } from '../../../../../../src/legacy/core_plugins/data/public'; -import { start as dataStart } from '../../../../../../src/legacy/core_plugins/data/public/legacy'; +import { start as dataShimStart } from '../../../../../../src/legacy/core_plugins/data/public/legacy'; import { editorFrameSetup, editorFrameStart, editorFrameStop } from '../editor_frame_plugin'; import { indexPatternDatasourceSetup, indexPatternDatasourceStop } from '../indexpattern_plugin'; import { SavedObjectIndexStore } from '../persistence'; @@ -26,7 +27,8 @@ import { App } from './app'; import { EditorFrameInstance } from '../types'; export interface LensPluginStartDependencies { - data: DataStart; + data: DataPublicPluginStart; + dataShim: DataStart; } export class AppPlugin { private instance: EditorFrameInstance | null = null; @@ -50,7 +52,7 @@ export class AppPlugin { editorFrameSetupInterface.registerDatasource('indexpattern', indexPattern); } - start(core: CoreStart, { data }: LensPluginStartDependencies) { + start(core: CoreStart, { data, dataShim }: LensPluginStartDependencies) { if (this.store === null) { throw new Error('Start lifecycle called before setup lifecycle'); } @@ -66,6 +68,7 @@ export class AppPlugin { app.setup(npSetup.core, {}); -export const appStart = () => app.start(npStart.core, { data: dataStart }); +export const appStart = () => + app.start(npStart.core, { dataShim: dataShimStart, data: npStart.plugins.data }); export const appStop = () => app.stop(); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__snapshots__/lens_field_icon.test.tsx.snap b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__snapshots__/lens_field_icon.test.tsx.snap new file mode 100644 index 0000000000000..5593a1af00d70 --- /dev/null +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__snapshots__/lens_field_icon.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LensFieldIcon renders properly 1`] = ` + +`; diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.tsx index 11d6228251025..fbe71381fd449 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.tsx @@ -30,7 +30,7 @@ import { DatasourceDataPanelProps, DataType } from '../types'; import { IndexPatternPrivateState, IndexPatternField, IndexPattern } from './indexpattern'; import { ChildDragDropProvider, DragContextState } from '../drag_drop'; import { FieldItem } from './field_item'; -import { FieldIcon } from './field_icon'; +import { LensFieldIcon } from './lens_field_icon'; import { updateLayerIndexPattern } from './state_helpers'; import { ChangeIndexPattern } from './change_indexpattern'; @@ -442,7 +442,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ })) } > - {fieldTypeNames[type]} + {fieldTypeNames[type]} ))} /> diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/field_select.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/field_select.tsx index 0cd7329b4613d..d76e882f11cf5 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/field_select.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/dimension_panel/field_select.tsx @@ -14,7 +14,7 @@ import { EuiHighlight, } from '@elastic/eui'; import { OperationType, IndexPattern, IndexPatternField } from '../indexpattern'; -import { FieldIcon } from '../field_icon'; +import { LensFieldIcon } from '../lens_field_icon'; import { DataType } from '../../types'; import { OperationFieldSupportMatrix } from './dimension_panel'; @@ -172,7 +172,9 @@ export function FieldSelect({ return ( - + {option.label} diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/field_item.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/field_item.tsx index 804ea478e57f1..9cfe2893155ca 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/field_item.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/field_item.tsx @@ -41,9 +41,9 @@ import { Query } from 'src/plugins/data/common'; import { fieldFormats } from '../../../../../../src/legacy/ui/public/registry/field_formats'; import { IndexPattern, IndexPatternField, DraggedField } from './indexpattern'; import { DragDrop } from '../drag_drop'; -import { FieldIcon, getColorForDataType } from './field_icon'; import { DatasourceDataPanelProps, DataType } from '../types'; import { BucketedAggregation, FieldStatsResponse } from '../../common'; +import { LensFieldIcon, getColorForDataType } from './lens_field_icon'; export interface FieldItemProps { core: DatasourceDataPanelProps['core']; @@ -177,7 +177,7 @@ export function FieldItem(props: FieldItemProps) { values: { fieldName: field.name }, })} > - + {wrappableHighlightableFieldName} @@ -362,11 +362,11 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { defaultMessage: 'Count', }) ); - const expectedColor = getColorForDataType(field.type); const colors: DataSeriesColorsValues = { colorValues: [], specId, }; + const expectedColor = getColorForDataType(field.type); const seriesColors = new Map([[colors, expectedColor]]); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.test.tsx new file mode 100644 index 0000000000000..7441083550706 --- /dev/null +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.test.tsx @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { shallow } from 'enzyme'; +import { LensFieldIcon, getColorForDataType } from './lens_field_icon'; + +test('LensFieldIcon renders properly', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); +}); + +test('LensFieldIcon getColorForDataType for a valid type', () => { + const color = getColorForDataType('date'); + expect(color).toEqual('#B0916F'); +}); + +test('LensFieldIcon getColorForDataType for an invalid type', () => { + const color = getColorForDataType('invalid'); + expect(color).toEqual('#1EA593'); +}); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.tsx new file mode 100644 index 0000000000000..1773022bf6e1a --- /dev/null +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/lens_field_icon.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { palettes } from '@elastic/eui'; +import { FieldIcon, typeToEuiIconMap } from '../../../../../../src/plugins/kibana_react/public'; +import { DataType } from '../types'; + +export function getColorForDataType(type: string) { + const iconMap = typeToEuiIconMap[type]; + if (iconMap) { + return iconMap.color; + } + return palettes.euiPaletteColorBlind.colors[0]; +} + +export function LensFieldIcon({ type }: { type: DataType }) { + return ; +} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap index 4c9ef61478ab4..c3d4ff673e3d5 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap @@ -5,7 +5,7 @@ exports[`LayerPanel is rendered 1`] = ` services={ Object { "appName": "maps", - "autocomplete": undefined, + "data": undefined, "store": Storage { "clear": [Function], "get": [Function], diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js index 9efbfe45da29c..28afabc40bd75 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js @@ -155,7 +155,7 @@ export class LayerPanel extends React.Component { services={{ appName: 'maps', store: localStorage, - autocomplete: npStart.plugins.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/x-pack/legacy/plugins/reporting/server/browsers/browsers.js b/x-pack/legacy/plugins/reporting/server/browsers/browsers.ts similarity index 85% rename from x-pack/legacy/plugins/reporting/server/browsers/browsers.js rename to x-pack/legacy/plugins/reporting/server/browsers/browsers.ts index 75f06de9a2a45..ff9dece504ea6 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/browsers.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/browsers.ts @@ -6,6 +6,8 @@ import * as chromium from './chromium'; +export type BrowserType = keyof typeof BROWSERS_BY_TYPE; + export const BROWSERS_BY_TYPE = { chromium, }; diff --git a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts index ada20914eccb5..cf3e2fe25b4d6 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore -import { BROWSERS_BY_TYPE } from './browsers'; -// @ts-ignore +import { BROWSERS_BY_TYPE, BrowserType } from './browsers'; import { ensureBrowserDownloaded } from './download'; import { installBrowser } from './install'; import { LevelLogger } from '../lib/level_logger'; @@ -22,7 +20,7 @@ export async function createBrowserDriverFactory( const DATA_DIR = config.get('path.data'); const CAPTURE_CONFIG = config.get('xpack.reporting.capture'); - const BROWSER_TYPE = CAPTURE_CONFIG.browser.type; + const BROWSER_TYPE: BrowserType = CAPTURE_CONFIG.browser.type; const BROWSER_AUTO_DOWNLOAD = CAPTURE_CONFIG.browser.autoDownload; const BROWSER_CONFIG = CAPTURE_CONFIG.browser[BROWSER_TYPE]; const REPORTING_TIMEOUT = config.get('xpack.reporting.queue.timeout'); diff --git a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.js b/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts similarity index 94% rename from x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.js rename to x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts index 952d6a99c4e4b..a21a4b33722ff 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts @@ -9,7 +9,7 @@ import { promisify } from 'util'; const getos = promisify(getosSync); -const distroSupportsUnprivilegedUsernamespaces = (distro) => { +const distroSupportsUnprivilegedUsernamespaces = (distro: string) => { // Debian 7 and 8 don't support usernamespaces by default // this should be reevaluated when Debian 9 is available if (distro.toLowerCase() === 'debian') { diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/checksum.ts b/x-pack/legacy/plugins/reporting/server/browsers/download/checksum.ts index b5e50fcebd453..fd68a8e356e10 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/checksum.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/checksum.ts @@ -7,7 +7,6 @@ import { createHash } from 'crypto'; import { createReadStream } from 'fs'; -// @ts-ignore import { readableEnd } from './util'; export async function md5(path: string) { diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/clean.js b/x-pack/legacy/plugins/reporting/server/browsers/download/clean.ts similarity index 85% rename from x-pack/legacy/plugins/reporting/server/browsers/download/clean.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/clean.ts index ad487311e12df..394b76d772531 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/clean.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/clean.ts @@ -14,12 +14,9 @@ import { log, asyncMap } from './util'; /** * Delete any file in the `dir` that is not in the expectedPaths - * @param {String} dir - * @param {Array} expectedPaths - * @return {Promise} */ -export async function clean(dir, expectedPaths) { - let filenames; +export async function clean(dir: string, expectedPaths: string[]) { + let filenames: string[]; try { filenames = await readdirSync(dir); } catch (error) { diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/download.test.js b/x-pack/legacy/plugins/reporting/server/browsers/download/download.test.ts similarity index 55% rename from x-pack/legacy/plugins/reporting/server/browsers/download/download.test.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/download.test.ts index 61b505703a751..901fc6ccf9b22 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/download.test.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/download.test.ts @@ -7,6 +7,7 @@ import { createHash } from 'crypto'; import { resolve as resolvePath } from 'path'; import { readFileSync } from 'fs'; +import { Readable } from 'stream'; import del from 'del'; import { download } from './download'; @@ -14,41 +15,27 @@ import { download } from './download'; const TEMP_DIR = resolvePath(__dirname, '__tmp__'); const TEMP_FILE = resolvePath(TEMP_DIR, 'foo/bar/download'); -jest.mock('request', () => { - let resp = ''; - const sinon = require('sinon'); - const Readable = require('stream').Readable; - const request = sinon.spy(function () { - return new Readable({ - read() { - if (resp instanceof Error) { - this.emit('error', resp); - return; - } +class ReadableOf extends Readable { + constructor(private readonly responseBody: string) { + super(); + } - this.push(resp.shift()); + _read() { + this.push(this.responseBody); + this.push(null); + } +} - if (resp.length === 0) { - this.push(null); - } - } - }); - }); - - request._setResponse = (chunks) => { - if (typeof chunks === 'string') { - chunks = chunks.split(''); - } - - resp = chunks; - }; - - return request; -}); +jest.mock('axios'); +const request: jest.Mock = jest.requireMock('axios').request; test('downloads the url to the path', async () => { const BODY = 'abdcefg'; - require('request')._setResponse(BODY); + request.mockImplementationOnce(async () => { + return { + data: new ReadableOf(BODY), + }; + }); await download('url', TEMP_FILE); expect(readFileSync(TEMP_FILE, 'utf8')).toEqual(BODY); @@ -56,18 +43,25 @@ test('downloads the url to the path', async () => { test('returns the md5 hex hash of the http body', async () => { const BODY = 'foobar'; - const HASH = createHash('md5').update(BODY).digest('hex'); - require('request')._setResponse(BODY); + const HASH = createHash('md5') + .update(BODY) + .digest('hex'); + request.mockImplementationOnce(async () => { + return { + data: new ReadableOf(BODY), + }; + }); const returned = await download('url', TEMP_FILE); expect(returned).toEqual(HASH); }); test('throws if request emits an error', async () => { - require('request')._setResponse(new Error('foo')); + request.mockImplementationOnce(async () => { + throw new Error('foo'); + }); + return expect(download('url', TEMP_FILE)).rejects.toThrow('foo'); }); -afterEach(async () => ( - await del(TEMP_DIR) -)); +afterEach(async () => await del(TEMP_DIR)); diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/download.js b/x-pack/legacy/plugins/reporting/server/browsers/download/download.ts similarity index 68% rename from x-pack/legacy/plugins/reporting/server/browsers/download/download.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/download.ts index f8436f5ce7af7..a5ad69b46e46d 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/download.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/download.ts @@ -8,9 +8,9 @@ import { openSync, writeSync, closeSync, mkdirSync } from 'fs'; import { createHash } from 'crypto'; import { dirname } from 'path'; -import request from 'request'; +import Axios from 'axios'; -import { log, readableEnd } from './util'; +import { log } from './util'; /** * Download a url and calculate it's checksum @@ -18,7 +18,7 @@ import { log, readableEnd } from './util'; * @param {String} path * @return {Promise} checksum of the downloaded file */ -export async function download(url, path) { +export async function download(url: string, path: string) { log(`Downloading ${url}`); const hash = createHash('md5'); @@ -27,11 +27,20 @@ export async function download(url, path) { const handle = openSync(path, 'w'); try { - const readable = request(url).on('data', chunk => { + const resp = await Axios.request({ + url, + method: 'GET', + responseType: 'stream', + }); + + resp.data.on('data', (chunk: Buffer) => { writeSync(handle, chunk); hash.update(chunk); }); - await readableEnd(readable); + + await new Promise((resolve, reject) => { + resp.data.on('error', reject).on('end', resolve); + }); } finally { closeSync(handle); } diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.js b/x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.ts similarity index 68% rename from x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.ts index 2a8052689e02d..d322566f9aa1d 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/ensure_downloaded.ts @@ -7,21 +7,20 @@ import { resolve as resolvePath } from 'path'; import { existsSync } from 'fs'; -import { BROWSERS_BY_TYPE } from '../browsers'; +import { BROWSERS_BY_TYPE, BrowserType } from '../browsers'; import { md5 } from './checksum'; import { asyncMap } from './util'; import { download } from './download'; import { clean } from './clean'; - /** * Check for the downloaded archive of each requested browser type and * download them if they are missing or their checksum is invalid * @param {String} browserType * @return {Promise} */ -export async function ensureBrowserDownloaded(browserType) { +export async function ensureBrowserDownloaded(browserType: BrowserType) { await ensureDownloaded([BROWSERS_BY_TYPE[browserType]]); } @@ -33,7 +32,6 @@ export async function ensureAllBrowsersDownloaded() { await ensureDownloaded(Object.values(BROWSERS_BY_TYPE)); } - /** * Clears the unexpected files in the browsers archivesPath * and ensures that all packages/archives are downloaded and @@ -41,20 +39,29 @@ export async function ensureAllBrowsersDownloaded() { * @param {BrowserSpec} browsers * @return {Promise} */ -async function ensureDownloaded(browsers) { - await asyncMap(Object.values(browsers), async (browser) => { +async function ensureDownloaded( + browsers: Array<{ + paths: { + archivesPath: string; + baseUrl: string; + packages: Array<{ archiveFilename: string; archiveChecksum: string }>; + }; + }> +) { + await asyncMap(browsers, async browser => { const { archivesPath } = browser.paths; - await clean(archivesPath, browser.paths.packages.map(p => ( - resolvePath(archivesPath, p.archiveFilename) - ))); + await clean( + archivesPath, + browser.paths.packages.map(p => resolvePath(archivesPath, p.archiveFilename)) + ); - const invalidChecksums = []; + const invalidChecksums: string[] = []; await asyncMap(browser.paths.packages, async ({ archiveFilename, archiveChecksum }) => { const url = `${browser.paths.baseUrl}${archiveFilename}`; const path = resolvePath(archivesPath, archiveFilename); - if (existsSync(path) && await md5(path) === archiveChecksum) { + if (existsSync(path) && (await md5(path)) === archiveChecksum) { return; } @@ -65,7 +72,11 @@ async function ensureDownloaded(browsers) { }); if (invalidChecksums.length) { - throw new Error(`Error downloading browsers, checksums incorrect for:\n - ${invalidChecksums.join('\n - ')}`); + throw new Error( + `Error downloading browsers, checksums incorrect for:\n - ${invalidChecksums.join( + '\n - ' + )}` + ); } }); } diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/index.js b/x-pack/legacy/plugins/reporting/server/browsers/download/index.js deleted file mode 100644 index 9fbfa918e769d..0000000000000 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/index.js +++ /dev/null @@ -1,10 +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 { - ensureBrowserDownloaded, - ensureAllBrowsersDownloaded, -} from './ensure_downloaded'; diff --git a/x-pack/tasks/helpers/get_flags.js b/x-pack/legacy/plugins/reporting/server/browsers/download/index.ts similarity index 72% rename from x-pack/tasks/helpers/get_flags.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/index.ts index 397330daf4bda..bf7ed450b462f 100644 --- a/x-pack/tasks/helpers/get_flags.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export default function getFlags() { - return process.argv.slice(3); -} +export { ensureBrowserDownloaded, ensureAllBrowsersDownloaded } from './ensure_downloaded'; diff --git a/x-pack/legacy/plugins/reporting/server/browsers/download/util.js b/x-pack/legacy/plugins/reporting/server/browsers/download/util.ts similarity index 65% rename from x-pack/legacy/plugins/reporting/server/browsers/download/util.js rename to x-pack/legacy/plugins/reporting/server/browsers/download/util.ts index f9cc905e01264..679106742e3d0 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/download/util.js +++ b/x-pack/legacy/plugins/reporting/server/browsers/download/util.ts @@ -4,33 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Readable } from 'stream'; + /** * Log a message if the DEBUG environment variable is set - * @param {...any} args - * @return {undefined} */ -export function log(...args) { +export function log(...args: any[]) { if (process.env.DEBUG) { + // allow console log since this is off by default and only for debugging + // eslint-disable-next-line no-console console.log(...args); } } /** * Iterate an array asynchronously and in parallel - * @param {Array} array - * @param {Function} asyncFn - * @return {Promise} */ -export function asyncMap(array, asyncFn) { +export function asyncMap(array: T[], asyncFn: (x: T) => T2): Promise { return Promise.all(array.map(asyncFn)); } /** * Wait for a readable stream to end - * @param {Stream.Readable} stream - * @return {Promise} */ -export function readableEnd(stream) { +export function readableEnd(stream: Readable) { return new Promise((resolve, reject) => { stream.on('error', reject).on('end', resolve); }); diff --git a/x-pack/legacy/plugins/reporting/server/browsers/index.js b/x-pack/legacy/plugins/reporting/server/browsers/index.ts similarity index 100% rename from x-pack/legacy/plugins/reporting/server/browsers/index.js rename to x-pack/legacy/plugins/reporting/server/browsers/index.ts diff --git a/x-pack/legacy/plugins/task_manager/README.md b/x-pack/legacy/plugins/task_manager/README.md index adf7706443695..63c92102af251 100644 --- a/x-pack/legacy/plugins/task_manager/README.md +++ b/x-pack/legacy/plugins/task_manager/README.md @@ -171,9 +171,14 @@ The data stored for a task instance looks something like this: // This is incremented if a task fails or times out. attempts: 0, - // Currently, this is either idle | running. It is used to + // Currently, this is either idle | claiming | running | failed. It is used to // coordinate which Kibana instance owns / is running a specific // task instance. + // idle: Task Instance isn't being worked on + // claiming: A Kibana instance has claimed ownership but hasn't started running + // the Task Instance yet + // running: A Kibana instance has began working on the Task Instance + // failed: The last run of the Task Instance failed, waiting to retry status: 'idle', // The params specific to this task instance, which will be @@ -207,6 +212,9 @@ The data stored for a task instance looks something like this: // An application-specific designation, allowing different Kibana // plugins / apps to query for only those tasks they care about. scope: ['alerting'], + + // The Kibana UUID of the Kibana instance who last claimed ownership for running this task. + ownerId: '123e4567-e89b-12d3-a456-426655440000' } ``` diff --git a/x-pack/legacy/plugins/task_manager/lib/middleware.test.ts b/x-pack/legacy/plugins/task_manager/lib/middleware.test.ts index ff840061285c4..07afee1797462 100644 --- a/x-pack/legacy/plugins/task_manager/lib/middleware.test.ts +++ b/x-pack/legacy/plugins/task_manager/lib/middleware.test.ts @@ -31,6 +31,7 @@ const getMockConcreteTaskInstance = () => { state: any; taskType: string; params: any; + ownerId: string | null; } = { id: 'hy8o99o83', sequenceNumber: 1, @@ -44,6 +45,7 @@ const getMockConcreteTaskInstance = () => { state: {}, taskType: 'nice_task', params: { abc: 'def' }, + ownerId: null, }; return concrete; }; @@ -92,19 +94,19 @@ describe('addMiddlewareToChain', () => { .beforeSave({ taskInstance: getMockTaskInstance() }) .then((saveOpts: any) => { expect(saveOpts).toMatchInlineSnapshot(` -Object { - "taskInstance": Object { - "params": Object { - "abc": "def", - "m1": true, - "m2": true, - "m3": true, - }, - "state": Object {}, - "taskType": "nice_task", - }, -} -`); + Object { + "taskInstance": Object { + "params": Object { + "abc": "def", + "m1": true, + "m2": true, + "m3": true, + }, + "state": Object {}, + "taskType": "nice_task", + }, + } + `); }); }); @@ -145,29 +147,30 @@ Object { .beforeRun(getMockRunContext(getMockConcreteTaskInstance())) .then(contextOpts => { expect(contextOpts).toMatchInlineSnapshot(` -Object { - "kbnServer": Object {}, - "m1": true, - "m2": true, - "m3": true, - "taskInstance": Object { - "attempts": 0, - "id": "hy8o99o83", - "params": Object { - "abc": "def", - }, - "primaryTerm": 1, - "retryAt": null, - "runAt": 2018-09-18T05:33:09.588Z, - "scheduledAt": 2018-09-18T05:33:09.588Z, - "sequenceNumber": 1, - "startedAt": null, - "state": Object {}, - "status": "idle", - "taskType": "nice_task", - }, -} -`); + Object { + "kbnServer": Object {}, + "m1": true, + "m2": true, + "m3": true, + "taskInstance": Object { + "attempts": 0, + "id": "hy8o99o83", + "ownerId": null, + "params": Object { + "abc": "def", + }, + "primaryTerm": 1, + "retryAt": null, + "runAt": 2018-09-18T05:33:09.588Z, + "scheduledAt": 2018-09-18T05:33:09.588Z, + "sequenceNumber": 1, + "startedAt": null, + "state": Object {}, + "status": "idle", + "taskType": "nice_task", + }, + } + `); }); }); }); diff --git a/x-pack/legacy/plugins/task_manager/mappings.json b/x-pack/legacy/plugins/task_manager/mappings.json index 6638a75d82546..96653a4de1b31 100644 --- a/x-pack/legacy/plugins/task_manager/mappings.json +++ b/x-pack/legacy/plugins/task_manager/mappings.json @@ -36,6 +36,9 @@ }, "scope": { "type": "keyword" + }, + "ownerId": { + "type": "keyword" } } } diff --git a/x-pack/legacy/plugins/task_manager/task.ts b/x-pack/legacy/plugins/task_manager/task.ts index 5c85f692fd614..dd74acc2636e9 100644 --- a/x-pack/legacy/plugins/task_manager/task.ts +++ b/x-pack/legacy/plugins/task_manager/task.ts @@ -136,7 +136,7 @@ export interface TaskDictionary { [taskType: string]: T; } -export type TaskStatus = 'idle' | 'running' | 'failed'; +export type TaskStatus = 'idle' | 'claiming' | 'running' | 'failed'; /* * A task instance represents all of the data required to store, fetch, @@ -209,6 +209,11 @@ export interface TaskInstance { * and then query such tasks to provide a glimpse at only reporting tasks, rather than at all tasks. */ scope?: string[]; + + /** + * The random uuid of the Kibana instance which claimed ownership of the task last + */ + ownerId?: string | null; } /** @@ -268,4 +273,9 @@ export interface ConcreteTaskInstance extends TaskInstance { * any state, this will be the empy object: {} */ state: Record; + + /** + * The random uuid of the Kibana instance which claimed ownership of the task last + */ + ownerId: string | null; } diff --git a/x-pack/legacy/plugins/task_manager/task_manager.ts b/x-pack/legacy/plugins/task_manager/task_manager.ts index 01ddd1efbe762..7d2794fa33bcc 100644 --- a/x-pack/legacy/plugins/task_manager/task_manager.ts +++ b/x-pack/legacy/plugins/task_manager/task_manager.ts @@ -4,11 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import uuid from 'uuid'; import { SavedObjectsClientContract, SavedObjectsSerializer } from 'src/core/server'; import { Logger } from './types'; import { fillPool } from './lib/fill_pool'; import { addMiddlewareToChain, BeforeSaveMiddlewareParams, Middleware } from './lib/middleware'; import { sanitizeTaskDefinitions } from './lib/sanitize_task_definitions'; +import { intervalFromNow } from './lib/intervals'; import { TaskDefinition, TaskDictionary, @@ -29,6 +31,12 @@ export interface TaskManagerOpts { serializer: SavedObjectsSerializer; } +function generateTaskManagerUUID(logger: Logger): string { + const taskManagerUUID = uuid.v4(); + logger.info(`Initialising Task Manager with UUID: ${taskManagerUUID}`); + return taskManagerUUID; +} + /* * The TaskManager is the public interface into the task manager system. This glues together * all of the disparate modules in one integration point. The task manager operates in two different ways: @@ -77,7 +85,9 @@ export class TaskManager { index: opts.config.get('xpack.task_manager.index'), maxAttempts: opts.config.get('xpack.task_manager.max_attempts'), definitions: this.definitions, + taskManagerId: generateTaskManagerUUID(this.logger), }); + const pool = new TaskPool({ logger: this.logger, maxWorkers: this.maxWorkers, @@ -93,9 +103,7 @@ export class TaskManager { const poller = new TaskPoller({ logger: this.logger, pollInterval: opts.config.get('xpack.task_manager.poll_interval'), - work(): Promise { - return fillPool(pool.run, store.fetchAvailableTasks, createRunner); - }, + work: (): Promise => fillPool(pool.run, () => this.claimAvailableTasks(), createRunner), }); this.pool = pool; @@ -127,6 +135,20 @@ export class TaskManager { startPoller(); } + private async claimAvailableTasks() { + const { docs, claimedTasks } = await this.store.claimAvailableTasks({ + size: this.pool.availableWorkers, + claimOwnershipUntil: intervalFromNow('30s')!, + }); + + if (docs.length !== claimedTasks) { + this.logger.warn( + `[Task Ownership error]: (${claimedTasks}) tasks were claimed by Kibana, but (${docs.length}) tasks were fetched` + ); + } + return docs; + } + private async waitUntilStarted() { if (!this.isStarted) { await new Promise(resolve => { diff --git a/x-pack/legacy/plugins/task_manager/task_pool.test.ts b/x-pack/legacy/plugins/task_manager/task_pool.test.ts index 795d1099f3c6f..e6a83dd1911bd 100644 --- a/x-pack/legacy/plugins/task_manager/task_pool.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_pool.test.ts @@ -195,7 +195,7 @@ describe('TaskPool', () => { return { isExpired: false, cancel: async () => undefined, - claimOwnership: async () => true, + markTaskAsRunning: async () => true, run: mockRun(), }; } diff --git a/x-pack/legacy/plugins/task_manager/task_pool.ts b/x-pack/legacy/plugins/task_manager/task_pool.ts index 42a0e9ad436ad..7afbec65a0d8c 100644 --- a/x-pack/legacy/plugins/task_manager/task_pool.ts +++ b/x-pack/legacy/plugins/task_manager/task_pool.ts @@ -75,7 +75,7 @@ export class TaskPool { private async attemptToRun(tasks: TaskRunner[]) { for (const task of tasks) { if (this.availableWorkers > 0) { - if (await task.claimOwnership()) { + if (await task.markTaskAsRunning()) { this.running.add(task); task .run() @@ -83,6 +83,8 @@ export class TaskPool { this.logger.warn(`Task ${task} failed in attempt to run: ${err.message}`); }) .then(() => this.running.delete(task)); + } else { + this.logger.warn(`Failed to mark Task ${task} as running`); } } else { return false; diff --git a/x-pack/legacy/plugins/task_manager/task_runner.test.ts b/x-pack/legacy/plugins/task_manager/task_runner.test.ts index eaaa6717230a2..49c55279eafe7 100644 --- a/x-pack/legacy/plugins/task_manager/task_runner.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_runner.test.ts @@ -243,7 +243,7 @@ describe('TaskManagerRunner', () => { }, }); - await runner.claimOwnership(); + await runner.markTaskAsRunning(); sinon.assert.calledOnce(store.update); const instance = store.update.args[0][0]; @@ -409,7 +409,7 @@ describe('TaskManagerRunner', () => { }, }); - await runner.claimOwnership(); + await runner.markTaskAsRunning(); sinon.assert.calledOnce(store.update); sinon.assert.calledWith(getRetryStub, initialAttempts + 1); @@ -442,7 +442,7 @@ describe('TaskManagerRunner', () => { }, }); - await runner.claimOwnership(); + await runner.markTaskAsRunning(); sinon.assert.calledOnce(store.update); sinon.assert.calledWith(getRetryStub, initialAttempts + 1); @@ -477,7 +477,7 @@ describe('TaskManagerRunner', () => { }, }); - await runner.claimOwnership(); + await runner.markTaskAsRunning(); sinon.assert.calledOnce(store.update); sinon.assert.calledWith(getRetryStub, initialAttempts + 1); @@ -510,7 +510,7 @@ describe('TaskManagerRunner', () => { }, }); - await runner.claimOwnership(); + await runner.markTaskAsRunning(); sinon.assert.calledOnce(store.update); sinon.assert.notCalled(getRetryStub); @@ -619,6 +619,7 @@ describe('TaskManagerRunner', () => { state: {}, status: 'idle', user: 'example', + ownerId: null, }, opts.instance || {} ), diff --git a/x-pack/legacy/plugins/task_manager/task_runner.ts b/x-pack/legacy/plugins/task_manager/task_runner.ts index e97f361b2ca08..a51e0c885b978 100644 --- a/x-pack/legacy/plugins/task_manager/task_runner.ts +++ b/x-pack/legacy/plugins/task_manager/task_runner.ts @@ -30,7 +30,7 @@ const defaultBackoffPerFailure = 5 * 60 * 1000; export interface TaskRunner { isExpired: boolean; cancel: CancelFunction; - claimOwnership: () => Promise; + markTaskAsRunning: () => Promise; run: () => Promise; toString?: () => string; } @@ -152,12 +152,25 @@ export class TaskManagerRunner implements TaskRunner { * * @returns {Promise} */ - public async claimOwnership(): Promise { + public async markTaskAsRunning(): Promise { const VERSION_CONFLICT_STATUS = 409; const attempts = this.instance.attempts + 1; const now = new Date(); + const ownershipClaimedUntil = this.instance.retryAt; + try { + const { id } = this.instance; + + const timeUntilClaimExpires = howManyMsUntilOwnershipClaimExpires(ownershipClaimedUntil); + if (timeUntilClaimExpires < 0) { + this.logger.debug( + `[Task Runner] Task ${id} started after ownership expired (${Math.abs( + timeUntilClaimExpires + )}ms after expiry)` + ); + } + this.instance = await this.store.update({ ...this.instance, status: 'running', @@ -174,6 +187,17 @@ export class TaskManagerRunner implements TaskRunner { }), }); + const timeUntilClaimExpiresAfterUpdate = howManyMsUntilOwnershipClaimExpires( + ownershipClaimedUntil + ); + if (timeUntilClaimExpiresAfterUpdate < 0) { + this.logger.debug( + `[Task Runner] Task ${id} ran after ownership expired (${Math.abs( + timeUntilClaimExpiresAfterUpdate + )}ms after expiry)` + ); + } + return true; } catch (error) { if (error.statusCode !== VERSION_CONFLICT_STATUS) { @@ -246,6 +270,7 @@ export class TaskManagerRunner implements TaskRunner { status, startedAt: null, retryAt: null, + ownerId: null, attempts: result.error ? this.instance.attempts : 0, }); @@ -323,3 +348,7 @@ function sanitizeInstance(instance: ConcreteTaskInstance): ConcreteTaskInstance state: instance.state || {}, }; } + +function howManyMsUntilOwnershipClaimExpires(ownershipClaimedUntil: Date | null): number { + return ownershipClaimedUntil ? ownershipClaimedUntil.getTime() - Date.now() : 0; +} diff --git a/x-pack/legacy/plugins/task_manager/task_store.test.ts b/x-pack/legacy/plugins/task_manager/task_store.test.ts index c24ffe09d18e2..65b49820d6e6c 100644 --- a/x-pack/legacy/plugins/task_manager/task_store.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_store.test.ts @@ -6,8 +6,9 @@ import _ from 'lodash'; import sinon from 'sinon'; +import uuid from 'uuid'; import { TaskDictionary, TaskDefinition, TaskInstance, TaskStatus } from './task'; -import { FetchOpts, TaskStore } from './task_store'; +import { FetchOpts, StoreOpts, OwnershipClaimingOpts, TaskStore } from './task_store'; import { mockLogger } from './test_utils'; import { SavedObjectsClientMock } from 'src/core/server/mocks'; import { SavedObjectsSerializer, SavedObjectsSchema, SavedObjectAttributes } from 'src/core/server'; @@ -60,6 +61,7 @@ describe('TaskStore', () => { ); const store = new TaskStore({ index: 'tasky', + taskManagerId: '', serializer, callCluster, maxAttempts: 2, @@ -159,6 +161,7 @@ describe('TaskStore', () => { const callCluster = sinon.spy(async (name: string, params?: any) => ({ hits: { hits } })); const store = new TaskStore({ index: 'tasky', + taskManagerId: '', serializer, callCluster, maxAttempts: 2, @@ -350,6 +353,7 @@ describe('TaskStore', () => { const callCluster = sinon.spy(async (name: string, params?: any) => ({ hits: { hits: [] } })); const store = new TaskStore({ index: 'tasky', + taskManagerId: '', serializer, callCluster, definitions: taskDefinitions, @@ -549,6 +553,321 @@ describe('TaskStore', () => { }); }); + describe('claimAvailableTasks', () => { + async function testClaimAvailableTasks({ + opts = {}, + hits = generateFakeTasks(1), + claimingOpts, + }: { + opts: Partial; + hits?: any[]; + claimingOpts: OwnershipClaimingOpts; + }) { + const versionConflicts = 2; + const callCluster = sinon.spy(async (name: string, params?: any) => + name === 'updateByQuery' + ? { + total: hits.length + versionConflicts, + updated: hits.length, + version_conflicts: versionConflicts, + } + : { hits: { hits } } + ); + const store = new TaskStore({ + callCluster, + maxAttempts: 2, + definitions: taskDefinitions, + serializer, + savedObjectsRepository: savedObjectsClient, + taskManagerId: '', + index: '', + ...opts, + }); + + const result = await store.claimAvailableTasks(claimingOpts); + + sinon.assert.calledTwice(callCluster); + sinon.assert.calledWithMatch(callCluster, 'updateByQuery', { max_docs: claimingOpts.size }); + sinon.assert.calledWithMatch(callCluster, 'search', { body: { size: claimingOpts.size } }); + + return { + result, + args: Object.assign({}, ...callCluster.args.map(([name, args]) => ({ [name]: args }))), + }; + } + + test('it returns normally with no tasks when the index does not exist.', async () => { + const callCluster = sinon.spy(async (name: string, params?: any) => ({ + total: 0, + updated: 0, + })); + const store = new TaskStore({ + index: 'tasky', + taskManagerId: '', + serializer, + callCluster, + definitions: taskDefinitions, + maxAttempts: 2, + savedObjectsRepository: savedObjectsClient, + }); + const { docs } = await store.claimAvailableTasks({ + claimOwnershipUntil: new Date(), + size: 10, + }); + sinon.assert.calledOnce(callCluster); + sinon.assert.calledWithMatch(callCluster, 'updateByQuery', { + ignoreUnavailable: true, + max_docs: 10, + }); + expect(docs.length).toBe(0); + }); + + test('it filters claimed tasks down by supported types, maxAttempts, status, and runAt', async () => { + const maxAttempts = _.random(2, 43); + const customMaxAttempts = _.random(44, 100); + const { + args: { + updateByQuery: { + body: { query }, + }, + }, + } = await testClaimAvailableTasks({ + opts: { + maxAttempts, + definitions: { + foo: { + type: 'foo', + title: '', + createTaskRunner: jest.fn(), + }, + bar: { + type: 'bar', + title: '', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + }, + }, + claimingOpts: { claimOwnershipUntil: new Date(), size: 10 }, + }); + expect(query).toMatchObject({ + bool: { + must: [ + { term: { type: 'task' } }, + { + bool: { + must: [ + { + bool: { + should: [ + { + bool: { + must: [ + { term: { 'task.status': 'idle' } }, + { range: { 'task.runAt': { lte: 'now' } } }, + ], + }, + }, + { + bool: { + must: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }, + { range: { 'task.retryAt': { lte: 'now' } } }, + ], + }, + }, + ], + }, + }, + { + bool: { + should: [ + { exists: { field: 'task.interval' } }, + { + bool: { + must: [ + { term: { 'task.taskType': 'foo' } }, + { + range: { + 'task.attempts': { + lt: maxAttempts, + }, + }, + }, + ], + }, + }, + { + bool: { + must: [ + { term: { 'task.taskType': 'bar' } }, + { + range: { + 'task.attempts': { + lt: customMaxAttempts, + }, + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }); + }); + + test('it claims tasks by setting their ownerId, status and retryAt', async () => { + const taskManagerId = uuid.v1(); + const claimOwnershipUntil = new Date(Date.now()); + const { + args: { + updateByQuery: { + body: { script }, + }, + }, + } = await testClaimAvailableTasks({ + opts: { + taskManagerId, + }, + claimingOpts: { + claimOwnershipUntil, + size: 10, + }, + }); + expect(script).toMatchObject({ + source: `ctx._source.task.ownerId=params.ownerId; ctx._source.task.status=params.status; ctx._source.task.retryAt=params.retryAt;`, + lang: 'painless', + params: { + ownerId: taskManagerId, + retryAt: claimOwnershipUntil, + status: 'claiming', + }, + }); + }); + + test('it returns task objects', async () => { + const taskManagerId = uuid.v1(); + const claimOwnershipUntil = new Date(Date.now()); + const runAt = new Date(); + const tasks = [ + { + _id: 'aaa', + _source: { + type: 'task', + task: { + runAt, + taskType: 'foo', + interval: undefined, + attempts: 0, + status: 'idle', + params: '{ "hello": "world" }', + state: '{ "baby": "Henhen" }', + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + }, + }, + _seq_no: 1, + _primary_term: 2, + sort: ['a', 1], + }, + { + _id: 'bbb', + _source: { + type: 'task', + task: { + runAt, + taskType: 'bar', + interval: '5m', + attempts: 2, + status: 'running', + params: '{ "shazm": 1 }', + state: '{ "henry": "The 8th" }', + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + }, + }, + _seq_no: 3, + _primary_term: 4, + sort: ['b', 2], + }, + ]; + const { + result: { docs }, + args: { + search: { + body: { query }, + }, + }, + } = await testClaimAvailableTasks({ + opts: { + taskManagerId, + }, + claimingOpts: { + claimOwnershipUntil, + size: 10, + }, + hits: tasks, + }); + + expect(query.bool.must).toContainEqual({ + bool: { + must: [ + { + term: { + 'task.ownerId': taskManagerId, + }, + }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }); + + expect(docs).toMatchObject([ + { + attempts: 0, + id: 'aaa', + interval: undefined, + params: { hello: 'world' }, + runAt, + scope: ['reporting'], + state: { baby: 'Henhen' }, + status: 'idle', + taskType: 'foo', + user: 'jimbo', + ownerId: taskManagerId, + }, + { + attempts: 2, + id: 'bbb', + interval: '5m', + params: { shazm: 1 }, + runAt, + scope: ['reporting', 'ceo'], + state: { henry: 'The 8th' }, + status: 'running', + taskType: 'bar', + user: 'dabo', + ownerId: taskManagerId, + }, + ]); + }); + }); + describe('update', () => { test('refreshes the index, handles versioning', async () => { const task = { @@ -563,6 +882,7 @@ describe('TaskStore', () => { attempts: 3, status: 'idle' as TaskStatus, version: '123', + ownerId: null, }; savedObjectsClient.update.mockImplementation( @@ -579,6 +899,7 @@ describe('TaskStore', () => { const store = new TaskStore({ index: 'tasky', + taskManagerId: '', serializer, callCluster: jest.fn(), maxAttempts: 2, @@ -604,6 +925,7 @@ describe('TaskStore', () => { status: task.status, taskType: task.taskType, user: undefined, + ownerId: null, }, { version: '123' } ); @@ -626,6 +948,7 @@ describe('TaskStore', () => { const callCluster = jest.fn(); const store = new TaskStore({ index: 'tasky', + taskManagerId: '', serializer, callCluster, maxAttempts: 2, @@ -638,3 +961,16 @@ describe('TaskStore', () => { }); }); }); + +function generateFakeTasks(count: number = 1) { + return _.times(count, () => ({ + _id: 'aaa', + _source: { + type: 'task', + task: {}, + }, + _seq_no: _.random(1, 5), + _primary_term: _.random(1, 5), + sort: ['a', _.random(1, 5)], + })); +} diff --git a/x-pack/legacy/plugins/task_manager/task_store.ts b/x-pack/legacy/plugins/task_manager/task_store.ts index ddd1b0deb6004..2314d705544d2 100644 --- a/x-pack/legacy/plugins/task_manager/task_store.ts +++ b/x-pack/legacy/plugins/task_manager/task_store.ts @@ -27,16 +27,37 @@ import { export interface StoreOpts { callCluster: ElasticJs; index: string; + taskManagerId: string; maxAttempts: number; definitions: TaskDictionary; savedObjectsRepository: SavedObjectsClientContract; serializer: SavedObjectsSerializer; } -export interface FetchOpts { +export interface SearchOpts { searchAfter?: any[]; - sort?: object[]; + sort?: object | object[]; query?: object; + size?: number; + seq_no_primary_term?: boolean; + search_after?: any[]; +} + +export interface FetchOpts extends SearchOpts { + sort?: object[]; +} + +export interface UpdateByQuerySearchOpts extends SearchOpts { + script?: object; +} + +export interface UpdateByQueryOpts extends SearchOpts { + max_docs?: number; +} + +export interface OwnershipClaimingOpts { + claimOwnershipUntil: Date; + size: number; } export interface FetchResult { @@ -44,6 +65,17 @@ export interface FetchResult { docs: ConcreteTaskInstance[]; } +export interface ClaimOwnershipResult { + claimedTasks: number; + docs: ConcreteTaskInstance[]; +} + +export interface UpdateByQueryResult { + updated: number; + version_conflicts: number; + total: number; +} + /** * Wraps an elasticsearch connection and provides a task manager-specific * interface into the index. @@ -51,6 +83,7 @@ export interface FetchResult { export class TaskStore { public readonly maxAttempts: number; public readonly index: string; + public readonly taskManagerId: string; private callCluster: ElasticJs; private definitions: TaskDictionary; private savedObjectsRepository: SavedObjectsClientContract; @@ -69,6 +102,7 @@ export class TaskStore { constructor(opts: StoreOpts) { this.callCluster = opts.callCluster; this.index = opts.index; + this.taskManagerId = opts.taskManagerId; this.maxAttempts = opts.maxAttempts; this.definitions = opts.definitions; this.serializer = opts.serializer; @@ -196,6 +230,152 @@ export class TaskStore { return docs; } + /** + * Claims available tasks from the index, which are ready to be run. + * - runAt is now or past + * - is not currently claimed by any instance of Kibana + * - has a type that is in our task definitions + * + * @param {OwnershipClaimingOpts} options + * @returns {Promise} + */ + public async claimAvailableTasks(opts: OwnershipClaimingOpts): Promise { + const claimedTasks = await this.markAvailableTasksAsClaimed(opts); + const docs = claimedTasks > 0 ? await this.sweepForClaimedTasks(opts) : []; + return { + claimedTasks, + docs, + }; + } + + private async markAvailableTasksAsClaimed({ + size, + claimOwnershipUntil, + }: OwnershipClaimingOpts): Promise { + const { updated } = await this.updateByQuery( + { + query: { + bool: { + must: [ + // Either a task with idle status and runAt <= now or + // status running or claiming with a retryAt <= now. + { + bool: { + should: [ + { + bool: { + must: [ + { term: { 'task.status': 'idle' } }, + { range: { 'task.runAt': { lte: 'now' } } }, + ], + }, + }, + { + bool: { + must: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }, + { range: { 'task.retryAt': { lte: 'now' } } }, + ], + }, + }, + ], + }, + }, + // Either task has an interval or the attempts < the maximum configured + { + bool: { + should: [ + { exists: { field: 'task.interval' } }, + ...Object.entries(this.definitions).map(([type, definition]) => ({ + bool: { + must: [ + { term: { 'task.taskType': type } }, + { + range: { + 'task.attempts': { + lt: definition.maxAttempts || this.maxAttempts, + }, + }, + }, + ], + }, + })), + ], + }, + }, + ], + }, + }, + sort: { + _script: { + type: 'number', + order: 'asc', + script: { + lang: 'expression', + source: `doc['task.retryAt'].value || doc['task.runAt'].value`, + }, + }, + }, + seq_no_primary_term: true, + script: { + source: `ctx._source.task.ownerId=params.ownerId; ctx._source.task.status=params.status; ctx._source.task.retryAt=params.retryAt;`, + lang: 'painless', + params: { + ownerId: this.taskManagerId, + retryAt: claimOwnershipUntil, + status: 'claiming', + }, + }, + }, + { + max_docs: size, + } + ); + return updated; + } + + /** + * Fetches tasks from the index, which are owned by the current Kibana instance + */ + private async sweepForClaimedTasks({ + size, + }: OwnershipClaimingOpts): Promise { + const { docs } = await this.search({ + query: { + bool: { + must: [ + { + term: { + 'task.ownerId': this.taskManagerId, + }, + }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }, + size, + sort: { + _script: { + type: 'number', + order: 'asc', + script: { + lang: 'expression', + source: `doc['task.retryAt'].value || doc['task.runAt'].value`, + }, + }, + }, + seq_no_primary_term: true, + }); + + return docs; + } /** * Updates the specified doc in the index, returning the doc * with its version up to date. @@ -224,12 +404,8 @@ export class TaskStore { await this.savedObjectsRepository.delete('task', id); } - private async search(opts: any = {}): Promise { - const originalQuery = opts.query; - const queryOnlyTasks = { term: { type: 'task' } }; - const query = originalQuery - ? { bool: { must: [queryOnlyTasks, originalQuery] } } - : queryOnlyTasks; + private async search(opts: SearchOpts = {}): Promise { + const { query } = ensureQueryOnlyReturnsTaskObjects(opts); const result = await this.callCluster('search', { index: this.index, @@ -250,6 +426,31 @@ export class TaskStore { searchAfter: (rawDocs.length && rawDocs[rawDocs.length - 1].sort) || [], }; } + + private async updateByQuery( + opts: UpdateByQuerySearchOpts = {}, + { max_docs }: UpdateByQueryOpts = {} + ): Promise { + const { query } = ensureQueryOnlyReturnsTaskObjects(opts); + const result = await this.callCluster('updateByQuery', { + index: this.index, + ignoreUnavailable: true, + refresh: true, + max_docs, + conflicts: 'proceed', + body: { + ...opts, + query, + }, + }); + + const { total, updated, version_conflicts } = result; + return { + total, + updated, + version_conflicts, + }; + } } function paginatableSort(sort: any[] = []) { @@ -301,3 +502,16 @@ function parseJSONField(json: string, fieldName: string, id: string) { throw new Error(`Task "${id}"'s ${fieldName} field has invalid JSON: ${json}`); } } + +function ensureQueryOnlyReturnsTaskObjects(opts: SearchOpts): SearchOpts { + const originalQuery = opts.query; + const queryOnlyTasks = { term: { type: 'task' } }; + const query = originalQuery + ? { bool: { must: [queryOnlyTasks, originalQuery] } } + : queryOnlyTasks; + + return { + ...opts, + query, + }; +} diff --git a/x-pack/package.json b/x-pack/package.json index 0fd53c1b38b28..b145fa13b6fc1 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -9,7 +9,7 @@ "kbn:bootstrap": "node legacy/plugins/canvas/scripts/storybook --clean", "start": "gulp dev", "build": "gulp build", - "testonly": "gulp testonly", + "testonly": "echo 'Deprecated, use `yarn test`' && gulp test", "test": "gulp test", "test:browser:dev": "gulp testbrowser-dev", "test:browser": "gulp testbrowser", @@ -56,10 +56,13 @@ "@types/d3-time": "^1.0.10", "@types/d3-time-format": "^2.1.1", "@types/elasticsearch": "^5.0.33", + "@types/fancy-log": "^1.3.1", "@types/file-saver": "^2.0.0", + "@types/getos": "^3.0.0", "@types/git-url-parse": "^9.0.0", "@types/glob": "^7.1.1", "@types/graphql": "^0.13.1", + "@types/gulp": "^4.0.6", "@types/hapi__wreck": "^15.0.1", "@types/history": "^4.7.3", "@types/jest": "^24.0.18", @@ -67,7 +70,7 @@ "@types/js-yaml": "^3.11.1", "@types/jsdom": "^12.2.4", "@types/json-stable-stringify": "^1.0.32", - "@types/jsonwebtoken": "^7.2.7", + "@types/jsonwebtoken": "^7.2.8", "@types/lodash": "^3.10.1", "@types/mapbox-gl": "^0.54.1", "@types/memoize-one": "^4.1.0", @@ -82,7 +85,7 @@ "@types/pngjs": "^3.3.2", "@types/prop-types": "^15.5.3", "@types/proper-lockfile": "^3.0.1", - "@types/puppeteer": "^1.19.0", + "@types/puppeteer": "^1.20.1", "@types/react": "^16.8.0", "@types/react-dom": "^16.8.0", "@types/react-redux": "^6.0.6", @@ -122,7 +125,6 @@ "copy-webpack-plugin": "^5.0.4", "cypress": "^3.4.1", "del": "^4.1.1", - "dotenv": "2.0.0", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", "enzyme-adapter-utils": "^1.12.0", @@ -134,8 +136,8 @@ "graphql-codegen-introspection-template": "^0.13.0", "graphql-codegen-typescript-resolvers-template": "^0.13.0", "graphql-codegen-typescript-template": "^0.13.0", - "gulp": "3.9.1", - "gulp-mocha": "^7.0.1", + "gulp": "4.0.2", + "gulp-mocha": "^7.0.2", "gulp-multi-process": "1.3.1", "hapi": "^17.5.3", "jest": "^24.9.0", @@ -162,7 +164,6 @@ "react-testing-library": "^6.0.0", "redux-test-utils": "0.2.2", "rsync": "0.6.1", - "run-sequence": "^2.2.1", "sass-loader": "^7.3.1", "simple-git": "1.116.0", "sinon": "^7.4.2", @@ -257,7 +258,7 @@ "humps": "2.0.1", "i18n-iso-countries": "^4.3.1", "icalendar": "0.7.1", - "idx": "^2.5.2", + "idx": "^2.5.6", "immer": "^1.5.0", "inline-style": "^2.0.0", "intl": "^1.2.5", @@ -268,7 +269,7 @@ "jquery": "^3.4.1", "js-yaml": "3.13.1", "json-stable-stringify": "^1.0.1", - "jsonwebtoken": "^8.3.0", + "jsonwebtoken": "^8.5.1", "jsts": "^1.6.2", "lodash": "npm:@elastic/lodash@3.10.1-kibana3", "lodash.keyby": "^4.6.0", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a91655357bb0e..43b86a09a0a6f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5315,11 +5315,8 @@ "xpack.infra.header.logsTitle": "ログ", "xpack.infra.homePage.settingsTabTitle": "設定", "xpack.infra.kibanaMetrics.cloudIdMissingErrorMessage": "{metricId} のモデルには cloudId が必要ですが、{nodeId} に cloudId が指定されていません。", - "xpack.infra.logs.analysis.logRateSectionAnomalySeriesName": "異常", - "xpack.infra.logs.analysis.logRateSectionAreaSeriesName": "期待値", "xpack.infra.logs.analysis.logRateSectionLineSeriesName": "15 分ごとのログエントリー (平均)", "xpack.infra.logs.analysis.logRateSectionLoadingAriaLabel": "ログレートの結果を読み込み中", - "xpack.infra.logs.analysis.logRateSectionModelBoundsCheckboxLabel": "モデルバウンドを表示", "xpack.infra.logs.analysis.logRateSectionNoDataBody": "時間範囲を調整する必要があるかもしれません。", "xpack.infra.logs.analysis.logRateSectionNoDataTitle": "表示するデータがありません。", "xpack.infra.logs.analysis.logRateSectionTitle": "ログレート", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2d2f7eb19845f..d724bcbcacf67 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5318,11 +5318,8 @@ "xpack.infra.header.logsTitle": "Logs", "xpack.infra.homePage.settingsTabTitle": "设置", "xpack.infra.kibanaMetrics.cloudIdMissingErrorMessage": "{metricId} 的模型需要云 ID,但没有为 {nodeId} 提供。", - "xpack.infra.logs.analysis.logRateSectionAnomalySeriesName": "异常", - "xpack.infra.logs.analysis.logRateSectionAreaSeriesName": "预期", "xpack.infra.logs.analysis.logRateSectionLineSeriesName": "每 15 分钟日志条目数(平均值)", "xpack.infra.logs.analysis.logRateSectionLoadingAriaLabel": "正在加载日志速率结果", - "xpack.infra.logs.analysis.logRateSectionModelBoundsCheckboxLabel": "显示模型边界", "xpack.infra.logs.analysis.logRateSectionNoDataBody": "您可能想调整时间范围。", "xpack.infra.logs.analysis.logRateSectionNoDataTitle": "没有可显示的数据。", "xpack.infra.logs.analysis.logRateSectionTitle": "日志速率", diff --git a/x-pack/tasks/build.js b/x-pack/tasks/build.js deleted file mode 100644 index ee7f22a4f2034..0000000000000 --- a/x-pack/tasks/build.js +++ /dev/null @@ -1,36 +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 { resolve } from 'path'; -import { writeFileSync } from 'fs'; -import pluginHelpers from '@kbn/plugin-helpers'; -import { ToolingLog } from '@kbn/dev-utils'; -import { generateNoticeFromSource } from '../../src/dev'; - -export default (gulp, { buildTarget }) => { - gulp.task('build', ['clean', 'report', 'prepare:build'], async () => { - await pluginHelpers.run('build', { - skipArchive: true, - buildDestination: buildTarget, - }); - - const buildRoot = resolve(buildTarget, 'kibana/x-pack'); - - const log = new ToolingLog({ - level: 'info', - writeTo: process.stdout - }); - - writeFileSync( - resolve(buildRoot, 'NOTICE.txt'), - await generateNoticeFromSource({ - productName: 'Kibana X-Pack', - log, - directory: buildRoot - }) - ); - }); -}; diff --git a/x-pack/tasks/build.ts b/x-pack/tasks/build.ts new file mode 100644 index 0000000000000..6bc615613387e --- /dev/null +++ b/x-pack/tasks/build.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { resolve } from 'path'; +import { writeFileSync } from 'fs'; + +import pluginHelpers from '@kbn/plugin-helpers'; +import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; +import gulp from 'gulp'; +import del from 'del'; +import fancyLog from 'fancy-log'; +import chalk from 'chalk'; + +import { generateNoticeFromSource } from '../../src/dev/notice'; +import { prepareTask } from './prepare'; +import { gitInfo } from './helpers/git_info'; +import { PKG_NAME } from './helpers/pkg'; +import { BUILD_VERSION } from './helpers/build_version'; + +const BUILD_DIR = resolve(REPO_ROOT, 'x-pack/build'); +const PLUGIN_BUILD_DIR = resolve(BUILD_DIR, 'plugin'); + +async function cleanBuildTask() { + fancyLog('Deleting', BUILD_DIR); + await del(BUILD_DIR); +} + +async function reportTask() { + const info = await gitInfo(); + + fancyLog('Package Name', chalk.yellow(PKG_NAME)); + fancyLog('Version', chalk.yellow(BUILD_VERSION)); + fancyLog('Build Number', chalk.yellow(`${info.number}`)); + fancyLog('Build SHA', chalk.yellow(info.sha)); +} + +async function pluginHelpersBuild() { + await pluginHelpers.run('build', { + skipArchive: true, + buildDestination: PLUGIN_BUILD_DIR, + }); +} + +async function generateNoticeText() { + const buildRoot = resolve(PLUGIN_BUILD_DIR, 'kibana/x-pack'); + const log = new ToolingLog({ + level: 'info', + writeTo: process.stdout, + }); + + writeFileSync( + resolve(buildRoot, 'NOTICE.txt'), + await generateNoticeFromSource({ + productName: 'Kibana X-Pack', + log, + directory: buildRoot, + }) + ); +} + +export const buildTask = gulp.series( + cleanBuildTask, + reportTask, + prepareTask, + pluginHelpersBuild, + generateNoticeText +); diff --git a/x-pack/tasks/clean.js b/x-pack/tasks/clean.js deleted file mode 100644 index 8e2098c3b474a..0000000000000 --- a/x-pack/tasks/clean.js +++ /dev/null @@ -1,22 +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 del from 'del'; - -export default (gulp, { coverageDir, buildDir, packageDir, log }) => { - gulp.task('clean-test', () => { - log('Deleting', coverageDir); - return del([coverageDir]); - }); - - gulp.task('clean', ['clean-test'], () => { - const toDelete = [ - buildDir, - packageDir, - ]; - log('Deleting', toDelete.join(', ')); - return del(toDelete); - }); -}; diff --git a/x-pack/tasks/dev.js b/x-pack/tasks/dev.ts similarity index 55% rename from x-pack/tasks/dev.js rename to x-pack/tasks/dev.ts index 048e32ed86574..6e398f231a27c 100644 --- a/x-pack/tasks/dev.js +++ b/x-pack/tasks/dev.ts @@ -5,8 +5,12 @@ */ import pluginHelpers from '@kbn/plugin-helpers'; -import getFlags from './helpers/get_flags'; +import gulp from 'gulp'; -export default (gulp) => { - gulp.task('dev', ['prepare:dev'], () => pluginHelpers.run('start', { flags: getFlags() })); -}; +import { prepareTask } from './prepare'; + +export const devTask = gulp.series(prepareTask, async function startKibanaServer() { + await pluginHelpers.run('start', { + flags: process.argv.slice(3), + }); +}); diff --git a/x-pack/tasks/helpers/build_version.js b/x-pack/tasks/helpers/build_version.js deleted file mode 100644 index f77e1fb7168f4..0000000000000 --- a/x-pack/tasks/helpers/build_version.js +++ /dev/null @@ -1,29 +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 yargs from 'yargs'; -import semver from 'semver'; - -yargs - .alias('r', 'release').describe('r', 'Create a release build, not a snapshot') - .option('build-qualifier', { - default: null - }); -const argv = yargs.argv; - -export default function getVersion(pkg) { - const { version } = pkg; - if (!version) { - throw new Error('No version found in package.json'); - } - if (!semver.valid(version)) { - throw new Error(`Version is not valid semver: ${version}`); - } - - const snapshotText = (argv.release) ? '' : '-SNAPSHOT'; - const qualifierText = argv.buildQualifier ? '-' + argv.buildQualifier : ''; - return `${version}${qualifierText}${snapshotText}`; -} diff --git a/x-pack/tasks/helpers/build_version.ts b/x-pack/tasks/helpers/build_version.ts new file mode 100644 index 0000000000000..7e9954ed3f756 --- /dev/null +++ b/x-pack/tasks/helpers/build_version.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 { PKG_VERSION } from './pkg'; +import { FLAGS } from './flags'; + +const snapshotText = FLAGS.release ? '' : '-SNAPSHOT'; +const qualifierText = FLAGS.buildQualifier ? '-' + FLAGS.buildQualifier : ''; +export const BUILD_VERSION = `${PKG_VERSION}${qualifierText}${snapshotText}`; diff --git a/x-pack/tasks/helpers/flags.ts b/x-pack/tasks/helpers/flags.ts new file mode 100644 index 0000000000000..62a382b02ed22 --- /dev/null +++ b/x-pack/tasks/helpers/flags.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { resolve } from 'path'; + +import log from 'fancy-log'; +import getopts from 'getopts'; +import { toArray } from 'rxjs/operators'; + +// @ts-ignore complicated module doesn't have types yet +import { findPluginSpecs } from '../../../src/legacy/plugin_discovery'; + +/* + Usage: + Specifying which plugins to run tests can be done with the --plugins flag. + One of more plugins can be specified, and each one should be command separated, like so: + gulp testserver --plugins monitoring,reporting + If using with yarn: + yarn test:server --plugins graph +*/ + +const opts = Object.freeze( + getopts(process.argv.slice(2), { + alias: { + release: 'r', + }, + boolean: ['release', 'flags'], + string: ['build-qualifier', 'plugins'], + }) +); + +if (opts.flags) { + log(` + X-Pack Gulpfile Flags: + + --flags Print this message + --plugins Comma-separated list of plugins + --release, -r Build to a release version + --build-qualifier Qualifier to include in the build version + `); + process.exit(0); +} + +export const FLAGS = { + release: !!opts.release, + buildQualifier: opts.buildQualifier as string | undefined, + plugins: opts.plugins + ? String(opts.plugins) + .split(',') + .map(id => id.trim()) + : undefined, +}; + +export async function getEnabledPlugins() { + if (FLAGS.plugins) { + return FLAGS.plugins; + } + + const { spec$ } = findPluginSpecs({ + plugins: { + paths: [resolve(__dirname, '..', '..')], + }, + }); + + const enabledPlugins: Array<{ getId: () => string }> = await spec$.pipe(toArray()).toPromise(); + return enabledPlugins.map(spec => spec.getId()); +} diff --git a/x-pack/tasks/helpers/get_plugins.js b/x-pack/tasks/helpers/get_plugins.js deleted file mode 100644 index a540cda27bd73..0000000000000 --- a/x-pack/tasks/helpers/get_plugins.js +++ /dev/null @@ -1,46 +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 { resolve } from 'path'; -import yargs from 'yargs'; -import glob from 'glob'; -import { toArray } from 'rxjs/operators'; -import { findPluginSpecs } from '../../../src/legacy/plugin_discovery'; - -/* - Usage: - Specifying which plugins to run tests can be done with the --plugins flag. - One of more plugins can be specified, and each one should be command separated, like so: - gulp testserver --plugins monitoring,reporting - If using with yarn: - yarn test:server --plugins graph -*/ - -const argv = yargs - .describe('plugins', 'Comma-separated list of plugins') - .argv; -const allPlugins = glob.sync('*', { cwd: resolve(__dirname, '..', '..', 'legacy', 'plugins') }); - -export function getPlugins() { - const plugins = argv.plugins && argv.plugins.split(','); - if (!Array.isArray(plugins) || plugins.length === 0) { - return allPlugins; - } - return plugins; -} - -const { spec$ } = findPluginSpecs({ - plugins: { paths: [resolve(__dirname, '..', '..')] } -}); - -export async function getEnabledPlugins() { - const plugins = argv.plugins && argv.plugins.split(','); - if (!Array.isArray(plugins) || plugins.length === 0) { - const enabledPlugins = await spec$.pipe(toArray()).toPromise(); - return enabledPlugins.map(spec => spec.getId()); - } - return plugins; -} diff --git a/x-pack/tasks/helpers/git_info.js b/x-pack/tasks/helpers/git_info.ts similarity index 50% rename from x-pack/tasks/helpers/git_info.js rename to x-pack/tasks/helpers/git_info.ts index 8e6f463004746..3c144e6cc10d0 100644 --- a/x-pack/tasks/helpers/git_info.js +++ b/x-pack/tasks/helpers/git_info.ts @@ -5,20 +5,24 @@ */ import path from 'path'; +// @ts-ignore barely used, untyped module import simpleGit from 'simple-git'; const gitDir = path.resolve(__dirname, '..', '..'); -export default function gitInfo() { +export async function gitInfo() { const git = simpleGit(gitDir); - return new Promise((resolve, reject) => { - git.log((err, log) => { - if (err) return reject(err); - resolve({ - number: log.total, - sha: log.latest.hash, - }); + return new Promise<{ number: number; sha: string }>((resolve, reject) => { + git.log((err: undefined | Error, log: { total: number; latest: { hash: string } }) => { + if (err) { + reject(err); + } else { + resolve({ + number: log.total, + sha: log.latest.hash, + }); + } }); }); } diff --git a/x-pack/tasks/helpers/globs.js b/x-pack/tasks/helpers/globs.js deleted file mode 100644 index 0576389c94249..0000000000000 --- a/x-pack/tasks/helpers/globs.js +++ /dev/null @@ -1,49 +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 { getPlugins } from './get_plugins'; - -/* - * Note: The path `plugins / pluginName / ** / __tests__ / ** / *.js` will match - * all public and server tests, so a special var must be used for "index" tests - * paths: `plugins / pluginName / __tests__ / ** / *.js` - */ -function getPluginPaths(plugins, opts = {}) { - const testPath = opts.tests ? '__tests__/**' : ''; - - return plugins.reduce((paths, pluginName) => { - const plugin = pluginName.trim(); - - const commonPath = `${plugin}/common`; - const serverPath = `${plugin}/**/server`; - const publicPath = `${plugin}/**/public`; - - const indexPaths = `legacy/plugins/${plugin}/${testPath}/*.js`; // index and helpers - const commonPaths = `legacy/plugins/${commonPath}/**/${testPath}/*.js`; - const serverPaths = `legacy/plugins/${serverPath}/**/${testPath}/*.js`; - const publicPaths = `legacy/plugins/${publicPath}/**/${testPath}/*.js`; - - paths = paths.concat([indexPaths, commonPaths, serverPaths]); - if (plugin === 'code') { - paths.push(`legacy/plugins/${serverPath}/**/${testPath}/*.ts`); - } - if (opts.browser) { - paths = paths.concat(publicPaths); - } - - return paths; - }, []); -} - -export function forPlugins() { - const plugins = getPlugins(); - return getPluginPaths(plugins, { browser: true }); -} - -export function forPluginServerTests() { - const plugins = getPlugins(); - return getPluginPaths(plugins, { tests: true }); -} diff --git a/x-pack/tasks/helpers/pkg.ts b/x-pack/tasks/helpers/pkg.ts new file mode 100644 index 0000000000000..8411ebcf7186a --- /dev/null +++ b/x-pack/tasks/helpers/pkg.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import Fs from 'fs'; +import semver from 'semver'; + +interface PackageJson { + name: string; + version: string; + dependencies: Record; + devDependencies: Record; + [key: string]: unknown; +} + +const PKG_PATH = require.resolve('../../package.json'); +export const PKG: PackageJson = JSON.parse(Fs.readFileSync(PKG_PATH, 'utf8')); +export const PKG_VERSION = PKG.version; +export const PKG_NAME = PKG.name; + +if (!PKG_VERSION) { + throw new Error('No "version" found in package.json'); +} + +if (!PKG_NAME) { + throw new Error('No "name" found in package.json'); +} + +if (!semver.valid(PKG_VERSION)) { + throw new Error(`Version is not valid semver: ${PKG_VERSION}`); +} diff --git a/x-pack/tasks/prepare.js b/x-pack/tasks/prepare.js deleted file mode 100644 index 287781a819400..0000000000000 --- a/x-pack/tasks/prepare.js +++ /dev/null @@ -1,18 +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 { ensureAllBrowsersDownloaded } from '../legacy/plugins/reporting/server/browsers'; - -export default gulp => { - // anything that should always happen before anything else - gulp.task('prepare', () => ensureAllBrowsersDownloaded()); - - // anything that needs to happen before development - gulp.task('prepare:dev', ['prepare']); - - // anything that needs to happen before building - gulp.task('prepare:build', ['prepare']); -}; diff --git a/x-pack/legacy/plugins/canvas/tasks/mocks/uiStorage.js b/x-pack/tasks/prepare.ts similarity index 58% rename from x-pack/legacy/plugins/canvas/tasks/mocks/uiStorage.js rename to x-pack/tasks/prepare.ts index ff10d2d4bf68e..6d4eb5603ad3a 100644 --- a/x-pack/legacy/plugins/canvas/tasks/mocks/uiStorage.js +++ b/x-pack/tasks/prepare.ts @@ -4,12 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export class Storage { - get(key) { - return this[key]; - } +import { ensureAllBrowsersDownloaded } from '../legacy/plugins/reporting/server/browsers'; - set(key, value) { - this[key] = value; - } -} +export const prepareTask = async () => { + await ensureAllBrowsersDownloaded(); +}; diff --git a/x-pack/tasks/report.js b/x-pack/tasks/report.js deleted file mode 100644 index a7e1a2e31de58..0000000000000 --- a/x-pack/tasks/report.js +++ /dev/null @@ -1,21 +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 buildVersion from './helpers/build_version'; -import gitInfo from './helpers/git_info'; -import chalk from 'chalk'; - -export default (gulp, { log, pkg }) => { - gulp.task('report', () => { - return gitInfo() - .then(function (info) { - log('Package Name', chalk.yellow(pkg.name)); - log('Version', chalk.yellow(buildVersion(pkg))); - log('Build Number', chalk.yellow(info.number)); - log('Build SHA', chalk.yellow(info.sha)); - }); - }); -}; diff --git a/x-pack/tasks/test.js b/x-pack/tasks/test.js deleted file mode 100644 index 5aae780dda6d7..0000000000000 --- a/x-pack/tasks/test.js +++ /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. - */ - -import runSequence from 'run-sequence'; -import pluginHelpers from '@kbn/plugin-helpers'; -import { getEnabledPlugins } from './helpers/get_plugins'; -import { forPluginServerTests } from './helpers/globs'; -import { createAutoJUnitReporter } from '../../src/dev'; - -const MOCHA_OPTIONS = { - ui: 'bdd', - require: require.resolve('../../src/setup_node_env'), - reporter: createAutoJUnitReporter({ - reportName: 'X-Pack Mocha Tests', - }), -}; - -export default (gulp, { mocha }) => { - gulp.task('test', (cb) => { - const preTasks = ['clean-test']; - runSequence(preTasks, 'testserver', 'testbrowser', cb); - }); - - gulp.task('testonly', ['testserver', 'testbrowser']); - - gulp.task('testserver', () => { - const globs = [ - 'common/**/__tests__/**/*.js', - 'server/**/__tests__/**/*.js', - ].concat(forPluginServerTests()); - return gulp.src(globs, { read: false }) - .pipe(mocha(MOCHA_OPTIONS)); - }); - - gulp.task('testbrowser', () => { - return getEnabledPlugins().then(plugins => { - return pluginHelpers.run('testBrowser', { - plugins: plugins.join(','), - }); - }); - }); - - gulp.task('testbrowser-dev', () => { - return getEnabledPlugins().then(plugins => { - return pluginHelpers.run('testBrowser', { - dev: true, - plugins: plugins.join(','), - }); - }); - }); -}; diff --git a/x-pack/tasks/test.ts b/x-pack/tasks/test.ts new file mode 100644 index 0000000000000..d172a0234fe4f --- /dev/null +++ b/x-pack/tasks/test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import pluginHelpers from '@kbn/plugin-helpers'; +// @ts-ignore no types available +import mocha from 'gulp-mocha'; +import gulp from 'gulp'; + +// @ts-ignore untyped, converted in a different location in master +import { createAutoJUnitReporter } from '../../src/dev/mocha'; +import { getEnabledPlugins } from './helpers/flags'; + +export const testServerTask = async () => { + const pluginIds = await getEnabledPlugins(); + + const testGlobs = ['common/**/__tests__/**/*.js', 'server/**/__tests__/**/*.js']; + + if (pluginIds.includes('code')) { + testGlobs.push(`legacy/plugins/**/server/**/__tests__/**/*.ts`); + } + + for (const pluginId of pluginIds) { + testGlobs.push( + `legacy/plugins/${pluginId}/__tests__/**/*.js`, + `legacy/plugins/${pluginId}/common/**/__tests__/**/*.js`, + `legacy/plugins/${pluginId}/**/server/**/__tests__/**/*.js` + ); + } + + return gulp.src(testGlobs, { read: false }).pipe( + mocha({ + ui: 'bdd', + require: require.resolve('../../src/setup_node_env'), + reporter: createAutoJUnitReporter({ + reportName: 'X-Pack Mocha Tests', + }), + }) + ); +}; + +export const testBrowserTask = async () => { + const plugins = await getEnabledPlugins(); + await pluginHelpers.run('testBrowser', { + plugins: plugins.join(','), + }); +}; + +export const testBrowserDevTask = async () => { + const plugins = await getEnabledPlugins(); + await pluginHelpers.run('testBrowser', { + dev: true, + plugins: plugins.join(','), + }); +}; + +export const testTask = gulp.series(testServerTask, testBrowserTask); diff --git a/x-pack/test/api_integration/apis/infra/log_analysis.ts b/x-pack/test/api_integration/apis/infra/log_analysis.ts index bd09cdf6ff56e..fe7d55649d1d6 100644 --- a/x-pack/test/api_integration/apis/infra/log_analysis.ts +++ b/x-pack/test/api_integration/apis/infra/log_analysis.ts @@ -20,8 +20,8 @@ import { } from '../../../../legacy/plugins/infra/common/runtime_types'; import { FtrProviderContext } from '../../ftr_provider_context'; -const TIME_BEFORE_START = 1564315100000; -const TIME_AFTER_END = 1565040700000; +const TIME_BEFORE_START = 1569934800000; +const TIME_AFTER_END = 1570016700000; const COMMON_HEADERS = { 'kbn-xsrf': 'some-xsrf-token', }; @@ -32,8 +32,8 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); describe('log analysis apis', () => { - before(() => esArchiver.load('infra/8.0.0/ml_anomalies_log_rate')); - after(() => esArchiver.unload('infra/8.0.0/ml_anomalies_log_rate')); + before(() => esArchiver.load('infra/8.0.0/ml_anomalies_partitioned_log_rate')); + after(() => esArchiver.unload('infra/8.0.0/ml_anomalies_partitioned_log_rate')); describe('log rate results', () => { describe('with the default source', () => { @@ -62,11 +62,12 @@ export default ({ getService }: FtrProviderContext) => { getLogEntryRateSuccessReponsePayloadRT.decode(body), fold(throwErrors(createPlainError), identity) ); - expect(logEntryRateBuckets.data.bucketDuration).to.be(15 * 60 * 1000); expect(logEntryRateBuckets.data.histogramBuckets).to.not.be.empty(); expect( - logEntryRateBuckets.data.histogramBuckets.some(bucket => bucket.anomalies.length > 0) + logEntryRateBuckets.data.histogramBuckets.some(bucket => { + return bucket.dataSets.some(dataSet => dataSet.anomalies.length > 0); + }) ).to.be(true); }); diff --git a/x-pack/test/functional/apps/code/history.ts b/x-pack/test/functional/apps/code/history.ts index 8893b88e6fa49..a0442d1e3fb2e 100644 --- a/x-pack/test/functional/apps/code/history.ts +++ b/x-pack/test/functional/apps/code/history.ts @@ -33,7 +33,6 @@ export default function manageRepositoriesFunctionalTests({ const repositoryListSelector = 'codeRepositoryList > codeRepositoryItem'; describe('browser history can go back while exploring code app', () => { - let driver: any; before(async () => { await repoLoad( 'github.com/elastic/TypeScript-Node-Starter', @@ -45,9 +44,6 @@ export default function manageRepositoriesFunctionalTests({ // Navigate to the code app. await PageObjects.common.navigateToApp('code'); await PageObjects.header.waitUntilLoadingHasFinished(); - - const webDriver = await getService('__webdriver__').init(); - driver = webDriver.driver; }); after(async () => { @@ -89,7 +85,7 @@ export default function manageRepositoriesFunctionalTests({ }); // can go forward to source view page - await driver.navigate().forward(); + await browser.goForward(); await retry.try(async () => { expect(await testSubjects.exists('codeStructureTreeTab')).to.be(true); @@ -112,7 +108,7 @@ export default function manageRepositoriesFunctionalTests({ expect(await testSubjects.exists('codeStructureTreeTab')).to.be(true); }); - await driver.navigate().forward(); + await browser.goForward(); await retry.try(async () => { const searchResultListSelector = 'codeSearchResultList codeSearchResultFileItem'; @@ -157,7 +153,7 @@ export default function manageRepositoriesFunctionalTests({ expect(lang.indexOf('typescript')).to.equal(0); }); - await driver.navigate().forward(); + await browser.goForward(); await retry.try(async () => { const filter = await (await find.allByCssSelector( @@ -207,7 +203,7 @@ export default function manageRepositoriesFunctionalTests({ expect(existence).to.be(false); }); - await driver.navigate().forward(); + await browser.goForward(); await retry.try(async () => { const existence = await find.existsByCssSelector('.code-line-number-21', FIND_TIME); @@ -239,7 +235,7 @@ export default function manageRepositoriesFunctionalTests({ expect(testSubjects.exists('codeFileTreeTabActive')).to.be.ok(); }); - await driver.navigate().forward(); + await browser.goForward(); await retry.try(async () => { // if structure tree tab is active, file tree tab's `data-test-subj` would be `codeFileTreeTab` diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/index.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/index.ts new file mode 100644 index 0000000000000..8d2e58bb0614d --- /dev/null +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/index.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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function({ loadTestFile }: FtrProviderContext) { + describe('anomaly detection', function() { + loadTestFile(require.resolve('./single_metric_job')); + loadTestFile(require.resolve('./multi_metric_job')); + loadTestFile(require.resolve('./population_job')); + loadTestFile(require.resolve('./saved_search_job')); + }); +} diff --git a/x-pack/test/functional/apps/machine_learning/multi_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts similarity index 98% rename from x-pack/test/functional/apps/machine_learning/multi_metric_job.ts rename to x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts index 2fe5cfe1269d9..98059885a5abb 100644 --- a/x-pack/test/functional/apps/machine_learning/multi_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function({ getService }: FtrProviderContext) { @@ -94,7 +94,7 @@ export default function({ getService }: FtrProviderContext) { }); it('loads the job type selection page', async () => { - await ml.jobSourceSelection.selectSourceIndexPattern('farequote'); + await ml.jobSourceSelection.selectSource('farequote'); }); it('loads the multi metric job wizard page', async () => { diff --git a/x-pack/test/functional/apps/machine_learning/population_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts similarity index 99% rename from x-pack/test/functional/apps/machine_learning/population_job.ts rename to x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts index fa24673c21044..d6ec3a6e7e080 100644 --- a/x-pack/test/functional/apps/machine_learning/population_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function({ getService }: FtrProviderContext) { @@ -108,7 +108,7 @@ export default function({ getService }: FtrProviderContext) { }); it('loads the job type selection page', async () => { - await ml.jobSourceSelection.selectSourceIndexPattern('ecommerce'); + await ml.jobSourceSelection.selectSource('ecommerce'); }); it('loads the population job wizard page', async () => { diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts new file mode 100644 index 0000000000000..34934f8caf914 --- /dev/null +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts @@ -0,0 +1,472 @@ +/* + * 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'; + +// eslint-disable-next-line import/no-default-export +export default function({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + + const testDataList = [ + { + suiteTitle: 'with filter', + jobSource: 'farequote_filter', + jobId: `fq_saved_search_1_${Date.now()}`, + jobDescription: 'Create multi metric job based on a saved search with filter', + jobGroups: ['automated', 'farequote', 'multi-metric', 'saved-search'], + aggAndFieldIdentifiers: ['Mean(responsetime)'], + splitField: 'airline', + bucketSpan: '15m', + memoryLimit: '20mb', + expected: { + wizard: { + numberOfBackCards: 0, + frontCardTitle: 'ASA', + }, + row: { + recordCount: '5,675', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2016-02-11 23:59:54', + }, + counts: { + processed_record_count: '5,675', + processed_field_count: '11,350', + input_bytes: '430.9 KB', + input_field_count: '11,350', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '479', + earliest_record_timestamp: '2016-02-07 00:00:00', + latest_record_timestamp: '2016-02-11 23:59:54', + input_record_count: '5,675', + latest_bucket_timestamp: '2016-02-11 23:45:00', + }, + modelSizeStats: { + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '20971520', + total_by_field_count: '3', + total_over_field_count: '0', + total_partition_field_count: '2', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2016-02-11 23:30:00', + }, + }, + }, + { + suiteTitle: 'with lucene query', + jobSource: 'farequote_lucene', + jobId: `fq_saved_search_2_${Date.now()}`, + jobDescription: 'Create multi metric job based on a saved search with lucene query', + jobGroups: ['automated', 'farequote', 'multi-metric', 'saved-search'], + aggAndFieldIdentifiers: ['Mean(responsetime)'], + splitField: 'airline', + bucketSpan: '15m', + memoryLimit: '20mb', + expected: { + wizard: { + numberOfBackCards: 4, + frontCardTitle: 'AAL', + }, + row: { + recordCount: '34,416', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2016-02-11 23:59:54', + }, + counts: { + processed_record_count: '34,416', + processed_field_count: '68,832', + input_bytes: '2.6 MB', + input_field_count: '68,832', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '479', + earliest_record_timestamp: '2016-02-07 00:00:00', + latest_record_timestamp: '2016-02-11 23:59:54', + input_record_count: '34,416', + latest_bucket_timestamp: '2016-02-11 23:45:00', + }, + modelSizeStats: { + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '20971520', + total_by_field_count: '7', + total_over_field_count: '0', + total_partition_field_count: '6', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2016-02-11 23:30:00', + }, + }, + }, + { + suiteTitle: 'with kuery query', + jobSource: 'farequote_kuery', + jobId: `fq_saved_search_3_${Date.now()}`, + jobDescription: 'Create multi metric job based on a saved search with kuery query', + jobGroups: ['automated', 'farequote', 'multi-metric', 'saved-search'], + aggAndFieldIdentifiers: ['Mean(responsetime)'], + splitField: 'airline', + bucketSpan: '15m', + memoryLimit: '20mb', + expected: { + wizard: { + numberOfBackCards: 4, + frontCardTitle: 'AAL', + }, + row: { + recordCount: '34,415', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2016-02-11 23:59:54', + }, + counts: { + processed_record_count: '34,415', + processed_field_count: '68,830', + input_bytes: '2.6 MB', + input_field_count: '68,830', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '479', + earliest_record_timestamp: '2016-02-07 00:00:00', + latest_record_timestamp: '2016-02-11 23:59:54', + input_record_count: '34,415', + latest_bucket_timestamp: '2016-02-11 23:45:00', + }, + modelSizeStats: { + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '20971520', + total_by_field_count: '7', + total_over_field_count: '0', + total_partition_field_count: '6', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2016-02-11 23:30:00', + }, + }, + }, + { + suiteTitle: 'with filter and lucene query', + jobSource: 'farequote_filter_and_lucene', + jobId: `fq_saved_search_4_${Date.now()}`, + jobDescription: + 'Create multi metric job based on a saved search with filter and lucene query', + jobGroups: ['automated', 'farequote', 'multi-metric', 'saved-search'], + aggAndFieldIdentifiers: ['Mean(responsetime)'], + splitField: 'airline', + bucketSpan: '15m', + memoryLimit: '20mb', + expected: { + wizard: { + numberOfBackCards: 0, + frontCardTitle: 'ASA', + }, + row: { + recordCount: '5,673', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2016-02-11 23:59:54', + }, + counts: { + processed_record_count: '5,673', + processed_field_count: '11,346', + input_bytes: '430.7 KB', + input_field_count: '11,346', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '479', + earliest_record_timestamp: '2016-02-07 00:00:00', + latest_record_timestamp: '2016-02-11 23:59:54', + input_record_count: '5,673', + latest_bucket_timestamp: '2016-02-11 23:45:00', + }, + modelSizeStats: { + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '20971520', + total_by_field_count: '3', + total_over_field_count: '0', + total_partition_field_count: '2', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2016-02-11 23:30:00', + }, + }, + }, + { + suiteTitle: 'with filter and kuery query', + jobSource: 'farequote_filter_and_kuery', + jobId: `fq_saved_search_5_${Date.now()}`, + jobDescription: 'Create multi metric job based on a saved search with filter and kuery query', + jobGroups: ['automated', 'farequote', 'multi-metric', 'saved-search'], + aggAndFieldIdentifiers: ['Mean(responsetime)'], + splitField: 'airline', + bucketSpan: '15m', + memoryLimit: '20mb', + expected: { + wizard: { + numberOfBackCards: 0, + frontCardTitle: 'ASA', + }, + row: { + recordCount: '5,674', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2016-02-11 23:59:54', + }, + counts: { + processed_record_count: '5,674', + processed_field_count: '11,348', + input_bytes: '430.8 KB', + input_field_count: '11,348', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '479', + earliest_record_timestamp: '2016-02-07 00:00:00', + latest_record_timestamp: '2016-02-11 23:59:54', + input_record_count: '5,674', + latest_bucket_timestamp: '2016-02-11 23:45:00', + }, + modelSizeStats: { + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '20971520', + total_by_field_count: '3', + total_over_field_count: '0', + total_partition_field_count: '2', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2016-02-11 23:30:00', + }, + }, + }, + ]; + + describe('saved search', function() { + this.tags(['smoke', 'mlqa']); + before(async () => { + await esArchiver.loadIfNeeded('ml/farequote'); + }); + + after(async () => { + await esArchiver.unload('ml/farequote'); + await ml.api.cleanMlIndices(); + await ml.api.cleanDataframeIndices(); + }); + + for (const testData of testDataList) { + describe(`job creation ${testData.suiteTitle}`, function() { + it('loads the job management page', async () => { + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + }); + + it('loads the new job source selection page', async () => { + await ml.jobManagement.navigateToNewJobSourceSelection(); + }); + + it('loads the job type selection page', async () => { + await ml.jobSourceSelection.selectSource(testData.jobSource); + }); + + it('loads the multi metric job wizard page', async () => { + await ml.jobTypeSelection.selectMultiMetricJob(); + }); + + it('displays the time range step', async () => { + await ml.jobWizardCommon.assertTimeRangeSectionExists(); + }); + + it('displays the event rate chart', async () => { + await ml.jobWizardCommon.clickUseFullDataButton( + 'Feb 7, 2016 @ 00:00:00.000', + 'Feb 11, 2016 @ 23:59:54.000' + ); + await ml.jobWizardCommon.assertEventRateChartExists(); + await ml.jobWizardCommon.assertEventRateChartHasData(); + }); + + it('displays the pick fields step', async () => { + await ml.jobWizardCommon.advanceToPickFieldsSection(); + }); + + it('selects detectors and displays detector previews', async () => { + for (const [index, aggAndFieldIdentifier] of testData.aggAndFieldIdentifiers.entries()) { + await ml.jobWizardCommon.assertAggAndFieldInputExists(); + await ml.jobWizardCommon.selectAggAndField(aggAndFieldIdentifier, false); + await ml.jobWizardCommon.assertDetectorPreviewExists( + aggAndFieldIdentifier, + index, + 'LINE' + ); + } + }); + + it('inputs the split field and displays split cards', async () => { + await ml.jobWizardMultiMetric.assertSplitFieldInputExists(); + await ml.jobWizardMultiMetric.selectSplitField(testData.splitField); + + await ml.jobWizardMultiMetric.assertDetectorSplitExists(testData.splitField); + await ml.jobWizardMultiMetric.assertDetectorSplitFrontCardTitle( + testData.expected.wizard.frontCardTitle + ); + await ml.jobWizardMultiMetric.assertDetectorSplitNumberOfBackCards( + testData.expected.wizard.numberOfBackCards + ); + + await ml.jobWizardCommon.assertInfluencerSelection([testData.splitField]); + }); + + it('displays the influencer field', async () => { + await ml.jobWizardCommon.assertInfluencerInputExists(); + await ml.jobWizardCommon.assertInfluencerSelection([testData.splitField]); + }); + + it('inputs the bucket span', async () => { + await ml.jobWizardCommon.assertBucketSpanInputExists(); + await ml.jobWizardCommon.setBucketSpan(testData.bucketSpan); + }); + + it('displays the job details step', async () => { + await ml.jobWizardCommon.advanceToJobDetailsSection(); + }); + + it('inputs the job id', async () => { + await ml.jobWizardCommon.assertJobIdInputExists(); + await ml.jobWizardCommon.setJobId(testData.jobId); + }); + + it('inputs the job description', async () => { + await ml.jobWizardCommon.assertJobDescriptionInputExists(); + await ml.jobWizardCommon.setJobDescription(testData.jobDescription); + }); + + it('inputs job groups', async () => { + await ml.jobWizardCommon.assertJobGroupInputExists(); + for (const jobGroup of testData.jobGroups) { + await ml.jobWizardCommon.addJobGroup(jobGroup); + } + await ml.jobWizardCommon.assertJobGroupSelection(testData.jobGroups); + }); + + it('opens the advanced section', async () => { + await ml.jobWizardCommon.ensureAdvancedSectionOpen(); + }); + + it('displays the model plot switch', async () => { + await ml.jobWizardCommon.assertModelPlotSwitchExists(); + }); + + it('enables the dedicated index switch', async () => { + await ml.jobWizardCommon.assertDedicatedIndexSwitchExists(); + await ml.jobWizardCommon.activateDedicatedIndexSwitch(); + }); + + it('inputs the model memory limit', async () => { + await ml.jobWizardCommon.assertModelMemoryLimitInputExists(); + await ml.jobWizardCommon.setModelMemoryLimit(testData.memoryLimit); + }); + + it('displays the validation step', async () => { + await ml.jobWizardCommon.advanceToValidationSection(); + }); + + it('displays the summary step', async () => { + await ml.jobWizardCommon.advanceToSummarySection(); + }); + + it('creates the job and finishes processing', async () => { + await ml.jobWizardCommon.assertCreateJobButtonExists(); + await ml.jobWizardCommon.createJobAndWaitForCompletion(); + }); + + it('displays the created job in the job list', async () => { + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(testData.jobId); + const rows = await ml.jobTable.parseJobTable(); + expect(rows.filter(row => row.id === testData.jobId)).to.have.length(1); + }); + + it('displays details for the created job in the job list', async () => { + await ml.jobTable.assertJobRowFields(testData.jobId, { + id: testData.jobId, + description: testData.jobDescription, + jobGroups: [...new Set(testData.jobGroups)].sort(), + recordCount: testData.expected.row.recordCount, + memoryStatus: testData.expected.row.memoryStatus, + jobState: testData.expected.row.jobState, + datafeedState: testData.expected.row.datafeedState, + latestTimestamp: testData.expected.row.latestTimestamp, + }); + + await ml.jobTable.assertJobRowDetailsCounts( + testData.jobId, + { + job_id: testData.jobId, + processed_record_count: testData.expected.counts.processed_record_count, + processed_field_count: testData.expected.counts.processed_field_count, + input_bytes: testData.expected.counts.input_bytes, + input_field_count: testData.expected.counts.input_field_count, + invalid_date_count: testData.expected.counts.invalid_date_count, + missing_field_count: testData.expected.counts.missing_field_count, + out_of_order_timestamp_count: testData.expected.counts.out_of_order_timestamp_count, + empty_bucket_count: testData.expected.counts.empty_bucket_count, + sparse_bucket_count: testData.expected.counts.sparse_bucket_count, + bucket_count: testData.expected.counts.bucket_count, + earliest_record_timestamp: testData.expected.counts.earliest_record_timestamp, + latest_record_timestamp: testData.expected.counts.latest_record_timestamp, + input_record_count: testData.expected.counts.input_record_count, + latest_bucket_timestamp: testData.expected.counts.latest_bucket_timestamp, + }, + { + job_id: testData.jobId, + result_type: testData.expected.modelSizeStats.result_type, + model_bytes_exceeded: testData.expected.modelSizeStats.model_bytes_exceeded, + model_bytes_memory_limit: testData.expected.modelSizeStats.model_bytes_memory_limit, + total_by_field_count: testData.expected.modelSizeStats.total_by_field_count, + total_over_field_count: testData.expected.modelSizeStats.total_over_field_count, + total_partition_field_count: + testData.expected.modelSizeStats.total_partition_field_count, + bucket_allocation_failures_count: + testData.expected.modelSizeStats.bucket_allocation_failures_count, + memory_status: testData.expected.modelSizeStats.memory_status, + timestamp: testData.expected.modelSizeStats.timestamp, + } + ); + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/machine_learning/single_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts similarity index 98% rename from x-pack/test/functional/apps/machine_learning/single_metric_job.ts rename to x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts index 4b112e63758d6..bd40ee61b18c8 100644 --- a/x-pack/test/functional/apps/machine_learning/single_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function({ getService }: FtrProviderContext) { @@ -93,7 +93,7 @@ export default function({ getService }: FtrProviderContext) { }); it('loads the job type selection page', async () => { - await ml.jobSourceSelection.selectSourceIndexPattern('farequote'); + await ml.jobSourceSelection.selectSource('farequote'); }); it('loads the single metric job wizard page', async () => { diff --git a/x-pack/test/functional/apps/machine_learning/index.ts b/x-pack/test/functional/apps/machine_learning/index.ts index 09641d8a75d63..1d081783c6c60 100644 --- a/x-pack/test/functional/apps/machine_learning/index.ts +++ b/x-pack/test/functional/apps/machine_learning/index.ts @@ -11,8 +11,6 @@ export default function({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./pages')); - loadTestFile(require.resolve('./single_metric_job')); - loadTestFile(require.resolve('./multi_metric_job')); - loadTestFile(require.resolve('./population_job')); + loadTestFile(require.resolve('./anomaly_detection')); }); } diff --git a/x-pack/test/functional/config.ie.js b/x-pack/test/functional/config.ie.js new file mode 100644 index 0000000000000..7a46471726fcf --- /dev/null +++ b/x-pack/test/functional/config.ie.js @@ -0,0 +1,81 @@ +/* + * 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 default async function ({ readConfigFile }) { + const defaultConfig = await readConfigFile(require.resolve('./config')); + + return { + ...defaultConfig.getAll(), + //csp.strict: false + // testFiles: [ + // require.resolve(__dirname, './apps/advanced_settings'), + // require.resolve(__dirname, './apps/canvas'), + // require.resolve(__dirname, './apps/graph'), + // require.resolve(__dirname, './apps/monitoring'), + // require.resolve(__dirname, './apps/watcher'), + // require.resolve(__dirname, './apps/dashboard'), + // require.resolve(__dirname, './apps/dashboard_mode'), + // require.resolve(__dirname, './apps/discover'), + // require.resolve(__dirname, './apps/security'), + // require.resolve(__dirname, './apps/spaces'), + // require.resolve(__dirname, './apps/lens'), + // require.resolve(__dirname, './apps/logstash'), + // require.resolve(__dirname, './apps/grok_debugger'), + // require.resolve(__dirname, './apps/infra'), + // require.resolve(__dirname, './apps/machine_learning'), + // require.resolve(__dirname, './apps/rollup_job'), + // require.resolve(__dirname, './apps/maps'), + // require.resolve(__dirname, './apps/status_page'), + // require.resolve(__dirname, './apps/timelion'), + // require.resolve(__dirname, './apps/upgrade_assistant'), + // require.resolve(__dirname, './apps/code'), + // require.resolve(__dirname, './apps/visualize'), + // require.resolve(__dirname, './apps/uptime'), + // require.resolve(__dirname, './apps/saved_objects_management'), + // require.resolve(__dirname, './apps/dev_tools'), + // require.resolve(__dirname, './apps/apm'), + // require.resolve(__dirname, './apps/index_patterns'), + // require.resolve(__dirname, './apps/index_management'), + // require.resolve(__dirname, './apps/index_lifecycle_management'), + // require.resolve(__dirname, './apps/snapshot_restore'), + // require.resolve(__dirname, './apps/cross_cluster_replication'), + // require.resolve(__dirname, './apps/remote_clusters'), + // // This license_management file must be last because it is destructive. + // require.resolve(__dirname, './apps/license_management'), + // ], + + browser: { + type: 'ie', + }, + + junit: { + reportName: 'Internet Explorer UI Functional X-Pack Tests' + }, + + uiSettings: { + defaults: { + 'accessibility:disableAnimations': true, + 'dateFormat:tz': 'UTC', + 'telemetry:optIn': false, + 'state:storeInSessionStorage': true, + }, + }, + + + kbnTestServer: { + ...defaultConfig.get('kbnTestServer'), + serverArgs: [ + ...defaultConfig.get('kbnTestServer.serverArgs'), + '--csp.strict=false', + ], + }, + + + }; +} diff --git a/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/data.json.gz b/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/data.json.gz new file mode 100644 index 0000000000000..8d15ff8ccb022 Binary files /dev/null and b/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/mappings.json b/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/mappings.json new file mode 100644 index 0000000000000..69ffc922ede7d --- /dev/null +++ b/x-pack/test/functional/es_archives/infra/8.0.0/ml_anomalies_partitioned_log_rate/mappings.json @@ -0,0 +1,513 @@ +{ + "type": "index", + "value": { + "aliases": { + ".ml-anomalies-.write-kibana-logs-ui-default-default-log-entry-rate": { + }, + ".ml-anomalies-kibana-logs-ui-default-default-log-entry-rate": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "kibana-logs-ui-default-default-log-entry-rate" + } + } + } + } + }, + "index": ".ml-anomalies-shared", + "mappings": { + "_meta": { + "version": "8.0.0" + }, + "dynamic_templates": [ + { + "strings_as_keywords": { + "mapping": { + "type": "keyword" + }, + "match": "*" + } + } + ], + "properties": { + "actual": { + "type": "double" + }, + "all_field_values": { + "analyzer": "whitespace", + "type": "text" + }, + "anomaly_score": { + "type": "double" + }, + "average_bucket_processing_time_ms": { + "type": "double" + }, + "bucket_allocation_failures_count": { + "type": "long" + }, + "bucket_count": { + "type": "long" + }, + "bucket_influencers": { + "properties": { + "anomaly_score": { + "type": "double" + }, + "bucket_span": { + "type": "long" + }, + "influencer_field_name": { + "type": "keyword" + }, + "initial_anomaly_score": { + "type": "double" + }, + "is_interim": { + "type": "boolean" + }, + "job_id": { + "type": "keyword" + }, + "probability": { + "type": "double" + }, + "raw_anomaly_score": { + "type": "double" + }, + "result_type": { + "type": "keyword" + }, + "timestamp": { + "type": "date" + } + }, + "type": "nested" + }, + "bucket_span": { + "type": "long" + }, + "by_field_name": { + "type": "keyword" + }, + "by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "category_id": { + "type": "long" + }, + "causes": { + "properties": { + "actual": { + "type": "double" + }, + "by_field_name": { + "type": "keyword" + }, + "by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "correlated_by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "field_name": { + "type": "keyword" + }, + "function": { + "type": "keyword" + }, + "function_description": { + "type": "keyword" + }, + "over_field_name": { + "type": "keyword" + }, + "over_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "partition_field_name": { + "type": "keyword" + }, + "partition_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "probability": { + "type": "double" + }, + "typical": { + "type": "double" + } + }, + "type": "nested" + }, + "description": { + "type": "text" + }, + "detector_index": { + "type": "integer" + }, + "earliest_record_timestamp": { + "type": "date" + }, + "empty_bucket_count": { + "type": "long" + }, + "event": { + "properties": { + "dataset": { + "type": "keyword" + } + } + }, + "event_count": { + "type": "long" + }, + "examples": { + "type": "text" + }, + "exponential_average_bucket_processing_time_ms": { + "type": "double" + }, + "exponential_average_calculation_context": { + "properties": { + "incremental_metric_value_ms": { + "type": "double" + }, + "latest_timestamp": { + "type": "date" + }, + "previous_exponential_average_ms": { + "type": "double" + } + } + }, + "field_name": { + "type": "keyword" + }, + "forecast_create_timestamp": { + "type": "date" + }, + "forecast_end_timestamp": { + "type": "date" + }, + "forecast_expiry_timestamp": { + "type": "date" + }, + "forecast_id": { + "type": "keyword" + }, + "forecast_lower": { + "type": "double" + }, + "forecast_memory_bytes": { + "type": "long" + }, + "forecast_messages": { + "type": "keyword" + }, + "forecast_prediction": { + "type": "double" + }, + "forecast_progress": { + "type": "double" + }, + "forecast_start_timestamp": { + "type": "date" + }, + "forecast_status": { + "type": "keyword" + }, + "forecast_upper": { + "type": "double" + }, + "function": { + "type": "keyword" + }, + "function_description": { + "type": "keyword" + }, + "influencer_field_name": { + "type": "keyword" + }, + "influencer_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "influencer_score": { + "type": "double" + }, + "influencers": { + "properties": { + "influencer_field_name": { + "type": "keyword" + }, + "influencer_field_values": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + } + }, + "type": "nested" + }, + "initial_anomaly_score": { + "type": "double" + }, + "initial_influencer_score": { + "type": "double" + }, + "initial_record_score": { + "type": "double" + }, + "input_bytes": { + "type": "long" + }, + "input_field_count": { + "type": "long" + }, + "input_record_count": { + "type": "long" + }, + "invalid_date_count": { + "type": "long" + }, + "is_interim": { + "type": "boolean" + }, + "job_id": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "last_data_time": { + "type": "date" + }, + "latest_empty_bucket_timestamp": { + "type": "date" + }, + "latest_record_time_stamp": { + "type": "date" + }, + "latest_record_timestamp": { + "type": "date" + }, + "latest_result_time_stamp": { + "type": "date" + }, + "latest_sparse_bucket_timestamp": { + "type": "date" + }, + "log_time": { + "type": "date" + }, + "max_matching_length": { + "type": "long" + }, + "maximum_bucket_processing_time_ms": { + "type": "double" + }, + "memory_status": { + "type": "keyword" + }, + "min_version": { + "type": "keyword" + }, + "minimum_bucket_processing_time_ms": { + "type": "double" + }, + "missing_field_count": { + "type": "long" + }, + "model_bytes": { + "type": "long" + }, + "model_bytes_exceeded": { + "type": "keyword" + }, + "model_bytes_memory_limit": { + "type": "keyword" + }, + "model_feature": { + "type": "keyword" + }, + "model_lower": { + "type": "double" + }, + "model_median": { + "type": "double" + }, + "model_size_stats": { + "properties": { + "bucket_allocation_failures_count": { + "type": "long" + }, + "job_id": { + "type": "keyword" + }, + "log_time": { + "type": "date" + }, + "memory_status": { + "type": "keyword" + }, + "model_bytes": { + "type": "long" + }, + "model_bytes_exceeded": { + "type": "keyword" + }, + "model_bytes_memory_limit": { + "type": "keyword" + }, + "result_type": { + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "total_by_field_count": { + "type": "long" + }, + "total_over_field_count": { + "type": "long" + }, + "total_partition_field_count": { + "type": "long" + } + } + }, + "model_upper": { + "type": "double" + }, + "multi_bucket_impact": { + "type": "double" + }, + "out_of_order_timestamp_count": { + "type": "long" + }, + "over_field_name": { + "type": "keyword" + }, + "over_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "partition_field_name": { + "type": "keyword" + }, + "partition_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "probability": { + "type": "double" + }, + "processed_field_count": { + "type": "long" + }, + "processed_record_count": { + "type": "long" + }, + "processing_time_ms": { + "type": "long" + }, + "quantiles": { + "enabled": false, + "type": "object" + }, + "raw_anomaly_score": { + "type": "double" + }, + "record_score": { + "type": "double" + }, + "regex": { + "type": "keyword" + }, + "result_type": { + "type": "keyword" + }, + "retain": { + "type": "boolean" + }, + "scheduled_events": { + "type": "keyword" + }, + "search_count": { + "type": "long" + }, + "snapshot_doc_count": { + "type": "integer" + }, + "snapshot_id": { + "type": "keyword" + }, + "sparse_bucket_count": { + "type": "long" + }, + "terms": { + "type": "text" + }, + "timestamp": { + "type": "date" + }, + "total_by_field_count": { + "type": "long" + }, + "total_over_field_count": { + "type": "long" + }, + "total_partition_field_count": { + "type": "long" + }, + "total_search_time_ms": { + "type": "double" + }, + "typical": { + "type": "double" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1", + "query": { + "default_field": "all_field_values" + }, + "translog": { + "durability": "async" + }, + "unassigned": { + "node_left": { + "delayed_timeout": "1m" + } + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/ml/farequote/data.json.gz b/x-pack/test/functional/es_archives/ml/farequote/data.json.gz index 6d84ef28be658..17cf75a4624f7 100644 Binary files a/x-pack/test/functional/es_archives/ml/farequote/data.json.gz and b/x-pack/test/functional/es_archives/ml/farequote/data.json.gz differ diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index 88501aad57b4a..67b2497cc91e3 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -19,7 +19,7 @@ export function InfraHomePageProvider({ getService }: FtrProviderContext) { const datePickerInput = await find.byCssSelector( `${testSubjSelector('waffleDatePicker')} .euiDatePicker.euiFieldText` ); - await datePickerInput.type(Array(30).fill(browser.keys.BACK_SPACE)); + await datePickerInput.clearValueWithKeyboard({ charByChar: true }); await datePickerInput.type([time, browser.keys.RETURN]); }, diff --git a/x-pack/test/functional/services/machine_learning/job_source_selection.ts b/x-pack/test/functional/services/machine_learning/job_source_selection.ts index 81f2de3a47e79..a418ad9561f6f 100644 --- a/x-pack/test/functional/services/machine_learning/job_source_selection.ts +++ b/x-pack/test/functional/services/machine_learning/job_source_selection.ts @@ -10,8 +10,20 @@ export function MachineLearningJobSourceSelectionProvider({ getService }: FtrPro const testSubjects = getService('testSubjects'); return { - async selectSourceIndexPattern(indexPattern: string) { - await testSubjects.clickWhenNotDisabled(`savedObjectTitle${indexPattern}`); + async assertSourceListContainsEntry(sourceName: string) { + await testSubjects.existOrFail(`savedObjectTitle${sourceName}`); + }, + + async filterSourceSelection(sourceName: string) { + await testSubjects.setValue('savedObjectFinderSearchInput', sourceName, { + withKeyboard: true, + }); + await this.assertSourceListContainsEntry(sourceName); + }, + + async selectSource(sourceName: string) { + await this.filterSourceSelection(sourceName); + await testSubjects.clickWhenNotDisabled(`savedObjectTitle${sourceName}`); await testSubjects.existOrFail('mlPageJobTypeSelection'); }, }; diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index 5c0b59674bded..30d830cd6c919 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -9,6 +9,8 @@ import expect from '@kbn/expect'; import url from 'url'; import supertestAsPromised from 'supertest-as-promised'; +const { task: { properties: taskManagerIndexMapping } } = require('../../../../legacy/plugins/task_manager/mappings.json'); + export default function ({ getService }) { const es = getService('es'); const log = getService('log'); @@ -30,6 +32,15 @@ export default function ({ getService }) { q: 'type:task', refresh: true, }); + } else { + await es.indices.create({ + index: testHistoryIndex, + body: { + mappings: { + properties: taskManagerIndexMapping + }, + }, + }); } }); diff --git a/x-pack/test/plugin_api_perf/README.md b/x-pack/test/plugin_api_perf/README.md index 034374e196dca..f47a2aeb7878a 100644 --- a/x-pack/test/plugin_api_perf/README.md +++ b/x-pack/test/plugin_api_perf/README.md @@ -50,4 +50,28 @@ After the test runs you should get the following output: If you look at the debug output you'll see a summary of how the test went: You'll see the average number of tasks executed per second, over a period of each 5 second window (meaning we calculate the running average based on a sliding window of 5 seconds). -You'll also see the average time it takes from the moment a task's scheduled time was reached, until Task Manager picked it up for execution. \ No newline at end of file +You'll also see the average time it takes from the moment a task's scheduled time was reached, until Task Manager picked it up for execution. + + +# Running the test against multiple Kibana and a single Elasticsearch +This is not a clean and ideal way of running this test, but it is a workaround that's worth understanding. + +## Test Description +The idea is that we would like to test performance of running multiple Kibana instances side by side, both pointing at the same Elasticsearch cluster. + +This is needed in order to verify that the distributed nature of Kibana doesn't introduce issues or break assumptions in our developed solutions. + +The challenge is that the _plugin_ used to create the Perf test is exposed in the FTS, but not in a standard Kibana build. + +Running two Kibana in FTS side by side is actually very tricky, so below is a step by step method for achieving this. +Ideally we can clean this up and make it easier and less hacky in the future, but for now, this documents how this can be achieved. + +## Method +1. You need two cloned repos of Kibana, so clone a second Kibana of your personal form along side your existing clone. Personally I have two co-located Kibana folders (`./elastic/kibana` and `./elastic/_kibana`, where the first is my working clone and the other is never used for actual dev work, but that's just me -GM). +1. You can run the FTS in the main clone of your fork by running `node scripts/functional_tests_server.js --config=test/plugin_api_perf/config.js` in the `x-pack` folder. +1. Once you've began running the default FTS, you want your second FTS to run such that it is referencing the Elasticsearch instance started by that first FTS. You achieve this by exporting a `TEST_ES_URL` Environment variable that points at it. By default, you should be able to run this: `export TEST_ES_URL=http://elastic:changeme@localhost:9220`. Do this in a terminal window opened in your **second** clone of Kibana (in my case, the `./elastic/_kibana` folder). +1. One issue I encountered with FTS is that I can't tell it _not to start its own ES instance at all_. To achieve this, in `packages/kbn-test/src/functional_tests/tasks.js` you need to comment out the line that starts up its own ES (`const es = await runElasticsearch({ config, options: opts });` [line 85] and `await es.cleanup();` shortly after) +1. Next you want each instance of Kibana to run with its own UUID as that is used to identify each Kibana's owned tasks. In the file `x-pack/test/functional/config.js` simple change the uuid on the line `--server.uuid=` into any random UUID. +1. Now that you've made these changes you can kick off your second Kibana FTS by running ths following in the second clone's `x-pack` folder: `TEST_KIBANA_PORT=5621 node scripts/functional_tests_server.js --config=test/plugin_api_perf/config.js`. This runs Kibana on a different port than the first FTS (`5621` instead of `5620`). +1. With two FTS Kibana running and both pointing at the same Elasticsearch. Now, you can run the actual perf test by running `node scripts/functional_test_runner.js --config=test/plugin_api_perf/config.js` in a third terminal + diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js index abad95729dcf7..0547069dfb469 100644 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js @@ -62,12 +62,32 @@ export default function TaskManagerPerformanceAPI(kibana) { createTaskRunner: ({ taskInstance }) => { return { async run() { - const { state } = taskInstance; - const leadTime = Date.now() - taskInstance.runAt; + const { params, state } = taskInstance; + + const runAt = millisecondsFromNow(5000); + const now = Date.now(); + const leadTime = now - taskInstance.runAt; performanceState.leadTimeQueue.push(leadTime); + + const counter = (state.counter ? 1 + state.counter : 1); + + const stateUpdated = { + ...state, + counter + }; + + if(params.trackExecutionTimeline) { + stateUpdated.timeline = stateUpdated.timeline || []; + stateUpdated.timeline.push({ + owner: taskInstance.owner.split('-')[0], + counter, + leadTime, + ranAt: now + }); + } return { - state, - runAt: millisecondsFromNow(1000), + state: stateUpdated, + runAt, }; }, }; diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js index 316c434b33c43..b9fe788093d11 100644 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js @@ -18,11 +18,12 @@ export function initRoutes(server, performanceState) { payload: Joi.object({ tasksToSpawn: Joi.number().required(), durationInSeconds: Joi.number().required(), + trackExecutionTimeline: Joi.boolean().default(false).required(), }), }, }, async handler(request) { - const { tasksToSpawn, durationInSeconds } = request.payload; + const { tasksToSpawn, durationInSeconds, trackExecutionTimeline } = request.payload; const tasks = []; for (let taskIndex = 0; taskIndex < tasksToSpawn; taskIndex++) { @@ -30,7 +31,7 @@ export function initRoutes(server, performanceState) { await taskManager.schedule( { taskType: 'performanceTestTask', - params: { taskIndex }, + params: { taskIndex, trackExecutionTimeline }, scope: [scope], }, { request } diff --git a/x-pack/test/plugin_api_perf/test_suites/task_manager/task_manager_perf_integration.ts b/x-pack/test/plugin_api_perf/test_suites/task_manager/task_manager_perf_integration.ts index 292a96baacd98..e8dbf7c509287 100644 --- a/x-pack/test/plugin_api_perf/test_suites/task_manager/task_manager_perf_integration.ts +++ b/x-pack/test/plugin_api_perf/test_suites/task_manager/task_manager_perf_integration.ts @@ -15,7 +15,7 @@ export default function({ getService }: { getService: (service: string) => any } const { runningAverageTasks, runningAverageLeadTime } = await supertest .post('/api/perf_tasks') .set('kbn-xsrf', 'xxx') - .send({ tasksToSpawn: 10, durationInSeconds: 60 }) + .send({ tasksToSpawn: 20, trackExecutionTimeline: true, durationInSeconds: 60 }) .expect(200) .then((response: any) => response.body); diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index d0452ae20a694..82b2131a0a855 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -6,7 +6,8 @@ "legacy/server/**/*", "legacy/plugins/**/*", "plugins/**/*", - "test_utils/**/*" + "test_utils/**/*", + "tasks/**/*" ], "exclude": [ "test/**/*", diff --git a/yarn.lock b/yarn.lock index 06c96a65d2536..91fcb22ee1f53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1106,10 +1106,10 @@ parse-gitignore "1.0.1" vscode-languageserver "^5.2.1" -"@elastic/elasticsearch@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.3.0.tgz#d62508cc03e91dd0676914a50af6500b45bfb199" - integrity sha512-CA8V4txIS+BPZg37ZVtOi5mN2xnXYAeQUCvgkjdtc2CzTd5pJrjdPzdmaDDATNc8nhlHMrqxMZZmpKD3OUkjAg== +"@elastic/elasticsearch@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.4.0.tgz#57f4066acf25e9d4e9b4f6376088433aae6f25d4" + integrity sha512-HpEKHH6mHQRvea3lw4NNJw9ZUS1KmkpwWKHucaHi1svDn+/fEAwY0wD8egL1vZJo4ZmWfCQMjVqGL+Hoy1HYRw== dependencies: debug "^4.1.1" decompress-response "^4.2.0" @@ -3284,6 +3284,11 @@ dependencies: "@types/node" "*" +"@types/fancy-log@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.1.tgz#dd94fbc8c2e2ab8ab402ca8d04bb8c34965f0696" + integrity sha512-31Dt9JaGfHretvwVxCBrCFL5iC9MQ3zOXpu+8C4qzW0cxc5rJJVGxB5c/vZ+wmeTk/JjPz/D0gv8BZ+Ip6iCqQ== + "@types/fetch-mock@^7.3.1": version "7.3.1" resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-7.3.1.tgz#df7421e8bcb351b430bfbfa5c52bb353826ac94f" @@ -3318,11 +3323,24 @@ resolved "https://registry.yarnpkg.com/@types/getopts/-/getopts-2.0.1.tgz#b7e5478fe7571838b45aff736a59ab69b8bcda18" integrity sha512-JsQJHtzLYKunMz7acYOX6x5IJ/42CsjjHFfLCmis1Hn/qFoD/y0kJFUIAg8HoDigQpKUcWj55d8rxZQBnvz1Pw== +"@types/getos@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/getos/-/getos-3.0.0.tgz#582c758e99e9d634f31f471faf7ce59cf1c39a71" + integrity sha512-g5O9kykBPMaK5USwU+zM5AyXaztqbvHjSQ7HaBjqgO3f5lKGChkRhLP58Z/Nrr4RBGNNPrBcJkWZwnmbmi9YjQ== + "@types/git-url-parse@^9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@types/git-url-parse/-/git-url-parse-9.0.0.tgz#aac1315a44fa4ed5a52c3820f6c3c2fb79cbd12d" integrity sha512-kA2RxBT/r/ZuDDKwMl+vFWn1Z0lfm1/Ik6Qb91wnSzyzCDa/fkM8gIOq6ruB7xfr37n6Mj5dyivileUVKsidlg== +"@types/glob-stream@*": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc" + integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg== + dependencies: + "@types/glob" "*" + "@types/node" "*" + "@types/glob@*", "@types/glob@^5.0.35": version "5.0.35" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.35.tgz#1ae151c802cece940443b5ac246925c85189f32a" @@ -3361,6 +3379,15 @@ resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1" integrity sha512-B4yel4ro2nTb3v0pYO8vO6SjgvFJSrwUY+IO6TUSLdOSB+gQFslylrhRCHxvXMIhxB71mv5PEE9dAX+24S8sew== +"@types/gulp@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/gulp/-/gulp-4.0.6.tgz#68fe0e1f0ff3657cfca46fb564806b744a1bf899" + integrity sha512-0E8/iV/7FKWyQWSmi7jnUvgXXgaw+pfAzEB06Xu+l0iXVJppLbpOye5z7E2klw5akXd+8kPtYuk65YBcZPM4ow== + dependencies: + "@types/undertaker" "*" + "@types/vinyl-fs" "*" + chokidar "^2.1.2" + "@types/hapi-auth-cookie@^9.1.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@types/hapi-auth-cookie/-/hapi-auth-cookie-9.1.0.tgz#cbcd2236b7d429bd0632a8cc45cfd355fdd7e7a2" @@ -3532,7 +3559,7 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA== -"@types/jsonwebtoken@^7.2.7": +"@types/jsonwebtoken@^7.2.8": version "7.2.8" resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-7.2.8.tgz#8d199dab4ddb5bba3234f8311b804d2027af2b3a" integrity sha512-XENN3YzEB8D6TiUww0O8SRznzy1v+77lH7UmuN54xq/IHIsyWjWOzZuFFTtoiRuaE782uAoRwBe/wwow+vQXZw== @@ -3791,10 +3818,10 @@ resolved "https://registry.yarnpkg.com/@types/proper-lockfile/-/proper-lockfile-3.0.1.tgz#dd770a2abce3adbcce3bd1ed892ce2f5f17fbc86" integrity sha512-ODOjqxmaNs0Zkij+BJovsNJRSX7BJrr681o8ZnNTNIcTermvVFzLpz/XFtfg3vNrlPVTJY1l4e9h2LvHoxC1lg== -"@types/puppeteer@^1.19.0": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.19.0.tgz#59f0050bae019cee7c3af2bb840a25892a3078b6" - integrity sha512-Db9LWOuTm2bR/qgPE7PQCmnsCQ6flHdULuIDWTks8YdQ/SGHKg5WGWG54gl0734NDKCTF5MbqAp2qWuvBiyQ3Q== +"@types/puppeteer@^1.20.1": + version "1.20.1" + resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.20.1.tgz#0aba5ae3d290daa91cd3ba9f66ba5e9fba3499cc" + integrity sha512-F91CqYDHETg3pQfIPNBNZKmi7R1xS1y4yycOYX7o6Xk16KF+IV+9LqTmVuG+FIxw/53/JEy94zKjjGjg92V6bg== dependencies: "@types/node" "*" @@ -3959,10 +3986,10 @@ "@types/glob" "*" "@types/node" "*" -"@types/selenium-webdriver@^3.0.16": - version "3.0.16" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a" - integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA== +"@types/selenium-webdriver@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.3.tgz#388f12c464cc1fff5d4c84cb372f19b9ab9b5c81" + integrity sha512-aMKIG1IKwV9/gjhm9uICjvmy4s2SL/bF9fE2WEgLhfdrTLKSIsDMt9M2pTqhZlxllgQPa+EUddtkx4YFTSjadw== "@types/semver@^5.5.0": version "5.5.0" @@ -4095,6 +4122,18 @@ resolved "https://registry.yarnpkg.com/@types/type-detect/-/type-detect-4.0.1.tgz#3b0f5ac82ea630090cbf57c57a1bf5a63a29b9b6" integrity sha512-0+S1S9Iq0oJ9w9IaBC5W/z1WsPNDUIAJG+THGmqR4vUAxUPCzIY+dApTvyGsaBUWjafTDL0Dg8Z9+iRuk3/BQA== +"@types/undertaker-registry@*": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz#4306d4a03d7acedb974b66530832b90729e1d1da" + integrity sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ== + +"@types/undertaker@*": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/undertaker/-/undertaker-1.2.2.tgz#927da24d0d3279830af96386862b035e040ead74" + integrity sha512-j4iepCSuY2JGW/hShVtUBagic0klYNFIXP7VweavnYnNC2EjiKxJFeaS9uaJmAT0ty9sQSqTS1aagWMZMV0HyA== + dependencies: + "@types/undertaker-registry" "*" + "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" @@ -4129,6 +4168,22 @@ "@types/unist" "*" "@types/vfile-message" "*" +"@types/vinyl-fs@*", "@types/vinyl-fs@^2.4.11": + version "2.4.11" + resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206" + integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA== + dependencies: + "@types/glob-stream" "*" + "@types/node" "*" + "@types/vinyl" "*" + +"@types/vinyl@*": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.3.tgz#80a6ce362ab5b32a0c98e860748a31bce9bff0de" + integrity sha512-hrT6xg16CWSmndZqOTJ6BGIn2abKyTw0B58bI+7ioUoj3Sma6u8ftZ1DTI2yCaJamOVGLOnQWiPH3a74+EaqTA== + dependencies: + "@types/node" "*" + "@types/webpack-env@*": version "1.13.9" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.9.tgz#a67287861c928ebf4159a908d1fb1a2a34d4097a" @@ -4557,6 +4612,11 @@ adm-zip@0.4.11: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a" integrity sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA== +adm-zip@^0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" + integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== + affine-hull@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/affine-hull/-/affine-hull-1.0.0.tgz#763ff1d38d063ceb7e272f17ee4d7bbcaf905c5d" @@ -4840,13 +4900,6 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.1.tgz#9638047e4213f3428a11944a7d4b31cba0a3ff95" integrity sha512-Xt+zb6nqgvV9SWAVp0EG3lRsHcbq5DDgqjPPz6pwgtj6RKz65zGXMNa82oJfOSBA/to6GmRP7Dr+6o+kbApTzQ== -ansi-cyan@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" - integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= - dependencies: - ansi-wrap "0.1.0" - ansi-escapes@^1.0.0, ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -4893,13 +4946,6 @@ ansi-html@0.0.7: resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= -ansi-red@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= - dependencies: - ansi-wrap "0.1.0" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -4997,10 +5043,10 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.0.2.tgz#ddb3a8495d44875423af7b919aace11e91732a41" - integrity sha512-rUe9SxpRQlVg4EM8It7JMNWWYHAirTPpbTuvaSKybb5IejNgWB3PGBBX9rrPKDx2pM/p3Wh+7+ASaWRyyAbxmQ== +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -5290,28 +5336,29 @@ aria-query@^3.0.0: ast-types-flow "0.0.7" commander "^2.11.0" -arr-diff@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" - integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= - dependencies: - arr-flatten "^1.0.1" - array-slice "^0.2.3" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= +arr-filter@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee" + integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4= + dependencies: + make-iterator "^1.0.0" + arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== -arr-union@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" - integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= +arr-map@^2.0.0, arr-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4" + integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ= + dependencies: + make-iterator "^1.0.0" arr-union@^3.1.0: version "3.1.0" @@ -5328,7 +5375,7 @@ array-differ@^3.0.0: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== -array-each@^1.0.1: +array-each@^1.0.0, array-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= @@ -5381,6 +5428,21 @@ array-includes@^3.0.3: define-properties "^1.1.2" es-abstract "^1.7.0" +array-initial@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795" + integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U= + dependencies: + array-slice "^1.0.0" + is-number "^4.0.0" + +array-last@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336" + integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== + dependencies: + is-number "^4.0.0" + array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" @@ -5411,6 +5473,15 @@ array-slice@^1.0.0: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + array-union@^1.0.1, array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -5423,7 +5494,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.0, array-uniq@^1.0.1, array-uniq@^1.0.2: +array-uniq@^1.0.0, array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= @@ -5581,6 +5652,16 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async-done@^1.2.0, async-done@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2" + integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.2" + process-nextick-args "^2.0.0" + stream-exhaust "^1.0.1" + async-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -5608,6 +5689,13 @@ async-retry@^1.2.3: dependencies: retry "0.12.0" +async-settle@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b" + integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs= + dependencies: + async-done "^1.2.2" + async.queue@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/async.queue/-/async.queue-0.5.2.tgz#8d5d90812e1481066bc0904e8cc1712b17c3bd7c" @@ -6312,6 +6400,21 @@ babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== +bach@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" + integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA= + dependencies: + arr-filter "^1.1.1" + arr-flatten "^1.0.1" + arr-map "^2.0.0" + array-each "^1.0.0" + array-initial "^1.0.0" + array-last "^1.1.1" + async-done "^1.2.2" + async-settle "^1.0.0" + now-and-later "^2.0.0" + backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -6410,11 +6513,6 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= - before-after-hook@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.1.0.tgz#83165e15a59460d13702cb8febd6a1807896db5a" @@ -6713,7 +6811,7 @@ boxen@^3.0.0: type-fest "^0.3.0" widest-line "^2.0.0" -brace-expansion@^1.0.0, brace-expansion@^1.1.7: +brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" integrity sha1-wHshHHyVLsH479Uad+8NHTmQopI= @@ -6749,7 +6847,7 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1, braces@^3.0.2: +braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -7633,25 +7731,25 @@ chokidar@2.1.2, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.7" -chokidar@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681" - integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA== - dependencies: - anymatch "^3.0.1" - braces "^3.0.2" - glob-parent "^5.0.0" - is-binary-path "^2.1.0" - is-glob "^4.0.1" - normalize-path "^3.0.0" - readdirp "^3.1.1" +chokidar@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.1.tgz#4634772a1924512d990d4505957bf3a510611387" + integrity sha512-/j5PPkb5Feyps9e+jo07jUZGvkB5Aj953NrI4s8xSVScrAo/RHeILrtdb4uzR7N6aaFFxxJ+gt8mA8HfNpw76w== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.1.3" optionalDependencies: - fsevents "^2.0.6" + fsevents "~2.1.0" -chokidar@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" - integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== +chokidar@^2.0.0, chokidar@^2.1.2, chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== dependencies: anymatch "^2.0.0" async-each "^1.0.1" @@ -8007,11 +8105,6 @@ clone-stats@^1.0.0: resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= -clone@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - integrity sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8= - clone@^1.0.0, clone@^1.0.1, clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -8085,6 +8178,15 @@ collapse-white-space@^1.0.2: resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.3.tgz#4b906f670e5a963a87b76b0e1689643341b6023c" integrity sha1-S5BvZw5aljqHt2sOFolkM0G2Ajw= +collection-map@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c" + integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw= + dependencies: + arr-map "^2.0.2" + for-own "^1.0.0" + make-iterator "^1.0.0" + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -8322,21 +8424,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.6.1: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== +concat-stream@1.6.0, concat-stream@^1.4.7, concat-stream@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= dependencies: - buffer-from "^1.0.0" inherits "^2.0.3" readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@^1.4.7, concat-stream@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= +concat-stream@1.6.2, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: + buffer-from "^1.0.0" inherits "^2.0.3" readable-stream "^2.2.2" typedarray "^0.0.6" @@ -8369,6 +8471,14 @@ config-chain@^1.1.11: ini "^1.3.4" proto-list "~1.2.1" +config-chain@~1.1.8: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + configstore@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" @@ -8569,6 +8679,14 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-props@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.4.tgz#93bb1cadfafd31da5bb8a9d4b41f471ec3a72dfe" + integrity sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== + dependencies: + each-props "^1.3.0" + is-plain-object "^2.0.1" + copy-to-clipboard@^3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9" @@ -9701,6 +9819,13 @@ deepmerge@^4.0.0: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09" integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -9716,12 +9841,17 @@ default-require-extensions@^2.0.0: dependencies: strip-bom "^3.0.0" +default-resolution@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" + integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= + default-uid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/default-uid/-/default-uid-1.0.0.tgz#fcefa9df9f5ac40c8916d912dd1fe1146aa3c59e" integrity sha1-/O+p359axAyJFtkS3R/hFGqjxZ4= -defaults@^1.0.0, defaults@^1.0.3: +defaults@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= @@ -9848,11 +9978,6 @@ deprecated-decorator@^0.1.6: resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" integrity sha1-AJZjF7ehL+kvPMgx91g68ym4bDc= -deprecated@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" - integrity sha1-+cmvVGSvoeepcUWKi97yqpTVuxk= - deprecation@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-1.0.1.tgz#2df79b79005752180816b7b6e079cbd80490d711" @@ -10303,11 +10428,6 @@ dotenv-webpack@^1.7.0: dependencies: dotenv-defaults "^1.0.2" -dotenv@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-2.0.0.tgz#bd759c357aaa70365e01c96b7b0bec08a6e0d949" - integrity sha1-vXWcNXqqcDZeAclrewvsCKbg2Uk= - dotenv@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" @@ -10353,13 +10473,6 @@ dragselect@1.13.1: resolved "https://registry.yarnpkg.com/dragselect/-/dragselect-1.13.1.tgz#aa4166e1164b51ed5ee0cd89e0c5310a9c35be6a" integrity sha512-spfUz6/sNnlY4fF/OxPBwaKLa5hVz6V+fq5XhVuD+h47RAkA75TMkfvr4AoWUh5Ufq3V1oIAbfu+sjc9QbewoA== -duplexer2@0.0.2, duplexer2@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= - dependencies: - readable-stream "~1.1.9" - duplexer2@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" @@ -10367,6 +10480,13 @@ duplexer2@^0.1.4: dependencies: readable-stream "^2.0.2" +duplexer2@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= + dependencies: + readable-stream "~1.1.9" + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -10405,6 +10525,14 @@ each-async@^1.1.1: onetime "^1.0.0" set-immediate-shim "^1.0.0" +each-props@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" + integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== + dependencies: + is-plain-object "^2.0.1" + object.defaults "^1.1.0" + eachr@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484" @@ -10438,6 +10566,13 @@ ecdsa-sig-formatter@1.0.10: dependencies: safe-buffer "^5.0.1" +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + editions@^1.1.1, editions@^1.3.3, editions@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" @@ -10594,13 +10729,6 @@ end-of-stream@^1.4.1: dependencies: once "^1.4.0" -end-of-stream@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf" - integrity sha1-jhdyBsPICDfYVjLouTWd/osvbq8= - dependencies: - once "~1.3.0" - engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" @@ -11739,13 +11867,6 @@ express@^4.17.0, express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" -extend-shallow@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" - integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= - dependencies: - kind-of "^1.1.0" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -11858,6 +11979,16 @@ extract-stack@^1.0.0: resolved "https://registry.yarnpkg.com/extract-stack/-/extract-stack-1.0.0.tgz#b97acaf9441eea2332529624b732fc5a1c8165fa" integrity sha1-uXrK+UQe6iMyUpYktzL8WhyBZfo= +extract-zip@1.6.6: + version "1.6.6" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" + integrity sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw= + dependencies: + concat-stream "1.6.0" + debug "2.6.9" + mkdirp "0.5.0" + yauzl "2.4.1" + extract-zip@1.6.7, extract-zip@^1.6.6, extract-zip@^1.6.7: version "1.6.7" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" @@ -11898,7 +12029,7 @@ falafel@^2.1.0: isarray "0.0.1" object-keys "^1.0.6" -fancy-log@^1.1.0, fancy-log@^1.3.2: +fancy-log@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" integrity sha1-9BEl49hPLn2JpD0G2VjI94vha+E= @@ -12307,11 +12438,6 @@ find-cache-dir@^3.0.0: make-dir "^3.0.0" pkg-dir "^4.1.0" -find-index@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" - integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= - find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -12362,7 +12488,7 @@ find@^0.3.0: dependencies: traverse-chain "~0.1.0" -findup-sync@3.0.0: +findup-sync@3.0.0, findup-sync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== @@ -12405,11 +12531,6 @@ finity@^0.5.4: resolved "https://registry.yarnpkg.com/finity/-/finity-0.5.4.tgz#f2a8a9198e8286467328ec32c8bfcc19a2229c11" integrity sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA== -first-chunk-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" - integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04= - first-chunk-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" @@ -12835,10 +12956,10 @@ fsevents@^1.2.7: nan "^2.9.2" node-pre-gyp "^0.10.0" -fsevents@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" - integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== +fsevents@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.0.tgz#ce1a5f9ac71c6d75278b0c5bd236d7dfece4cbaa" + integrity sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ== fstream@^1.0.0: version "1.0.11" @@ -12927,13 +13048,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gaze@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f" - integrity sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8= - dependencies: - globule "~0.1.0" - gaze@^1.0.0, gaze@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" @@ -13086,7 +13200,7 @@ get-stream@^4.0.0: dependencies: pump "^3.0.0" -get-stream@^5.0.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== @@ -13219,17 +13333,12 @@ glob-parent@^5.0.0: dependencies: is-glob "^4.0.1" -glob-stream@^3.1.5: - version "3.1.18" - resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b" - integrity sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs= +glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== dependencies: - glob "^4.3.1" - glob2base "^0.0.12" - minimatch "^2.0.1" - ordered-read-streams "^0.1.0" - through2 "^0.6.1" - unique-stream "^1.0.0" + is-glob "^4.0.1" glob-stream@^6.1.0: version "6.1.0" @@ -13257,19 +13366,17 @@ glob-to-regexp@^0.4.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.0.tgz#49bd677b1671022bd10921c3788f23cdebf9c7e6" integrity sha512-fyPCII4vn9Gvjq2U/oDAfP433aiE64cyP/CJjRJcpVGjqqNdioUYn9+r0cSzT1XPwmGAHuTT7iv+rQT8u/YHKQ== -glob-watcher@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b" - integrity sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs= - dependencies: - gaze "^0.5.1" - -glob2base@^0.0.12: - version "0.0.12" - resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" - integrity sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY= +glob-watcher@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.3.tgz#88a8abf1c4d131eb93928994bc4a593c2e5dd626" + integrity sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg== dependencies: - find-index "^0.1.1" + anymatch "^2.0.0" + async-done "^1.2.0" + chokidar "^2.0.0" + is-negated-glob "^1.0.0" + just-debounce "^1.0.0" + object.defaults "^1.1.0" glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: version "7.1.3" @@ -13295,16 +13402,6 @@ glob@7.1.4, glob@^7.1.4, glob@~7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^4.3.1: - version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" - integrity sha1-xstz0yJsHv7wTePFbQEvAzd+4V8= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - glob@^5.0.15, glob@~5.0.0: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -13327,15 +13424,6 @@ glob@^6.0.1, glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@~3.1.21: - version "3.1.21" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" - integrity sha1-0p4KBV3qUTj00H7UDomC6DwgZs0= - dependencies: - graceful-fs "~1.2.0" - inherits "1" - minimatch "~0.2.11" - glob@~7.0.0: version "7.0.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" @@ -13544,15 +13632,6 @@ globule@^1.0.0: lodash "~4.17.10" minimatch "~3.0.2" -globule@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" - integrity sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU= - dependencies: - glob "~3.1.21" - lodash "~1.0.1" - minimatch "~0.2.11" - glogg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" @@ -13701,13 +13780,6 @@ graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, g resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -graceful-fs@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg= - dependencies: - natives "^1.1.0" - graceful-fs@^4.1.15, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -13718,10 +13790,10 @@ graceful-fs@^4.2.0, graceful-fs@^4.2.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== -graceful-fs@~1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= +graceful-fs@~1.1: + version "1.1.14" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.1.14.tgz#07078db5f6377f6321fceaaedf497de124dc9465" + integrity sha1-BweNtfY3f2Mh/Oqu30l94STclGU= "graceful-readlink@>= 1.0.0": version "1.0.1" @@ -14084,10 +14156,34 @@ gulp-babel@^8.0.0: through2 "^2.0.0" vinyl-sourcemaps-apply "^0.2.0" -gulp-mocha@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/gulp-mocha/-/gulp-mocha-7.0.1.tgz#cd29f2fc214a8c08c7d96bf13927d539385a856d" - integrity sha512-LYBEWdOw52kvP+si91iR00LYX9iKXLTBjcKh9b3ChHvVmKtpoITjeRFslPEzDubEk+z6VI1ONEwn9ABqW9/tig== +gulp-cli@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.2.0.tgz#5533126eeb7fe415a7e3e84a297d334d5cf70ebc" + integrity sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA== + dependencies: + ansi-colors "^1.0.1" + archy "^1.0.0" + array-sort "^1.0.0" + color-support "^1.1.3" + concat-stream "^1.6.0" + copy-props "^2.0.1" + fancy-log "^1.3.2" + gulplog "^1.0.0" + interpret "^1.1.0" + isobject "^3.0.1" + liftoff "^3.1.0" + matchdep "^2.0.0" + mute-stdout "^1.0.0" + pretty-hrtime "^1.0.0" + replace-homedir "^1.0.0" + semver-greatest-satisfied-range "^1.1.0" + v8flags "^3.0.1" + yargs "^7.1.0" + +gulp-mocha@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/gulp-mocha/-/gulp-mocha-7.0.2.tgz#c7e13d133b3fde96d777e877f90b46225255e408" + integrity sha512-ZXBGN60TXYnFhttr19mfZBOtlHYGx9SvCSc+Kr/m2cMIGloUe176HBPwvPqlakPuQgeTGVRS47NmcdZUereKMQ== dependencies: dargs "^7.0.0" execa "^2.0.4" @@ -14125,59 +14221,26 @@ gulp-sourcemaps@2.6.5: strip-bom-string "1.X" through2 "2.X" -gulp-util@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulp-zip@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/gulp-zip/-/gulp-zip-4.2.0.tgz#e25e738c41ad0795ad853d1d8aeb1744d2a4ca82" - integrity sha512-I+697f6jf+PncdTrqfuwoauxgnLG1yHRg3vlmvDgmJuEnlEHy4meBktJ/oHgfyg4tp6X25wuZqUOraVeVg97wQ== +gulp-zip@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gulp-zip/-/gulp-zip-5.0.1.tgz#0dba5094901b0d91bcc8b53b3f6ff797c0f2002d" + integrity sha512-M/IWLh9RvOpuofDZkgDirtiyz9J3yIqnDOJ3muzk2D/XnZ1ruqPlPLRIpXnl/aZU+xXwKPdOIxjRzkUcVEQyZQ== dependencies: - get-stream "^3.0.0" - plugin-error "^0.1.2" - through2 "^2.0.1" + get-stream "^5.1.0" + plugin-error "^1.0.1" + through2 "^3.0.1" vinyl "^2.1.0" - yazl "^2.1.0" + yazl "^2.5.1" -gulp@3.9.1: - version "3.9.1" - resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4" - integrity sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ= +gulp@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa" + integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA== dependencies: - archy "^1.0.0" - chalk "^1.0.0" - deprecated "^0.0.1" - gulp-util "^3.0.0" - interpret "^1.0.0" - liftoff "^2.1.0" - minimist "^1.1.0" - orchestrator "^0.3.0" - pretty-hrtime "^1.0.0" - semver "^4.1.0" - tildify "^1.0.0" - v8flags "^2.0.2" - vinyl-fs "^0.3.0" + glob-watcher "^5.0.3" + gulp-cli "^2.2.0" + undertaker "^1.2.1" + vinyl-fs "^3.0.0" gulplog@^1.0.0: version "1.0.0" @@ -14356,13 +14419,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= - dependencies: - sparkles "^1.0.0" - has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" @@ -14813,7 +14869,7 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-middleware@^0.19.1: +http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== @@ -14946,10 +15002,24 @@ icss-utils@^4.1.0: dependencies: postcss "^7.0.14" -idx@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/idx/-/idx-2.5.2.tgz#4b405c2e6d68d04136e0a368a7ab35b9caa0595f" - integrity sha512-MLoGF4lQU5q/RqJJjRsuid52emu7tPVtSSZaYXsqRvSjvXdBEmIwk2urvbNvPBRU9Ox9I4WYnxiz2GjhU34Lrw== +idx@^2.5.6: + version "2.5.6" + resolved "https://registry.yarnpkg.com/idx/-/idx-2.5.6.tgz#1f824595070100ae9ad585c86db08dc74f83a59d" + integrity sha512-WFXLF7JgPytbMgelpRY46nHz5tyDcedJ76pLV+RJWdb8h33bxFq4bdZau38DhNSzk5eVniBf1K3jwfK+Lb5nYA== + +iedriver@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/iedriver/-/iedriver-3.14.1.tgz#447c49be83c62d3f2f158283d58ccf7b35002be8" + integrity sha512-YyCi703BGK7R37A8QlSe2B87xgwDGGoPqBrlXe4Q68o/MNLJrR53/IpTs6J1+KKk51MLiTbWa57N7P3KZ11tow== + dependencies: + adm-zip "^0.4.13" + extract-zip "1.6.6" + kew "~0.1.7" + md5-file "^1.1.4" + mkdirp "0.3.5" + npmconf "^2.1.3" + request "^2.88.0" + rimraf "~2.0.2" ieee754@^1.1.4: version "1.1.8" @@ -15141,11 +15211,6 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" - integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js= - inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -15156,7 +15221,7 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.2.0, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -15391,7 +15456,7 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" -interpret@1.2.0, interpret@^1.2.0: +interpret@1.2.0, interpret@^1.1.0, interpret@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== @@ -15509,10 +15574,10 @@ irregular-plurals@^1.0.0: resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" integrity sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y= -is-absolute-url@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.1.tgz#e315cbdcbbc3d6789532d591954ac78a0e5049f6" - integrity sha512-c2QjUwuMxLsld90sj3xYzpFYWJtuxkIn1f5ua9RTEYJt/vV2IsM+Py00/6qjV7qExgifUvt7qfyBGBBKm+2iBg== +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== is-absolute@^1.0.0: version "1.0.0" @@ -15573,7 +15638,7 @@ is-binary-path@^2.0.0: dependencies: binary-extensions "^1.0.0" -is-binary-path@^2.1.0: +is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== @@ -15770,7 +15835,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.1: +is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -17133,6 +17198,22 @@ jsonwebtoken@^8.3.0: lodash.once "^4.0.0" ms "^2.1.1" +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -17205,6 +17286,11 @@ jszip@^3.1.5: readable-stream "~2.3.6" set-immediate-shim "~1.0.1" +just-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" + integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= + just-extend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" @@ -17224,6 +17310,15 @@ jwa@^1.1.5: ecdsa-sig-formatter "1.0.10" safe-buffer "^5.0.1" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + jws@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f" @@ -17232,6 +17327,14 @@ jws@^3.1.5: jwa "^1.1.5" safe-buffer "^5.0.1" +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + karma-chrome-launcher@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" @@ -17322,6 +17425,11 @@ kdbush@^3.0.0: resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0" integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== +kew@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.1.7.tgz#0a32a817ff1a9b3b12b8c9bacf4bc4d679af8e72" + integrity sha1-CjKoF/8amzsSuMm6z0vE1nmvjnI= + keymirror@0.1.1, keymirror@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/keymirror/-/keymirror-0.1.1.tgz#918889ea13f8d0a42e7c557250eee713adc95c35" @@ -17339,11 +17447,6 @@ killable@^1.0.1: resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== -kind-of@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" - integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= - kind-of@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" @@ -17418,6 +17521,14 @@ kuler@1.0.x: dependencies: colornames "^1.1.1" +last-run@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b" + integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls= + dependencies: + default-resolution "^2.0.0" + es6-weak-map "^2.0.1" + latest-version@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" @@ -17584,13 +17695,13 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" -liftoff@^2.1.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" - integrity sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew= +liftoff@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" + integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== dependencies: extend "^3.0.0" - findup-sync "^2.0.0" + findup-sync "^3.0.0" fined "^1.0.1" flagged-respawn "^1.0.0" is-plain-object "^2.0.4" @@ -17886,51 +17997,11 @@ lodash-es@^4.17.11, lodash-es@^4.17.4, lodash-es@^4.17.5, lodash-es@^4.2.1: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= - lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= - lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" @@ -17986,13 +18057,6 @@ lodash.difference@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= - dependencies: - lodash._root "^3.0.0" - lodash.escape@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" @@ -18038,16 +18102,6 @@ lodash.intersection@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.intersection/-/lodash.intersection-4.4.0.tgz#0a11ba631d0e95c23c7f2f4cbb9a692ed178e705" integrity sha1-ChG6Yx0OlcI8fy9Mu5ppLtF45wU= -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= - lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -18103,15 +18157,6 @@ lodash.keyby@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.keyby/-/lodash.keyby-4.6.0.tgz#7f6a1abda93fd24e22728a4d361ed8bcba5a4354" integrity sha1-f2oavak/0k4icopNNh7YvLpaQ1Q= -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.lowercase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.lowercase/-/lodash.lowercase-4.3.0.tgz#46515aced4acb0b7093133333af068e4c3b14e9d" @@ -18202,11 +18247,6 @@ lodash.reject@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -18232,21 +18272,6 @@ lodash.startcase@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" integrity sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg= -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - lodash.template@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -18255,14 +18280,6 @@ lodash.template@^4.4.0: lodash._reinterpolate "^3.0.0" lodash.templatesettings "^4.0.0" -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.templatesettings@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" @@ -18315,11 +18332,6 @@ lodash@^3.10.1, lodash@^3.3.1: resolved "https://registry.yarnpkg.com/@elastic/lodash/-/lodash-3.10.1-kibana3.tgz#c0e318245219eeeff535895c429e0cef5058a9ad" integrity sha512-HMfwwT2yAkEQNzHSR1BxgE5YcDMUaZ/skhNyjy1nvM/A4m0Kh940hLZeCqKBCsSaUJz/8A/9cQGd9BaAOCIBLg== -lodash@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" - integrity sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE= - lodash@~2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" @@ -18391,10 +18403,10 @@ loglevel@^1.6.1: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= -loglevel@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" - integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== +loglevel@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" + integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g== loglevelnext@^1.0.1: version "1.0.5" @@ -18475,11 +18487,6 @@ lowlight@~1.9.1: dependencies: highlight.js "~9.12.0" -lru-cache@2, lru-cache@^2.6.5: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= - lru-cache@4.1.5, lru-cache@^4.0.1, lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -18496,6 +18503,11 @@ lru-cache@4.1.x, lru-cache@^4.0.0: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^2.6.5: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -18717,11 +18729,26 @@ marky@^1.2.1: resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02" integrity sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ== +matchdep@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" + integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4= + dependencies: + findup-sync "^2.0.0" + micromatch "^3.0.4" + resolve "^1.4.0" + stack-trace "0.0.10" + material-colors@^1.2.1: version "1.2.5" resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.5.tgz#5292593e6754cb1bcc2b98030e4e0d6a3afc9ea1" integrity sha1-UpJZPmdUyxvMK5gDDk4Najr8nqE= +md5-file@^1.1.4: + version "1.1.10" + resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-1.1.10.tgz#d8f4fce76c92cb20b7d143a59f58ca49b4cf3174" + integrity sha1-2PT852ySyyC30UOln1jKSbTPMXQ= + md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -19122,21 +19149,6 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimatch@^2.0.1: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - dependencies: - brace-expansion "^1.0.0" - -minimatch@~0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - integrity sha1-x054BXT2PG+aCQ6Q775u9TpqdWo= - dependencies: - lru-cache "2" - sigmund "~1.0.0" - minimist-options@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" @@ -19288,6 +19300,18 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" +mkdirp@0.3.5, mkdirp@^0.3.5, mkdirp@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= + +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + integrity sha1-HXMHam35hs2TROFecfzAWkyavxI= + dependencies: + minimist "0.0.8" + mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -19295,11 +19319,6 @@ 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@^0.3.5, mkdirp@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" - integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= - mobx-react@^5.4.3: version "5.4.3" resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.3.tgz#6709b7dd89670c40e9815914ac2ca49cc02bfb47" @@ -19546,13 +19565,6 @@ multimatch@^4.0.0: arrify "^2.0.1" minimatch "^3.0.4" -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= - dependencies: - duplexer2 "0.0.2" - multistream@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c" @@ -19586,6 +19598,11 @@ mutation-observer@^1.0.3: resolved "https://registry.yarnpkg.com/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0" integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA== +mute-stdout@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" + integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== + mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" @@ -19660,11 +19677,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -natives@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" - integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -19856,10 +19868,10 @@ node-fetch@^2.6.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== -node-forge@0.7.5: - version "0.7.5" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" - integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== +node-forge@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" + integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== node-forge@^0.7.6: version "0.7.6" @@ -20080,7 +20092,7 @@ nodemailer@^4.7.0: chalk "~0.4.0" underscore "~1.6.0" -"nopt@2 || 3", nopt@3.x, nopt@~3.0.6: +"nopt@2 || 3", nopt@3.x, nopt@~3.0.1, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= @@ -20136,7 +20148,7 @@ normalize-path@^2.0.1, normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -20227,6 +20239,22 @@ npm-run-path@^3.0.0: dependencies: path-key "^3.0.0" +npmconf@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/npmconf/-/npmconf-2.1.3.tgz#1cbe5dd02e899d365fed7260b54055473f90a15c" + integrity sha512-iTK+HI68GceCoGOHAQiJ/ik1iDfI7S+cgyG8A+PP18IU3X83kRhQIRhAUNj4Bp2JMx6Zrt5kCiozYa9uGWTjhA== + dependencies: + config-chain "~1.1.8" + inherits "~2.0.0" + ini "^1.2.0" + mkdirp "^0.5.0" + nopt "~3.0.1" + once "~1.3.0" + osenv "^0.1.0" + safe-buffer "^5.1.1" + semver "2 || 3 || 4" + uid-number "0.0.5" + "npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -20417,7 +20445,7 @@ object.assign@4.1.0, object.assign@^4.0.4, object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.defaults@^1.1.0: +object.defaults@^1.0.0, object.defaults@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= @@ -20480,6 +20508,14 @@ object.pick@^1.2.0, object.pick@^1.3.0: dependencies: isobject "^3.0.1" +object.reduce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad" + integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60= + dependencies: + 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" @@ -20669,20 +20705,6 @@ ora@^3.0.0, ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" -orchestrator@^0.3.0: - version "0.3.8" - resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" - integrity sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4= - dependencies: - end-of-stream "~0.1.5" - sequencify "~0.0.7" - stream-consume "~0.1.0" - -ordered-read-streams@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126" - integrity sha1-/VZamvjrRHO6abbtijQ1LLVS8SY= - ordered-read-streams@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" @@ -21594,17 +21616,6 @@ platform@^1.3.0: resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" integrity sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q== -plugin-error@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= - dependencies: - ansi-cyan "^0.1.1" - ansi-red "^0.1.1" - arr-diff "^1.0.1" - arr-union "^2.0.1" - extend-shallow "^1.1.2" - plugin-error@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" @@ -21694,10 +21705,10 @@ popper.js@^1.14.4: resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== -portfinder@^1.0.21: - version "1.0.23" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.23.tgz#894db4bcc5daf02b6614517ce89cd21a38226b82" - integrity sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ== +portfinder@^1.0.24: + version "1.0.24" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa" + integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg== dependencies: async "^1.5.2" debug "^2.2.0" @@ -21864,7 +21875,7 @@ prettier@1.16.4: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g== -prettier@1.18.2, prettier@^1.13.7, prettier@^1.14.3: +prettier@1.18.2, prettier@^1.13.7, prettier@^1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== @@ -23546,7 +23557,7 @@ read-pkg@^5.1.1, read-pkg@^5.2.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@1.0, "readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17, readable-stream@~1.0.27-1: +readable-stream@1.0, readable-stream@~1.0.17, readable-stream@~1.0.27-1: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= @@ -23606,10 +23617,10 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.2.tgz#fa85d2d14d4289920e4671dead96431add2ee78a" - integrity sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw== +readdirp@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.3.tgz#d6e011ed5b9240a92f08651eeb40f7942ceb6cc1" + integrity sha512-ZOsfTGkjO2kqeR5Mzr5RYDbTGYneSkdNKX2fOX2P5jF7vMrd/GNnIAUtDldeHHumHUCQ3V05YfWUdxMPAsRu9Q== dependencies: picomatch "^2.0.4" @@ -24011,7 +24022,7 @@ remove-bom-stream@^1.2.0: safe-buffer "^5.1.0" through2 "^2.0.3" -remove-trailing-separator@^1.0.1: +remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= @@ -24071,6 +24082,15 @@ replace-ext@1.0.0, replace-ext@^1.0.0: resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= +replace-homedir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c" + integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw= + dependencies: + homedir-polyfill "^1.0.1" + is-absolute "^1.0.0" + remove-trailing-separator "^1.1.0" + request-progress@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" @@ -24409,7 +24429,7 @@ resolve@^1.11.1: dependencies: path-parse "^1.0.6" -resolve@^1.12.0: +resolve@^1.12.0, resolve@^1.4.0: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== @@ -24528,6 +24548,13 @@ rimraf@2.7.1, rimraf@^2.7.1: dependencies: glob "^7.1.3" +rimraf@~2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.0.3.tgz#f50a2965e7144e9afd998982f15df706730f56a9" + integrity sha1-9QopZecUTpr9mYmC8V33BnMPVqk= + optionalDependencies: + graceful-fs "~1.1" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" @@ -24635,15 +24662,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -run-sequence@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/run-sequence/-/run-sequence-2.2.1.tgz#1ce643da36fd8c7ea7e1a9329da33fc2b8898495" - integrity sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw== - dependencies: - chalk "^1.1.3" - fancy-log "^1.3.2" - plugin-error "^0.1.2" - rw@1, rw@^1.3.2, rw@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" @@ -24940,22 +24958,22 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -selenium-webdriver@^4.0.0-alpha.4: - version "4.0.0-alpha.4" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.4.tgz#73694490e02c941d9d0bf7a36f7c49beb9372512" - integrity sha512-etJt20d8qInkxMAHIm5SEpPBSS+CdxVcybnxzSIB/GlWErb8pIWrArz/VA6VfUW0/6tIcokepXQ5ufvdzqqk1A== +selenium-webdriver@^4.0.0-alpha.5: + version "4.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.5.tgz#e4683b3dbf827d70df09a7e43bf02ebad20fa7c1" + integrity sha512-hktl3DSrhzM59yLhWzDGHIX9o56DvA+cVK7Dw6FcJR6qQ4CGzkaHeXQPcdrslkWMTeq0Ci9AmCxq0EMOvm2Rkg== dependencies: jszip "^3.1.5" rimraf "^2.6.3" tmp "0.0.30" xml2js "^0.4.19" -selfsigned@^1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" - integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== +selfsigned@^1.10.7: + version "1.10.7" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" + integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== dependencies: - node-forge "0.7.5" + node-forge "0.9.0" semaphore-async-await@^1.5.1: version "1.5.1" @@ -24969,6 +24987,13 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" +semver-greatest-satisfied-range@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b" + integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els= + dependencies: + sver-compat "^1.5.0" + semver-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9" @@ -24981,6 +25006,11 @@ semver-truncate@^1.0.0: dependencies: semver "^5.3.0" +"semver@2 || 3 || 4": + version "4.3.6" + 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" @@ -24996,11 +25026,6 @@ semver@5.7.0, semver@^5.4.1, semver@^5.6.0, semver@^5.7.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -semver@^4.1.0: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= - semver@^5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" @@ -25072,11 +25097,6 @@ sentence-case@^2.1.0: no-case "^2.2.0" upper-case-first "^1.1.2" -sequencify@~0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c" - integrity sha1-kM/xnQLgcCf9dn9erT57ldHnOAw= - serialize-javascript@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" @@ -25296,11 +25316,6 @@ shot@4.x.x: hoek "5.x.x" joi "13.x.x" -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -25535,6 +25550,18 @@ sockjs-client@1.3.0: json3 "^3.3.2" url-parse "^1.4.3" +sockjs-client@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" + integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + sockjs@0.3.19: version "0.3.19" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" @@ -25864,7 +25891,7 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-trace@0.0.x: +stack-trace@0.0.10, stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= @@ -25970,11 +25997,6 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" -stream-consume@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" - integrity sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8= - stream-each@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" @@ -25983,6 +26005,11 @@ stream-each@^1.1.0: end-of-stream "^1.1.0" stream-shift "^1.0.0" +stream-exhaust@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" + integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== + stream-http@^2.7.2: version "2.8.0" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" @@ -26248,14 +26275,6 @@ strip-bom-string@1.X: resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= -strip-bom@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794" - integrity sha1-hbiGLzhEtabV7IRnqTWYFzo295Q= - dependencies: - first-chunk-stream "^1.0.0" - is-utf8 "^0.2.0" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -26512,6 +26531,14 @@ suricata-sid-db@^1.0.2: dependencies: typescript "^3.3.3333" +sver-compat@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" + integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg= + dependencies: + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + svgo@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" @@ -26661,7 +26688,7 @@ tape@^4.5.1: string.prototype.trim "~1.1.2" through "~2.3.8" -tar-fs@^1.16.2, tar-fs@^1.16.3: +tar-fs@^1.16.3: version "1.16.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== @@ -26934,7 +26961,7 @@ through2-map@^3.0.0: through2 "~2.0.0" xtend "^4.0.0" -through2@2.X, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0: +through2@2.X, through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= @@ -26942,14 +26969,6 @@ through2@2.X, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0 readable-stream "^2.1.5" xtend "~4.0.1" -through2@^0.6.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg= - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - through2@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" @@ -26975,7 +26994,7 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" integrity sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E= -tildify@^1.0.0, tildify@^1.2.0: +tildify@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" integrity sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo= @@ -28044,6 +28063,11 @@ ui-select@0.19.8: resolved "https://registry.yarnpkg.com/ui-select/-/ui-select-0.19.8.tgz#74860848a7fd8bc494d9856d2f62776ea98637c1" integrity sha1-dIYISKf9i8SU2YVtL2J3bqmGN8E= +uid-number@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.5.tgz#5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e" + integrity sha1-Wj2yPvXb1VuB/ODsmirG/M3ruB4= + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -28075,6 +28099,26 @@ underscore@~1.6.0: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" integrity sha1-izixDKze9jM3uLJOT/htRa6lKag= +undertaker-registry@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50" + integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA= + +undertaker@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.2.1.tgz#701662ff8ce358715324dfd492a4f036055dfe4b" + integrity sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA== + dependencies: + arr-flatten "^1.0.1" + arr-map "^2.0.0" + bach "^1.0.0" + collection-map "^1.0.0" + es6-weak-map "^2.0.1" + last-run "^1.1.0" + object.defaults "^1.0.0" + object.reduce "^1.0.0" + undertaker-registry "^1.0.0" + unfetch@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db" @@ -28188,11 +28232,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -unique-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b" - integrity sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs= - unique-stream@^2.0.2: version "2.2.1" resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" @@ -28388,14 +28427,14 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.1.0.tgz#bcc1ecabbd197e913eca23f5e0378e24b4412961" - integrity sha512-kVrp/8VfEm5fUt+fl2E0FQyrpmOYgMEkBsv8+UDP1wFhszECq5JyGF33I7cajlVY90zRZ6MyfgKXngLvHYZX8A== +url-loader@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.2.0.tgz#af321aece1fd0d683adc8aaeb27829f29c75b46e" + integrity sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw== dependencies: loader-utils "^1.2.3" mime "^2.4.4" - schema-utils "^2.0.0" + schema-utils "^2.4.1" url-loader@^1.1.2: version "1.1.2" @@ -28456,11 +28495,6 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA= - user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -28550,12 +28584,12 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== -v8flags@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" - integrity sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ= +v8flags@^3.0.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.1.3.tgz#fc9dc23521ca20c5433f81cc4eb9b3033bb105d8" + integrity sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w== dependencies: - user-home "^1.1.1" + homedir-polyfill "^1.0.1" val-loader@^1.1.1: version "1.1.1" @@ -28992,21 +29026,7 @@ vinyl-file@^2.0.0: strip-bom-stream "^2.0.0" vinyl "^1.1.0" -vinyl-fs@^0.3.0: - version "0.3.14" - resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6" - integrity sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY= - dependencies: - defaults "^1.0.0" - glob-stream "^3.1.5" - glob-watcher "^0.0.6" - graceful-fs "^3.0.0" - mkdirp "^0.5.0" - strip-bom "^1.0.0" - through2 "^0.6.1" - vinyl "^0.4.0" - -vinyl-fs@^3.0.3: +vinyl-fs@^3.0.0, vinyl-fs@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== @@ -29049,23 +29069,6 @@ vinyl-sourcemaps-apply@^0.2.0: dependencies: source-map "^0.5.1" -vinyl@^0.4.0: - version "0.4.6" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" - integrity sha1-LzVsh6VQolVGHza76ypbqL94SEc= - dependencies: - clone "^0.2.0" - clone-stats "^0.0.1" - -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - vinyl@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" @@ -29267,10 +29270,10 @@ webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.7.tgz#77c8580dd8e92f69d635e0238eaf9d9c15759a91" - integrity sha512-OhTUCttAsr+IZSMVwGROGRHvT+QAs8H6/mHIl4SvhAwYywjiylYjpwybGx7WQ9Hkb45FhjtsymkwiRRbGJ1SZQ== +webpack-cli@^3.3.9: + version "3.3.9" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" + integrity sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -29294,41 +29297,52 @@ webpack-dev-middleware@^3.7.0: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz#06cc4fc2f440428508d0e9770da1fef10e5ef28d" - integrity sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ== +webpack-dev-middleware@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" + integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz#3292427bf6510da9a3ac2d500b924a4197667ff9" + integrity sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" - chokidar "^2.1.6" + chokidar "^2.1.8" compression "^1.7.4" connect-history-api-fallback "^1.6.0" debug "^4.1.1" del "^4.1.1" express "^4.17.1" html-entities "^1.2.1" - http-proxy-middleware "^0.19.1" + http-proxy-middleware "0.19.1" import-local "^2.0.0" internal-ip "^4.3.0" ip "^1.1.5" - is-absolute-url "^3.0.0" + is-absolute-url "^3.0.3" killable "^1.0.1" - loglevel "^1.6.3" + loglevel "^1.6.4" opn "^5.5.0" p-retry "^3.0.1" - portfinder "^1.0.21" + portfinder "^1.0.24" schema-utils "^1.0.0" - selfsigned "^1.10.4" + selfsigned "^1.10.7" semver "^6.3.0" serve-index "^1.9.1" sockjs "0.3.19" - sockjs-client "1.3.0" + sockjs-client "1.4.0" spdy "^4.0.1" strip-ansi "^3.0.1" supports-color "^6.1.0" url "^0.11.0" - webpack-dev-middleware "^3.7.0" + webpack-dev-middleware "^3.7.2" webpack-log "^2.0.0" ws "^6.2.1" yargs "12.0.5" @@ -29361,12 +29375,12 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" -webpack-merge@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.1.tgz#5e923cf802ea2ace4fd5af1d3247368a633489b4" - integrity sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw== +webpack-merge@4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== dependencies: - lodash "^4.17.5" + lodash "^4.17.15" webpack-sources@^1.1.0: version "1.3.0" @@ -29384,10 +29398,10 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@4.39.2, webpack@^4.39.2: - version "4.39.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.39.2.tgz#c9aa5c1776d7c309d1b3911764f0288c8c2816aa" - integrity sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA== +webpack@4.41.0, webpack@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b" + integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -29974,7 +29988,7 @@ xregexp@4.2.4: dependencies: "@babel/runtime-corejs2" "^7.2.0" -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= @@ -30166,7 +30180,7 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" -yargs@^7.0.0: +yargs@^7.0.0, yargs@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= @@ -30239,10 +30253,10 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" -yazl@^2.1.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" - integrity sha1-7CblzIfVYBud+EMtvdPNLlFzoHE= +yazl@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== dependencies: buffer-crc32 "~0.2.3"