diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4cc0c8016f1d0..754043ee0ef77 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ Delete any items that are not applicable to this PR. - [ ] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios - [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server) -- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) +- [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 211cfac3806ad..1466865df8d98 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -1,71 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`builds expected bundles, saves bundle counts to metadata: OptimizerConfig 1`] = ` -OptimizerConfig { - "bundles": Array [ - Bundle { - "cache": BundleCache { - "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public/.kbn-optimizer-cache, - "state": undefined, - }, - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, - "id": "bar", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, - "publicDirNames": Array [ - "public", - ], - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "type": "plugin", - }, - Bundle { - "cache": BundleCache { - "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public/.kbn-optimizer-cache, - "state": undefined, - }, - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, - "id": "foo", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, - "publicDirNames": Array [ - "public", - ], - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "type": "plugin", - }, - ], - "cache": true, - "dist": false, - "inspectWorkers": false, - "maxWorkerCount": 1, - "plugins": Array [ - Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, - "extraPublicDirs": Array [], - "id": "bar", - "isUiPlugin": true, - }, - Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, - "extraPublicDirs": Array [], - "id": "foo", - "isUiPlugin": true, - }, - Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz, - "extraPublicDirs": Array [], - "id": "baz", - "isUiPlugin": false, - }, - ], - "profileWebpack": false, - "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "themeTags": Array [ - "v7dark", - "v7light", - ], - "watch": false, -} -`; - exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"\\";return __webpack_require__(__webpack_require__.s=5)})([function(module,exports,__webpack_require__){\\"use strict\\";var isOldIE=function isOldIE(){var memo;return function memorize(){if(typeof memo===\\"undefined\\"){memo=Boolean(window&&document&&document.all&&!window.atob)}return memo}}();var getTarget=function getTarget(){var memo={};return function memorize(target){if(typeof memo[target]===\\"undefined\\"){var styleTarget=document.querySelector(target);if(window.HTMLIFrameElement&&styleTarget instanceof window.HTMLIFrameElement){try{styleTarget=styleTarget.contentDocument.head}catch(e){styleTarget=null}}memo[target]=styleTarget}return memo[target]}}();var stylesInDom=[];function getIndexByIdentifier(identifier){var result=-1;for(var i=0;i { @@ -36,8 +35,6 @@ export class SearchService implements Plugin { constructor(private initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup): ISearchSetup { - core.savedObjects.registerType(searchSavedObjectType); - this.registerSearchStrategy( ES_SEARCH_STRATEGY, esSearchStrategyProvider(this.initializerContext.config.legacy.globalConfig$) diff --git a/src/plugins/discover/server/plugin.ts b/src/plugins/discover/server/plugin.ts index a7445a5189163..77553ce644839 100644 --- a/src/plugins/discover/server/plugin.ts +++ b/src/plugins/discover/server/plugin.ts @@ -20,11 +20,13 @@ import { CoreSetup, CoreStart, Plugin } from 'kibana/server'; import { uiSettings } from './ui_settings'; import { capabilitiesProvider } from './capabilities_provider'; +import { searchSavedObjectType } from './saved_objects'; export class DiscoverServerPlugin implements Plugin { public setup(core: CoreSetup) { core.capabilities.registerProvider(capabilitiesProvider); core.uiSettings.register(uiSettings); + core.savedObjects.registerType(searchSavedObjectType); return {}; } diff --git a/src/plugins/discover/server/saved_objects/index.ts b/src/plugins/discover/server/saved_objects/index.ts new file mode 100644 index 0000000000000..efe785364ccb6 --- /dev/null +++ b/src/plugins/discover/server/saved_objects/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { searchSavedObjectType } from './search'; diff --git a/src/plugins/data/server/saved_objects/search.ts b/src/plugins/discover/server/saved_objects/search.ts similarity index 84% rename from src/plugins/data/server/saved_objects/search.ts rename to src/plugins/discover/server/saved_objects/search.ts index 16caaf05a0fc6..2348d89c4f4dd 100644 --- a/src/plugins/data/server/saved_objects/search.ts +++ b/src/plugins/discover/server/saved_objects/search.ts @@ -18,7 +18,7 @@ */ import { SavedObjectsType } from 'kibana/server'; -import { searchSavedObjectTypeMigrations } from './search_migrations'; +import { searchMigrations } from './search_migrations'; export const searchSavedObjectType: SavedObjectsType = { name: 'search', @@ -43,18 +43,18 @@ export const searchSavedObjectType: SavedObjectsType = { }, mappings: { properties: { - columns: { type: 'keyword' }, + columns: { type: 'keyword', index: false }, description: { type: 'text' }, - hits: { type: 'integer' }, + hits: { type: 'integer', index: false }, kibanaSavedObjectMeta: { properties: { - searchSourceJSON: { type: 'text' }, + searchSourceJSON: { type: 'text', index: false }, }, }, - sort: { type: 'keyword' }, + sort: { type: 'keyword', index: false }, title: { type: 'text' }, version: { type: 'integer' }, }, }, - migrations: searchSavedObjectTypeMigrations as any, + migrations: searchMigrations as any, }; diff --git a/src/plugins/data/server/saved_objects/search_migrations.test.ts b/src/plugins/discover/server/saved_objects/search_migrations.test.ts similarity index 96% rename from src/plugins/data/server/saved_objects/search_migrations.test.ts rename to src/plugins/discover/server/saved_objects/search_migrations.test.ts index 69db08a689255..babd25c03dbb2 100644 --- a/src/plugins/data/server/saved_objects/search_migrations.test.ts +++ b/src/plugins/discover/server/saved_objects/search_migrations.test.ts @@ -18,13 +18,13 @@ */ import { SavedObjectMigrationContext } from 'kibana/server'; -import { searchSavedObjectTypeMigrations } from './search_migrations'; +import { searchMigrations } from './search_migrations'; const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext; describe('migration search', () => { describe('6.7.2', () => { - const migrationFn = searchSavedObjectTypeMigrations['6.7.2']; + const migrationFn = searchMigrations['6.7.2']; it('should migrate obsolete match_all query', () => { const migratedDoc = migrationFn( @@ -56,7 +56,7 @@ describe('migration search', () => { }); describe('7.0.0', () => { - const migrationFn = searchSavedObjectTypeMigrations['7.0.0']; + const migrationFn = searchMigrations['7.0.0']; test('skips errors when searchSourceJSON is null', () => { const doc = { @@ -278,7 +278,7 @@ Object { }); describe('7.4.0', function () { - const migrationFn = searchSavedObjectTypeMigrations['7.4.0']; + const migrationFn = searchMigrations['7.4.0']; test('transforms one dimensional sort arrays into two dimensional arrays', () => { const doc = { diff --git a/src/plugins/data/server/saved_objects/search_migrations.ts b/src/plugins/discover/server/saved_objects/search_migrations.ts similarity index 97% rename from src/plugins/data/server/saved_objects/search_migrations.ts rename to src/plugins/discover/server/saved_objects/search_migrations.ts index 9bba429f8d71b..0302159c43c56 100644 --- a/src/plugins/data/server/saved_objects/search_migrations.ts +++ b/src/plugins/discover/server/saved_objects/search_migrations.ts @@ -19,7 +19,7 @@ import { flow, get } from 'lodash'; import { SavedObjectMigrationFn } from 'kibana/server'; -import { DEFAULT_QUERY_LANGUAGE } from '../../common'; +import { DEFAULT_QUERY_LANGUAGE } from '../../../data/common'; const migrateMatchAllQuery: SavedObjectMigrationFn = (doc) => { const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON'); @@ -121,7 +121,7 @@ const migrateSearchSortToNestedArray: SavedObjectMigrationFn = (doc) = }; }; -export const searchSavedObjectTypeMigrations = { +export const searchMigrations = { '6.7.2': flow(migrateMatchAllQuery), '7.0.0': flow(setNewReferences), '7.4.0': flow(migrateSearchSortToNestedArray), diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index 2e83d16dd778e..4e73d27c1c4a1 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -475,17 +475,6 @@ describe('Execution', () => { } }); - test('sets duration to 10 milliseconds when function executes 10 milliseconds', async () => { - const execution = createExecution('sleep 10', {}, true); - execution.start(-1); - await execution.result; - - const node = execution.state.get().ast.chain[0]; - expect(typeof node.debug?.duration).toBe('number'); - expect(node.debug?.duration).toBeLessThan(50); - expect(node.debug?.duration).toBeGreaterThanOrEqual(5); - }); - test('adds .debug field in expression AST on each executed function', async () => { const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); execution.start(-1); diff --git a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts index 689b88390810f..5791dfe5b9463 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts +++ b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts @@ -6,9 +6,6 @@ /* eslint-disable import/no-extraneous-dependencies */ -const RANGE_FROM = '2020-06-01T14:59:32.686Z'; -const RANGE_TO = '2020-06-16T16:59:36.219Z'; - const BASE_URL = Cypress.config().baseUrl; /** The default time in ms to wait for a Cypress command to complete */ @@ -16,20 +13,14 @@ export const DEFAULT_TIMEOUT = 60 * 1000; export function loginAndWaitForPage( url: string, - dateRange?: { to: string; from: string } + dateRange: { to: string; from: string } ) { const username = Cypress.env('elasticsearch_username'); const password = Cypress.env('elasticsearch_password'); cy.log(`Authenticating via ${username} / ${password}`); - let rangeFrom = RANGE_FROM; - let rangeTo = RANGE_TO; - if (dateRange) { - rangeFrom = dateRange.from; - rangeTo = dateRange.to; - } - - const fullUrl = `${BASE_URL}${url}?rangeFrom=${rangeFrom}&rangeTo=${rangeTo}`; + + const fullUrl = `${BASE_URL}${url}?rangeFrom=${dateRange.from}&rangeTo=${dateRange.to}`; cy.visit(fullUrl, { auth: { username, password } }); cy.viewport('macbook-15'); diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index ac09e575a46ae..7fbce2583903c 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -1,12 +1,5 @@ module.exports = { - "__version": "4.5.0", - "APM": { - "Transaction duration charts": { - "1": "55 ms", - "2": "28 ms", - "3": "0 ms" - } - }, + "__version": "4.9.0", "RUM Dashboard": { "Client metrics": { "1": "55 ", diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts index 361d055db9ac1..c1402bbd035f4 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts @@ -12,7 +12,10 @@ export const DEFAULT_TIMEOUT = 60 * 1000; Given(`a user browses the APM UI application`, () => { // open service overview page - loginAndWaitForPage(`/app/apm#/services`); + loginAndWaitForPage(`/app/apm#/services`, { + from: '2020-06-01T14:59:32.686Z', + to: '2020-06-16T16:59:36.219Z', + }); }); When(`the user inspects the opbeans-node service`, () => { @@ -34,9 +37,8 @@ Then(`should have correct y-axis ticks`, () => { // wait for all loading to finish cy.get('kbnLoadingIndicator').should('not.be.visible'); - cy.get(yAxisTick).eq(2).invoke('text').snapshot(); - - cy.get(yAxisTick).eq(1).invoke('text').snapshot(); - - cy.get(yAxisTick).eq(0).invoke('text').snapshot(); + // literal assertions because snapshot() doesn't retry + cy.get(yAxisTick).eq(2).should('have.text', '55 ms'); + cy.get(yAxisTick).eq(1).should('have.text', '28 ms'); + cy.get(yAxisTick).eq(0).should('have.text', '0 ms'); }); diff --git a/x-pack/plugins/apm/e2e/package.json b/x-pack/plugins/apm/e2e/package.json index 417dda4c5220e..5101e64235c62 100644 --- a/x-pack/plugins/apm/e2e/package.json +++ b/x-pack/plugins/apm/e2e/package.json @@ -9,19 +9,19 @@ }, "dependencies": { "@cypress/snapshot": "^2.1.3", - "@cypress/webpack-preprocessor": "^5.2.0", + "@cypress/webpack-preprocessor": "^5.4.1", "@types/cypress-cucumber-preprocessor": "^1.14.1", - "@types/node": "^14.0.1", + "@types/node": "^14.0.14", "axios": "^0.19.2", - "cypress": "^4.5.0", - "cypress-cucumber-preprocessor": "^2.3.1", + "cypress": "^4.9.0", + "cypress-cucumber-preprocessor": "^2.5.2", "ora": "^4.0.4", - "p-limit": "^2.3.0", + "p-limit": "^3.0.1", "p-retry": "^4.2.0", - "ts-loader": "^7.0.4", - "typescript": "3.9.5", - "wait-on": "^5.0.0", + "ts-loader": "^7.0.5", + "typescript": "3.9.6", + "wait-on": "^5.0.1", "webpack": "^4.43.0", - "yargs": "^15.3.1" + "yargs": "^15.4.0" } } diff --git a/x-pack/plugins/apm/e2e/run-e2e.sh b/x-pack/plugins/apm/e2e/run-e2e.sh index 43cc74a197f42..bc64f2b009d52 100755 --- a/x-pack/plugins/apm/e2e/run-e2e.sh +++ b/x-pack/plugins/apm/e2e/run-e2e.sh @@ -106,10 +106,12 @@ yarn &> ${TMP_DIR}/e2e-yarn.log echo "" # newline echo "${bold}Static mock data (logs: ${E2E_DIR}${TMP_DIR}/ingest-data.log)${normal}" +STATIC_MOCK_FILENAME='2020-06-12.json' + # Download static data if not already done -if [ ! -e "${TMP_DIR}/events.json" ]; then - echo 'Downloading events.json...' - curl --silent https://storage.googleapis.com/apm-ui-e2e-static-data/2020-06-12.json --output ${TMP_DIR}/events.json +if [ ! -e "${TMP_DIR}/${STATIC_MOCK_FILENAME}" ]; then + echo "Downloading ${STATIC_MOCK_FILENAME}..." + curl --silent https://storage.googleapis.com/apm-ui-e2e-static-data/${STATIC_MOCK_FILENAME} --output ${TMP_DIR}/${STATIC_MOCK_FILENAME} fi # echo "Deleting existing indices (apm* and .apm*)" @@ -117,7 +119,7 @@ curl --silent --user admin:changeme -XDELETE "localhost:${ELASTICSEARCH_PORT}/.a curl --silent --user admin:changeme -XDELETE "localhost:${ELASTICSEARCH_PORT}/apm*" > /dev/null # Ingest data into APM Server -node ingest-data/replay.js --server-url http://localhost:$APM_SERVER_PORT --events ${TMP_DIR}/events.json 2>> ${TMP_DIR}/ingest-data.log +node ingest-data/replay.js --server-url http://localhost:$APM_SERVER_PORT --events ${TMP_DIR}/${STATIC_MOCK_FILENAME} 2>> ${TMP_DIR}/ingest-data.log # Abort if not all events were ingested correctly if [ $? -ne 0 ]; then diff --git a/x-pack/plugins/apm/e2e/yarn.lock b/x-pack/plugins/apm/e2e/yarn.lock index 975154d71b85d..936294052aa7b 100644 --- a/x-pack/plugins/apm/e2e/yarn.lock +++ b/x-pack/plugins/apm/e2e/yarn.lock @@ -689,6 +689,14 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" +"@babel/runtime-corejs3@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz#f29fc1990307c4c57b10dbd6ce667b27159d9e0d" + integrity sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" + "@babel/runtime@7.3.1": version "7.3.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" @@ -802,13 +810,14 @@ snap-shot-compare "2.8.3" snap-shot-store "1.2.3" -"@cypress/webpack-preprocessor@^5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.2.0.tgz#3a17b478f6e2d600e536e6dda9c2e349d25a297e" - integrity sha512-uvo0FfKL+rIXrBGS6qPIaJRD8euK+t6YoZvrTuLPnStprzlgeGfSCnCDUEMJZqFk9LwBd1NtOop+J7qNuv74ng== +"@cypress/webpack-preprocessor@^5.4.1": + version "5.4.1" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.4.1.tgz#eb58f6cd02932a95653c1a674cfd769da2409806" + integrity sha512-1E2BdVVXQ4wDQ7f3mXCvS9xmfTVwEoT3oqKhjAr1iNlTJpBq10Z0VNBZd3VZ3nmCTFwTuUvs735QGnRE1gQ1BA== dependencies: bluebird "3.7.1" debug "4.1.1" + lodash "4.17.15" "@cypress/xvfb@1.2.4": version "1.2.4" @@ -865,34 +874,6 @@ dependencies: any-observable "^0.3.0" -"@types/blob-util@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@types/blob-util/-/blob-util-1.3.3.tgz#adba644ae34f88e1dd9a5864c66ad651caaf628a" - integrity sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w== - -"@types/bluebird@3.5.29": - version "3.5.29" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6" - integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw== - -"@types/chai-jquery@1.1.40": - version "1.1.40" - resolved "https://registry.yarnpkg.com/@types/chai-jquery/-/chai-jquery-1.1.40.tgz#445bedcbbb2ae4e3027f46fa2c1733c43481ffa1" - integrity sha512-mCNEZ3GKP7T7kftKeIs7QmfZZQM7hslGSpYzKbOlR2a2HCFf9ph4nlMRA9UnuOETeOQYJVhJQK7MwGqNZVyUtQ== - dependencies: - "@types/chai" "*" - "@types/jquery" "*" - -"@types/chai@*": - version "4.2.11" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" - integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== - -"@types/chai@4.2.7": - version "4.2.7" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d" - integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -903,71 +884,22 @@ resolved "https://registry.yarnpkg.com/@types/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.14.1.tgz#9787f4e89553ebc6359ce157a26ad51ed14aa98b" integrity sha512-CpYsiQ49UrOmadhFg0G5RkokPUmGGctD01mOWjNxFxHw5VgIRv33L2RyFHL8klaAI4HaedGN3Tcj4HTQ65hn+A== -"@types/jquery@*": - version "3.3.38" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.38.tgz#6385f1e1b30bd2bff55ae8ee75ea42a999cc3608" - integrity sha512-nkDvmx7x/6kDM5guu/YpXkGZ/Xj/IwGiLDdKM99YA5Vag7pjGyTJ8BNUh/6hxEn/sEu5DKtyRgnONJ7EmOoKrA== - dependencies: - "@types/sizzle" "*" - -"@types/jquery@3.3.31": - version "3.3.31" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b" - integrity sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg== - dependencies: - "@types/sizzle" "*" - -"@types/lodash@4.14.149": - version "4.14.149" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" - integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== - -"@types/minimatch@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/mocha@5.2.7": - version "5.2.7" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" - integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== - -"@types/node@^14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c" - integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA== +"@types/node@^14.0.14": + version "14.0.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce" + integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ== "@types/retry@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== -"@types/sinon-chai@3.2.3": - version "3.2.3" - resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.3.tgz#afe392303dda95cc8069685d1e537ff434fa506e" - integrity sha512-TOUFS6vqS0PVL1I8NGVSNcFaNJtFoyZPXZ5zur+qlhDfOmQECZZM4H4kKgca6O8L+QceX/ymODZASfUfn+y4yQ== - dependencies: - "@types/chai" "*" - "@types/sinon" "*" - -"@types/sinon@*": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.0.tgz#5b70a360f55645dd64f205defd2a31b749a59799" - integrity sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA== - dependencies: - "@types/sinonjs__fake-timers" "*" - -"@types/sinon@7.5.1": - version "7.5.1" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.1.tgz#d27b81af0d1cfe1f9b24eebe7a24f74ae40f5b7c" - integrity sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ== - -"@types/sinonjs__fake-timers@*": +"@types/sinonjs__fake-timers@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e" integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA== -"@types/sizzle@*", "@types/sizzle@2.3.2": +"@types/sizzle@2.3.2": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== @@ -1262,10 +1194,10 @@ aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -arch@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" - integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== +arch@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.2.tgz#0c52bbe7344bb4fa260c443d2cbad9c00ff2f0bf" + integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== argparse@^1.0.7: version "1.0.10" @@ -1347,7 +1279,7 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async@^3.1.0: +async@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== @@ -2046,10 +1978,10 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" - integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== +commander@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== commander@^2.19.0, commander@^2.20.0, commander@^2.9.0: version "2.20.3" @@ -2141,6 +2073,11 @@ core-js-compat@^3.1.1: browserslist "^4.8.3" semver "7.0.0" +core-js-pure@^3.0.0: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" + integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== + core-js@^2.4.0: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" @@ -2278,10 +2215,10 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= -cypress-cucumber-preprocessor@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-2.3.1.tgz#dc9dee8d59d3c787c5c70fc4271c32e95575b083" - integrity sha512-cKa7/VsOthzvdSQSdFiLwSWtBrtDE2q/qAPDL6NWOF4Tqm/AWvvOv18b9l9Z1t4SpphezR7RGnG1QIU45y9PPw== +cypress-cucumber-preprocessor@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-2.5.2.tgz#d544616ece1fb361867e904678d970fe82398b54" + integrity sha512-djQjXmRWUKlA15GxWGhkqaeu1PalWeNrRyxij74QJ2dEp/ozQg35NeVABeWQjgjY2xTE87X6k5iC4y+Sbohe3A== dependencies: "@cypress/browserify-preprocessor" "^2.1.1" chai "^4.1.2" @@ -2297,48 +2234,39 @@ cypress-cucumber-preprocessor@^2.3.1: minimist "^1.2.0" through "^2.3.8" -cypress@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.5.0.tgz#01940d085f6429cec3c87d290daa47bb976a7c7b" - integrity sha512-2A4g5FW5d2fHzq8HKUGAMVTnW6P8nlWYQALiCoGN4bqBLvgwhYM/oG9oKc2CS6LnvgHFiKivKzpm9sfk3uU3zQ== +cypress@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.9.0.tgz#c188a3864ddf841c0fdc81a9e4eff5cf539cd1c1" + integrity sha512-qGxT5E0j21FPryzhb0OBjCdhoR/n1jXtumpFFSBPYWsaZZhNaBvc3XlBUDEZKkkXPsqUFYiyhWdHN/zo0t5FcA== dependencies: "@cypress/listr-verbose-renderer" "0.4.1" "@cypress/request" "2.88.5" "@cypress/xvfb" "1.2.4" - "@types/blob-util" "1.3.3" - "@types/bluebird" "3.5.29" - "@types/chai" "4.2.7" - "@types/chai-jquery" "1.1.40" - "@types/jquery" "3.3.31" - "@types/lodash" "4.14.149" - "@types/minimatch" "3.0.3" - "@types/mocha" "5.2.7" - "@types/sinon" "7.5.1" - "@types/sinon-chai" "3.2.3" + "@types/sinonjs__fake-timers" "6.0.1" "@types/sizzle" "2.3.2" - arch "2.1.1" + arch "2.1.2" bluebird "3.7.2" cachedir "2.3.0" chalk "2.4.2" check-more-types "2.24.0" cli-table3 "0.5.1" - commander "4.1.0" + commander "4.1.1" common-tags "1.8.0" debug "4.1.1" - eventemitter2 "4.1.2" + eventemitter2 "6.4.2" execa "1.0.0" executable "4.1.1" extract-zip "1.7.0" fs-extra "8.1.0" - getos "3.1.4" + getos "3.2.1" is-ci "2.0.0" - is-installed-globally "0.1.0" + is-installed-globally "0.3.2" lazy-ass "1.6.0" listr "0.14.3" lodash "4.17.15" log-symbols "3.0.0" minimist "1.2.5" - moment "2.24.0" + moment "2.26.0" ospath "1.2.2" pretty-bytes "5.3.0" ramda "0.26.1" @@ -2407,6 +2335,13 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-3.2.0.tgz#84b8e8f4f8c579f938e35e2cc7024907e0090851" + integrity sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw== + dependencies: + xregexp "^4.2.4" + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -2698,10 +2633,10 @@ esutils@^2.0.0, esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter2@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15" - integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU= +eventemitter2@6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.2.tgz#f31f8b99d45245f0edbc5b00797830ff3b388970" + integrity sha512-r/Pwupa5RIzxIHbEKCkNXqpEQIIT4uQDxmP4G/Lug/NokVUWj0joz/WzWl3OxRpC5kDrH/WdiUJoR+IrwvXJEw== events@^2.0.0: version "2.1.0" @@ -3040,12 +2975,12 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getos@3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.4.tgz#29cdf240ed10a70c049add7b6f8cb08c81876faf" - integrity sha512-UORPzguEB/7UG5hqiZai8f0vQ7hzynMQyJLxStoQ8dPGAcmgsfXOPA4iE/fGtweHYkK+z4zc9V0g+CIFRf5HYw== +getos@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== dependencies: - async "^3.1.0" + async "^3.2.0" getpass@^0.1.1: version "0.1.7" @@ -3079,12 +3014,12 @@ glob@^7.0.0, glob@^7.1.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= +global-dirs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" + integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A== dependencies: - ini "^1.3.4" + ini "^1.3.5" globals@^11.1.0: version "11.12.0" @@ -3261,7 +3196,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4: +ini@^1.3.4, ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -3424,13 +3359,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-installed-globally@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= +is-installed-globally@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" + global-dirs "^2.0.1" + is-path-inside "^3.0.1" is-interactive@^1.0.0: version "1.0.0" @@ -3456,12 +3391,10 @@ is-observable@^1.1.0: dependencies: symbol-observable "^1.1.0" -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" @@ -4031,10 +3964,10 @@ module-deps@^6.0.0: through2 "^2.0.0" xtend "^4.0.0" -moment@2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== +moment@2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" + integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== move-concurrently@^1.0.1: version "1.0.1" @@ -4319,10 +4252,10 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== +p-limit@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.1.tgz#584784ac0722d1aed09f19f90ed2999af6ce2839" + integrity sha512-mw/p92EyOzl2MhauKodw54Rx5ZK4624rNfgNaBguFZkHzyUG9WsDzFF5/yQVEJinbJDdP4jEfMN+uBquiGnaLg== dependencies: p-try "^2.0.0" @@ -4436,11 +4369,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -4711,6 +4639,11 @@ regenerator-runtime@^0.12.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" @@ -5503,10 +5436,10 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -ts-loader@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.4.tgz#5d9b95227de5afb91fdd9668f8920eb193cfe0cc" - integrity sha512-5du6OQHl+4ZjO4crEyoYUyWSrmmo7bAO+inkaILZ68mvahqrfoa4nn0DRmpQ4ruT4l+cuJCgF0xD7SBIyLeeow== +ts-loader@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.5.tgz#789338fb01cb5dc0a33c54e50558b34a73c9c4c5" + integrity sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -5561,10 +5494,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== +typescript@3.9.6: + version "3.9.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" + integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw== umd@^3.0.0: version "3.0.3" @@ -5740,10 +5673,10 @@ vm-browserify@^1.0.0, vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -wait-on@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.0.0.tgz#72e554b338490bbc7131362755ca1af04f46d029" - integrity sha512-6v9lttmGGRT7Lr16E/0rISTBIV1DN72n9+77Bpt1iBfzmhBI+75RDlacFe0Q+JizkmwWXmgHUcFG5cgx3Bwqzw== +wait-on@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.0.1.tgz#7dadfe83c36fdf034de996a41aa094af5cf23077" + integrity sha512-TxzkYIfRWK1hLc9IlUh9bE1mrvIIM3ptPRKQ86Z8Qo0tBQLCHEvWzkRD1Ge4FWprKflHOnAtqIBH2nKmib/lrg== dependencies: "@hapi/joi" "^17.1.1" axios "^0.19.2" @@ -5858,6 +5791,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +xregexp@^4.2.4: + version "4.3.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" + integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== + dependencies: + "@babel/runtime-corejs3" "^7.8.3" + xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -5878,21 +5818,21 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@^18.1.1: - version "18.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.2.tgz#2f482bea2136dbde0861683abea7756d30b504f1" - integrity sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ== +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@^15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== +yargs@^15.4.0: + version "15.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.0.tgz#53949fb768309bac1843de9b17b80051e9805ec2" + integrity sha512-D3fRFnZwLWp8jVAAhPZBsmeIHY8tTsb8ItV9KaAaopmC6wde2u6Yw29JBIZHXw14kgkRnYmDgmQU4FVMDlIsWw== dependencies: cliui "^6.0.0" - decamelize "^1.2.0" + decamelize "^3.2.0" find-up "^4.1.0" get-caller-file "^2.0.1" require-directory "^2.1.1" @@ -5901,7 +5841,7 @@ yargs@^15.3.1: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" + yargs-parser "^18.1.2" yauzl@2.10.0, yauzl@^2.10.0: version "2.10.0" diff --git a/x-pack/plugins/apm/readme.md b/x-pack/plugins/apm/readme.md index 778b1f2ad2d91..f460ff6ff9bf2 100644 --- a/x-pack/plugins/apm/readme.md +++ b/x-pack/plugins/apm/readme.md @@ -81,37 +81,32 @@ For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme) ### API integration tests Our tests are separated in two suites: one suite runs with a basic license, and the other -with a trial license (the equivalent of gold+). This requires separate test servers and test runs. +with a trial license (the equivalent of gold+). This requires separate test servers and test runners. -**Start server** - -Basic: +**Basic** ``` +# Start server node scripts/functional_tests_server --config x-pack/test/apm_api_integration/basic/config.ts -``` - -Trial: -``` -node scripts/functional_tests_server --config x-pack/test/apm_api_integration/trial/config.ts +# Run tests +node scripts/functional_test_runner --config x-pack/test/apm_api_integration/basic/config.ts ``` -**Run tests** +The API tests for "basic" are located in `x-pack/test/apm_api_integration/basic/tests`. -Basic: +**Trial** ``` -node scripts/functional_test_runner --config x-pack/test/apm_api_integration/basic/config.ts -``` - -Trial: +# Start server +node scripts/functional_tests_server --config x-pack/test/apm_api_integration/trial/config.ts -``` +# Run tests node scripts/functional_test_runner --config x-pack/test/apm_api_integration/trial/config.ts ``` -APM tests are located in `x-pack/test/apm_api_integration`. +The API tests for "trial" are located in `x-pack/test/apm_api_integration/trial/tests`. + For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme) ### Linting diff --git a/x-pack/plugins/global_search/server/mocks.ts b/x-pack/plugins/global_search/server/mocks.ts index 8a189a5701708..e7c133edf95c8 100644 --- a/x-pack/plugins/global_search/server/mocks.ts +++ b/x-pack/plugins/global_search/server/mocks.ts @@ -11,6 +11,7 @@ import { RouteHandlerGlobalSearchContext, } from './types'; import { searchServiceMock } from './services/search_service.mock'; +import { contextMock } from './services/context.mock'; const createSetupMock = (): jest.Mocked => { const searchMock = searchServiceMock.createSetupContract(); @@ -29,17 +30,18 @@ const createStartMock = (): jest.Mocked => { }; const createRouteHandlerContextMock = (): jest.Mocked => { - const contextMock = { + const handlerContextMock = { find: jest.fn(), }; - contextMock.find.mockReturnValue(of([])); + handlerContextMock.find.mockReturnValue(of([])); - return contextMock; + return handlerContextMock; }; export const globalSearchPluginMock = { createSetupContract: createSetupMock, createStartContract: createStartMock, createRouteHandlerContext: createRouteHandlerContextMock, + createProviderContext: contextMock.create, }; diff --git a/x-pack/plugins/global_search/server/services/context.mock.ts b/x-pack/plugins/global_search/server/services/context.mock.ts new file mode 100644 index 0000000000000..50c6da109f8dd --- /dev/null +++ b/x-pack/plugins/global_search/server/services/context.mock.ts @@ -0,0 +1,38 @@ +/* + * 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 { + savedObjectsTypeRegistryMock, + savedObjectsClientMock, + elasticsearchServiceMock, + uiSettingsServiceMock, +} from '../../../../../src/core/server/mocks'; + +const createContextMock = () => { + return { + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + typeRegistry: savedObjectsTypeRegistryMock.create(), + }, + elasticsearch: { + legacy: { + client: elasticsearchServiceMock.createScopedClusterClient(), + }, + }, + uiSettings: { + client: uiSettingsServiceMock.createClient(), + }, + }, + }; +}; + +const createFactoryMock = () => () => () => createContextMock(); + +export const contextMock = { + create: createContextMock, + createFactory: createFactoryMock, +}; diff --git a/x-pack/plugins/global_search_providers/kibana.json b/x-pack/plugins/global_search_providers/kibana.json index 025ea2bceed2c..39eca87d0bf89 100644 --- a/x-pack/plugins/global_search_providers/kibana.json +++ b/x-pack/plugins/global_search_providers/kibana.json @@ -2,7 +2,7 @@ "id": "globalSearchProviders", "version": "8.0.0", "kibanaVersion": "kibana", - "server": false, + "server": true, "ui": true, "requiredPlugins": ["globalSearch"], "optionalPlugins": [], diff --git a/x-pack/plugins/global_search_providers/server/index.ts b/x-pack/plugins/global_search_providers/server/index.ts new file mode 100644 index 0000000000000..26e4142d4865a --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { PluginInitializer } from 'src/core/server'; +import { GlobalSearchProvidersPlugin, GlobalSearchProvidersPluginSetupDeps } from './plugin'; + +export const plugin: PluginInitializer<{}, {}, GlobalSearchProvidersPluginSetupDeps, {}> = () => + new GlobalSearchProvidersPlugin(); diff --git a/x-pack/plugins/global_search_providers/server/plugin.test.ts b/x-pack/plugins/global_search_providers/server/plugin.test.ts new file mode 100644 index 0000000000000..c9b51619d1789 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/plugin.test.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 { coreMock } from '../../../../src/core/server/mocks'; +import { globalSearchPluginMock } from '../../global_search/server/mocks'; +import { GlobalSearchProvidersPlugin } from './plugin'; + +describe('GlobalSearchProvidersPlugin', () => { + let plugin: GlobalSearchProvidersPlugin; + let globalSearchSetup: ReturnType; + + beforeEach(() => { + plugin = new GlobalSearchProvidersPlugin(); + globalSearchSetup = globalSearchPluginMock.createSetupContract(); + }); + + describe('#setup', () => { + it('registers the `savedObjects` result provider', () => { + const coreSetup = coreMock.createSetup(); + plugin.setup(coreSetup, { globalSearch: globalSearchSetup }); + + expect(globalSearchSetup.registerResultProvider).toHaveBeenCalledTimes(1); + expect(globalSearchSetup.registerResultProvider).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'savedObjects', + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/global_search_providers/server/plugin.ts b/x-pack/plugins/global_search_providers/server/plugin.ts new file mode 100644 index 0000000000000..64e7802937d80 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/plugin.ts @@ -0,0 +1,28 @@ +/* + * 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 { CoreSetup, Plugin } from 'src/core/server'; +import { GlobalSearchPluginSetup } from '../../global_search/server'; +import { createSavedObjectsResultProvider } from './providers'; + +export interface GlobalSearchProvidersPluginSetupDeps { + globalSearch: GlobalSearchPluginSetup; +} + +export class GlobalSearchProvidersPlugin + implements Plugin<{}, {}, GlobalSearchProvidersPluginSetupDeps, {}> { + setup( + { getStartServices }: CoreSetup<{}, {}>, + { globalSearch }: GlobalSearchProvidersPluginSetupDeps + ) { + globalSearch.registerResultProvider(createSavedObjectsResultProvider()); + return {}; + } + + start() { + return {}; + } +} diff --git a/x-pack/plugins/global_search_providers/server/providers/index.ts b/x-pack/plugins/global_search_providers/server/providers/index.ts new file mode 100644 index 0000000000000..1670871f305d9 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { createSavedObjectsResultProvider } from './saved_objects'; diff --git a/x-pack/plugins/global_search_providers/server/providers/saved_objects/index.ts b/x-pack/plugins/global_search_providers/server/providers/saved_objects/index.ts new file mode 100644 index 0000000000000..4a67fd8b3df18 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/saved_objects/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { createSavedObjectsResultProvider } from './provider'; diff --git a/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.test.ts b/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.test.ts new file mode 100644 index 0000000000000..0085331c5be5f --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.test.ts @@ -0,0 +1,208 @@ +/* + * 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 { SavedObjectsFindResult, SavedObjectsType, SavedObjectTypeRegistry } from 'src/core/server'; +import { mapToResult, mapToResults } from './map_object_to_result'; + +const createType = (props: Partial): SavedObjectsType => { + return { + name: 'type', + hidden: false, + namespaceType: 'single', + mappings: { properties: {} }, + ...props, + }; +}; + +const createObject = ( + props: Partial, + attributes: T +): SavedObjectsFindResult => { + return { + id: 'id', + type: 'dashboard', + references: [], + score: 100, + ...props, + attributes, + }; +}; + +describe('mapToResult', () => { + it('converts a savedObject to a result', () => { + const type = createType({ + name: 'dashboard', + management: { + defaultSearchField: 'title', + getInAppUrl: (obj) => ({ path: `/dashboard/${obj.id}`, uiCapabilitiesPath: '' }), + }, + }); + + const obj = createObject( + { + id: 'dash1', + type: 'dashboard', + score: 42, + }, + { + title: 'My dashboard', + } + ); + + expect(mapToResult(obj, type)).toEqual({ + id: 'dash1', + title: 'My dashboard', + type: 'dashboard', + url: '/dashboard/dash1', + score: 42, + }); + }); + + it('throws if the type do not have management information', () => { + const object = createObject( + { id: 'dash1', type: 'dashboard', score: 42 }, + { title: 'My dashboard' } + ); + + expect(() => { + mapToResult( + object, + createType({ + name: 'dashboard', + management: { + getInAppUrl: (obj) => ({ path: `/dashboard/${obj.id}`, uiCapabilitiesPath: '' }), + }, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Trying to map an object from a type without management metadata"` + ); + + expect(() => { + mapToResult( + object, + createType({ + name: 'dashboard', + management: { + defaultSearchField: 'title', + }, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Trying to map an object from a type without management metadata"` + ); + + expect(() => { + mapToResult( + object, + createType({ + name: 'dashboard', + management: undefined, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Trying to map an object from a type without management metadata"` + ); + }); +}); + +describe('mapToResults', () => { + let typeRegistry: SavedObjectTypeRegistry; + + beforeEach(() => { + typeRegistry = new SavedObjectTypeRegistry(); + }); + + it('converts savedObjects to results', () => { + typeRegistry.registerType( + createType({ + name: 'typeA', + management: { + defaultSearchField: 'title', + getInAppUrl: (obj) => ({ path: `/type-a/${obj.id}`, uiCapabilitiesPath: '' }), + }, + }) + ); + typeRegistry.registerType( + createType({ + name: 'typeB', + management: { + defaultSearchField: 'description', + getInAppUrl: (obj) => ({ path: `/type-b/${obj.id}`, uiCapabilitiesPath: 'foo' }), + }, + }) + ); + typeRegistry.registerType( + createType({ + name: 'typeC', + management: { + defaultSearchField: 'excerpt', + getInAppUrl: (obj) => ({ path: `/type-c/${obj.id}`, uiCapabilitiesPath: 'bar' }), + }, + }) + ); + + const results = [ + createObject( + { + id: 'resultA', + type: 'typeA', + score: 100, + }, + { + title: 'titleA', + field: 'noise', + } + ), + createObject( + { + id: 'resultC', + type: 'typeC', + score: 42, + }, + { + excerpt: 'titleC', + title: 'foo', + } + ), + createObject( + { + id: 'resultB', + type: 'typeB', + score: 69, + }, + { + description: 'titleB', + bar: 'baz', + } + ), + ]; + + expect(mapToResults(results, typeRegistry)).toEqual([ + { + id: 'resultA', + title: 'titleA', + type: 'typeA', + url: '/type-a/resultA', + score: 100, + }, + { + id: 'resultC', + title: 'titleC', + type: 'typeC', + url: '/type-c/resultC', + score: 42, + }, + { + id: 'resultB', + title: 'titleB', + type: 'typeB', + url: '/type-b/resultB', + score: 69, + }, + ]); + }); +}); diff --git a/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.ts b/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.ts new file mode 100644 index 0000000000000..c93558b1a3cf4 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/saved_objects/map_object_to_result.ts @@ -0,0 +1,38 @@ +/* + * 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 { + SavedObjectsType, + ISavedObjectTypeRegistry, + SavedObjectsFindResult, +} from 'src/core/server'; +import { GlobalSearchProviderResult } from '../../../../global_search/server'; + +export const mapToResults = ( + objects: Array>, + registry: ISavedObjectTypeRegistry +): GlobalSearchProviderResult[] => { + return objects.map((obj) => mapToResult(obj, registry.getType(obj.type)!)); +}; + +export const mapToResult = ( + object: SavedObjectsFindResult, + type: SavedObjectsType +): GlobalSearchProviderResult => { + const { defaultSearchField, getInAppUrl } = type.management ?? {}; + if (defaultSearchField === undefined || getInAppUrl === undefined) { + throw new Error('Trying to map an object from a type without management metadata'); + } + return { + id: object.id, + // defaultSearchField is dynamic and not 'directly' bound to the generic type of the SavedObject + // so we are forced to cast the attributes to any to access the properties associated with it. + title: (object.attributes as any)[defaultSearchField], + type: object.type, + url: getInAppUrl(object).path, + score: object.score, + }; +}; diff --git a/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.test.ts b/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.test.ts new file mode 100644 index 0000000000000..84e05c67c5f66 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.test.ts @@ -0,0 +1,166 @@ +/* + * 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 { EMPTY } from 'rxjs'; +import { TestScheduler } from 'rxjs/testing'; +import { + SavedObjectsFindResponse, + SavedObjectsFindResult, + SavedObjectsType, + SavedObjectTypeRegistry, +} from 'src/core/server'; +import { globalSearchPluginMock } from '../../../../global_search/server/mocks'; +import { + GlobalSearchResultProvider, + GlobalSearchProviderFindOptions, +} from '../../../../global_search/server'; +import { createSavedObjectsResultProvider } from './provider'; + +const getTestScheduler = () => + new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + +const createFindResponse = ( + results: SavedObjectsFindResult[] +): SavedObjectsFindResponse => ({ + saved_objects: results, + page: 1, + per_page: 20, + total: results.length, +}); + +const createType = (props: Partial): SavedObjectsType => { + return { + name: 'type', + hidden: false, + namespaceType: 'single', + mappings: { properties: {} }, + ...props, + management: { + defaultSearchField: 'field', + getInAppUrl: (obj) => ({ path: `/object/${obj.id}`, uiCapabilitiesPath: '' }), + ...props.management, + }, + }; +}; + +const createObject = ( + props: Partial, + attributes: T +): SavedObjectsFindResult => { + return { + id: 'id', + type: 'dashboard', + score: 100, + references: [], + ...props, + attributes, + }; +}; + +const defaultOption: GlobalSearchProviderFindOptions = { + preference: 'pref', + maxResults: 20, + aborted$: EMPTY, +}; + +describe('savedObjectsResultProvider', () => { + let provider: GlobalSearchResultProvider; + let registry: SavedObjectTypeRegistry; + let context: ReturnType; + + beforeEach(() => { + provider = createSavedObjectsResultProvider(); + registry = new SavedObjectTypeRegistry(); + + registry.registerType( + createType({ + name: 'typeA', + management: { + defaultSearchField: 'title', + getInAppUrl: (obj) => ({ path: `/type-a/${obj.id}`, uiCapabilitiesPath: '' }), + }, + }) + ); + registry.registerType( + createType({ + name: 'typeB', + management: { + defaultSearchField: 'description', + getInAppUrl: (obj) => ({ path: `/type-b/${obj.id}`, uiCapabilitiesPath: 'foo' }), + }, + }) + ); + + context = globalSearchPluginMock.createProviderContext(); + context.core.savedObjects.client.find.mockResolvedValue(createFindResponse([])); + context.core.savedObjects.typeRegistry = registry as any; + }); + + it('has the correct id', () => { + expect(provider.id).toBe('savedObjects'); + }); + + it('calls `savedObjectClient.find` with the correct parameters', () => { + provider.find('term', defaultOption, context); + + expect(context.core.savedObjects.client.find).toHaveBeenCalledTimes(1); + expect(context.core.savedObjects.client.find).toHaveBeenCalledWith({ + page: 1, + perPage: defaultOption.maxResults, + search: 'term', + preference: 'pref', + searchFields: ['title', 'description'], + type: ['typeA', 'typeB'], + }); + }); + + it('converts the saved objects to results', async () => { + context.core.savedObjects.client.find.mockResolvedValue( + createFindResponse([ + createObject({ id: 'resultA', type: 'typeA', score: 50 }, { title: 'titleA' }), + createObject({ id: 'resultB', type: 'typeB', score: 78 }, { description: 'titleB' }), + ]) + ); + + const results = await provider.find('term', defaultOption, context).toPromise(); + expect(results).toEqual([ + { + id: 'resultA', + title: 'titleA', + type: 'typeA', + url: '/type-a/resultA', + score: 50, + }, + { + id: 'resultB', + title: 'titleB', + type: 'typeB', + url: '/type-b/resultB', + score: 78, + }, + ]); + }); + + it('only emits results until `aborted$` emits', () => { + getTestScheduler().run(({ hot, expectObservable }) => { + // test scheduler doesnt play well with promises. need to workaround by passing + // an observable instead. Behavior with promise is asserted in previous tests of the suite + context.core.savedObjects.client.find.mockReturnValue( + hot('---a', { a: createFindResponse([]) }) as any + ); + + const resultObs = provider.find( + 'term', + { ...defaultOption, aborted$: hot('-(a|)', { a: undefined }) }, + context + ); + + expectObservable(resultObs).toBe('-|'); + }); + }); +}); diff --git a/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.ts b/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.ts new file mode 100644 index 0000000000000..b423b19ebc672 --- /dev/null +++ b/x-pack/plugins/global_search_providers/server/providers/saved_objects/provider.ts @@ -0,0 +1,42 @@ +/* + * 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 { from } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; +import { GlobalSearchResultProvider } from '../../../../global_search/server'; +import { mapToResults } from './map_object_to_result'; + +export const createSavedObjectsResultProvider = (): GlobalSearchResultProvider => { + return { + id: 'savedObjects', + find: (term, { aborted$, maxResults, preference }, { core }) => { + const { typeRegistry, client } = core.savedObjects; + + const searchableTypes = typeRegistry + .getVisibleTypes() + .filter((type) => type.management?.defaultSearchField && type.management?.getInAppUrl); + const searchFields = uniq( + searchableTypes.map((type) => type.management!.defaultSearchField!) + ); + + const responsePromise = client.find({ + page: 1, + perPage: maxResults, + search: term, + preference, + searchFields, + type: searchableTypes.map((type) => type.name), + }); + + return from(responsePromise).pipe( + takeUntil(aborted$), + map((res) => mapToResults(res.saved_objects, typeRegistry)) + ); + }, + }; +}; + +const uniq = (values: T[]): T[] => [...new Set(values)]; diff --git a/x-pack/plugins/security_solution/public/alerts/components/alerts_histogram_panel/index.tsx b/x-pack/plugins/security_solution/public/alerts/components/alerts_histogram_panel/index.tsx index b002700d7eff0..533a9d51a9bcd 100644 --- a/x-pack/plugins/security_solution/public/alerts/components/alerts_histogram_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/alerts/components/alerts_histogram_panel/index.tsx @@ -11,6 +11,7 @@ import styled from 'styled-components'; import { isEmpty } from 'lodash/fp'; import uuid from 'uuid'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { DEFAULT_NUMBER_FORMAT, APP_ID } from '../../../../common/constants'; import { UpdateDateRange } from '../../../common/components/charts/common'; import { LegendItem } from '../../../common/components/charts/draggable_legend_item'; @@ -28,7 +29,7 @@ import { alertsHistogramOptions } from './config'; import { formatAlertsData, getAlertsHistogramQuery, showInitialLoadingSpinner } from './helpers'; import { AlertsHistogram } from './alerts_histogram'; import * as i18n from './translations'; -import { RegisterQuery, AlertsHistogramOption, AlertsAggregation, AlertsTotal } from './types'; +import { AlertsHistogramOption, AlertsAggregation, AlertsTotal } from './types'; import { LinkButton } from '../../../common/components/links'; import { SecurityPageName } from '../../../app/types'; @@ -52,12 +53,11 @@ const ViewAlertsFlexItem = styled(EuiFlexItem)` margin-left: 24px; `; -interface AlertsHistogramPanelProps { +interface AlertsHistogramPanelProps + extends Pick { chartHeight?: number; defaultStackByOption?: AlertsHistogramOption; - deleteQuery?: ({ id }: { id: string }) => void; filters?: Filter[]; - from: number; headerChildren?: React.ReactNode; /** Override all defaults, and only display this field */ onlyField?: string; @@ -65,13 +65,11 @@ interface AlertsHistogramPanelProps { legendPosition?: Position; panelHeight?: number; signalIndexName: string | null; - setQuery: (params: RegisterQuery) => void; showLinkToAlerts?: boolean; showTotalAlertsCount?: boolean; stackByOptions?: AlertsHistogramOption[]; timelineId?: string; title?: string; - to: number; updateDateRange: UpdateDateRange; } diff --git a/x-pack/plugins/security_solution/public/alerts/components/detection_engine_header_page/index.tsx b/x-pack/plugins/security_solution/public/alerts/components/detection_engine_header_page/index.tsx index a3e76557a6ff5..78a18dc336e5b 100644 --- a/x-pack/plugins/security_solution/public/alerts/components/detection_engine_header_page/index.tsx +++ b/x-pack/plugins/security_solution/public/alerts/components/detection_engine_header_page/index.tsx @@ -22,3 +22,5 @@ DetectionEngineHeaderPageComponent.defaultProps = { }; export const DetectionEngineHeaderPage = React.memo(DetectionEngineHeaderPageComponent); + +DetectionEngineHeaderPage.displayName = 'DetectionEngineHeaderPage'; diff --git a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.test.tsx b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.test.tsx index d033bc25e9801..fa7c85c95d87b 100644 --- a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.test.tsx +++ b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.test.tsx @@ -17,6 +17,11 @@ import { useWithSource } from '../../../common/containers/source'; jest.mock('../../components/user_info'); jest.mock('../../../common/containers/source'); jest.mock('../../../common/components/link_to'); +jest.mock('../../../common/containers/use_global_time', () => ({ + useGlobalTime: jest + .fn() + .mockReturnValue({ from: 0, isInitializing: false, to: 0, setQuery: jest.fn() }), +})); jest.mock('react-router-dom', () => { const originalModule = jest.requireActual('react-router-dom'); diff --git a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.tsx index dc0b22c82af3e..5c525a8553477 100644 --- a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/detection_engine.tsx @@ -12,7 +12,7 @@ import { connect, ConnectedProps } from 'react-redux'; import { useHistory } from 'react-router-dom'; import { SecurityPageName } from '../../../app/types'; import { TimelineId } from '../../../../common/types/timeline'; -import { GlobalTime } from '../../../common/containers/global_time'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useWithSource } from '../../../common/containers/source'; import { UpdateDateRange } from '../../../common/components/charts/common'; import { FiltersGlobal } from '../../../common/components/filters_global'; @@ -44,6 +44,7 @@ export const DetectionEnginePageComponent: React.FC = ({ query, setAbsoluteRangeDatePicker, }) => { + const { to, from, deleteQuery, setQuery } = useGlobalTime(); const { loading, isSignalIndexExists, @@ -131,36 +132,28 @@ export const DetectionEnginePageComponent: React.FC = ({ - - {({ to, from, deleteQuery, setQuery }) => ( - <> - <> - - - - - - )} - + + + ) : ( diff --git a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.test.tsx b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.test.tsx index 0acb18082379a..11099e8cfc755 100644 --- a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.test.tsx @@ -18,6 +18,12 @@ import { useParams } from 'react-router-dom'; jest.mock('../../../../../common/components/link_to'); jest.mock('../../../../components/user_info'); jest.mock('../../../../../common/containers/source'); +jest.mock('../../../../../common/containers/use_global_time', () => ({ + useGlobalTime: jest + .fn() + .mockReturnValue({ from: 0, isInitializing: false, to: 0, setQuery: jest.fn() }), +})); + jest.mock('react-router-dom', () => { const originalModule = jest.requireActual('react-router-dom'); @@ -50,6 +56,6 @@ describe('RuleDetailsPageComponent', () => { } ); - expect(wrapper.find('GlobalTime')).toHaveLength(1); + expect(wrapper.find('DetectionEngineHeaderPage')).toHaveLength(1); }); }); diff --git a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.tsx index 2ec603546983e..b937e95c0a57e 100644 --- a/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/alerts/pages/detection_engine/rules/details/index.tsx @@ -56,7 +56,7 @@ import { StepPanel } from '../../../../components/rules/step_panel'; import { getStepsData, redirectToDetections, userHasNoPermissions } from '../helpers'; import * as ruleI18n from '../translations'; import * as i18n from './translations'; -import { GlobalTime } from '../../../../../common/containers/global_time'; +import { useGlobalTime } from '../../../../../common/containers/use_global_time'; import { alertsHistogramOptions } from '../../../../components/alerts_histogram_panel/config'; import { inputsSelectors } from '../../../../../common/store/inputs'; import { State } from '../../../../../common/store'; @@ -103,6 +103,7 @@ export const RuleDetailsPageComponent: FC = ({ query, setAbsoluteRangeDatePicker, }) => { + const { to, from, deleteQuery, setQuery } = useGlobalTime(); const { loading, isSignalIndexExists, @@ -263,169 +264,164 @@ export const RuleDetailsPageComponent: FC = ({ {hasIndexWrite != null && !hasIndexWrite && } {userHasNoPermissions(canUserCRUD) && } {indicesExist ? ( - - {({ to, from, deleteQuery, setQuery }) => ( - - - - - - - - {detectionI18n.LAST_ALERT} - {': '} - {lastAlerts} - , - ] - : []), - , - ]} - title={title} - > - + + + + + + + + {detectionI18n.LAST_ALERT} + {': '} + {lastAlerts} + , + ] + : []), + , + ]} + title={title} + > + + + + + + + + + - - - + {ruleI18n.EDIT_RULE_SETTINGS} + - - - - - {ruleI18n.EDIT_RULE_SETTINGS} - - - - - - + - - {ruleError} - - - - + + + + {ruleError} + + + + + + + + + + + {defineRuleData != null && ( + + )} + - - - - - - {defineRuleData != null && ( - - )} - - - - - - {scheduleRuleData != null && ( - - )} - - - + + + + {scheduleRuleData != null && ( + + )} + + + + + {tabs} + + {ruleDetailTab === RuleDetailTabs.alerts && ( + <> + - {tabs} - - {ruleDetailTab === RuleDetailTabs.alerts && ( - <> - - - {ruleId != null && ( - - )} - - )} - {ruleDetailTab === RuleDetailTabs.exceptions && ( - )} - {ruleDetailTab === RuleDetailTabs.failures && } - - - )} - + + )} + {ruleDetailTab === RuleDetailTabs.exceptions && ( + + )} + {ruleDetailTab === RuleDetailTabs.failures && } + + ) : ( diff --git a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx index 31f7e1b7fac7c..16fe2a6669ff0 100644 --- a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx @@ -31,7 +31,7 @@ import { GetTitle, GetSubTitle, } from '../../components/matrix_histogram/types'; -import { SetQuery } from '../../../hosts/pages/navigation/types'; +import { GlobalTimeArgs } from '../../containers/use_global_time'; import { QueryTemplateProps } from '../../containers/query_template'; import { setAbsoluteRangeDatePicker } from '../../store/inputs/actions'; import { InputsModelId } from '../../store/inputs/constants'; @@ -48,7 +48,7 @@ export interface OwnProps extends QueryTemplateProps { legendPosition?: Position; mapping?: MatrixHistogramMappingTypes; showSpacer?: boolean; - setQuery: SetQuery; + setQuery: GlobalTimeArgs['setQuery']; setAbsoluteRangeDatePickerTarget?: InputsModelId; showLegend?: boolean; stackByOptions: MatrixHistogramOption[]; diff --git a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts index f388409b443db..ff0816758cb0c 100644 --- a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts @@ -8,10 +8,10 @@ import { EuiTitleSize } from '@elastic/eui'; import { ScaleType, Position, TickFormatter } from '@elastic/charts'; import { ActionCreator } from 'redux'; import { ESQuery } from '../../../../common/typed_json'; -import { SetQuery } from '../../../hosts/pages/navigation/types'; import { InputsModelId } from '../../store/inputs/constants'; import { HistogramType } from '../../../graphql/types'; import { UpdateDateRange } from '../charts/common'; +import { GlobalTimeArgs } from '../../containers/use_global_time'; export type MatrixHistogramMappingTypes = Record< string, @@ -47,15 +47,15 @@ interface MatrixHistogramBasicProps { from: number; to: number; }>; - endDate: number; + endDate: GlobalTimeArgs['to']; headerChildren?: React.ReactNode; hideHistogramIfEmpty?: boolean; id: string; legendPosition?: Position; mapping?: MatrixHistogramMappingTypes; panelHeight?: number; - setQuery: SetQuery; - startDate: number; + setQuery: GlobalTimeArgs['setQuery']; + startDate: GlobalTimeArgs['from']; stackByOptions: MatrixHistogramOption[]; subtitle?: string | GetSubTitle; title?: string | GetTitle; diff --git a/x-pack/plugins/security_solution/public/common/components/page/manage_query.tsx b/x-pack/plugins/security_solution/public/common/components/page/manage_query.tsx index 9e78f704b0f05..02d9a62f2890e 100644 --- a/x-pack/plugins/security_solution/public/common/components/page/manage_query.tsx +++ b/x-pack/plugins/security_solution/public/common/components/page/manage_query.tsx @@ -9,16 +9,14 @@ import { omit } from 'lodash/fp'; import React from 'react'; import { inputsModel } from '../../store'; -import { SetQuery } from '../../../hosts/pages/navigation/types'; +import { GlobalTimeArgs } from '../../containers/use_global_time'; -interface OwnProps { - deleteQuery?: ({ id }: { id: string }) => void; +interface OwnProps extends Pick { headerChildren?: React.ReactNode; id: string; legendPosition?: Position; loading: boolean; refetch: inputsModel.Refetch; - setQuery: SetQuery; inspect?: inputsModel.InspectQuery; } diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx index b453760ebcf09..0b2f1f1e35cc7 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { connect, ConnectedProps } from 'react-redux'; -import { GlobalTime } from '../../containers/global_time'; +import { useGlobalTime } from '../../containers/use_global_time'; import { BrowserFields } from '../../containers/source'; import { useKibana } from '../../lib/kibana'; import { @@ -104,60 +104,55 @@ const StatefulTopNComponent: React.FC = ({ value, }) => { const kibana = useKibana(); + const { from, deleteQuery, setQuery, to } = useGlobalTime(); const options = getOptions( timelineId === TimelineId.active ? activeTimelineEventType : undefined ); return ( - - {({ from, deleteQuery, setQuery, to }) => ( - - )} - + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx index 7d19bf21271aa..5e2fd998224c6 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/top_n.tsx @@ -9,10 +9,10 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { ActionCreator } from 'typescript-fsa'; +import { GlobalTimeArgs } from '../../containers/use_global_time'; import { EventsByDataset } from '../../../overview/components/events_by_dataset'; import { SignalsByCategory } from '../../../overview/components/signals_by_category'; import { Filter, IIndexPattern, Query } from '../../../../../../../src/plugins/data/public'; -import { inputsModel } from '../../store'; import { InputsModelId } from '../../store/inputs/constants'; import { EventType } from '../../../timelines/store/timeline/model'; @@ -43,13 +43,11 @@ const TopNContent = styled.div` } `; -export interface Props { +export interface Props extends Pick { combinedQueries?: string; defaultView: EventType; - deleteQuery?: ({ id }: { id: string }) => void; field: string; filters: Filter[]; - from: number; indexPattern: IIndexPattern; indexToAdd?: string[] | null; options: TopNOption[]; @@ -60,13 +58,6 @@ export interface Props { to: number; }>; setAbsoluteRangeDatePickerTarget: InputsModelId; - setQuery: (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; - to: number; timelineId?: string; toggleTopN: () => void; onFilterAdded?: () => void; diff --git a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts index a2009809a9916..d716df70246f7 100644 --- a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts +++ b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts @@ -7,7 +7,7 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import { NarrowDateRange } from '../../../components/ml/types'; import { UpdateDateRange } from '../../../components/charts/common'; -import { SetQuery } from '../../../../hosts/pages/navigation/types'; +import { GlobalTimeArgs } from '../../use_global_time'; import { FlowTarget } from '../../../../graphql/types'; import { HostsType } from '../../../../hosts/store/model'; import { NetworkType } from '../../../../network/store//model'; @@ -22,11 +22,11 @@ export type AnomaliesQueryTabBodyProps = QueryTabBodyProps & { // eslint-disable-next-line @typescript-eslint/no-explicit-any AnomaliesTableComponent: React.NamedExoticComponent; deleteQuery?: ({ id }: { id: string }) => void; - endDate: number; + endDate: GlobalTimeArgs['to']; flowTarget?: FlowTarget; narrowDateRange: NarrowDateRange; - setQuery: SetQuery; - startDate: number; + setQuery: GlobalTimeArgs['setQuery']; + startDate: GlobalTimeArgs['from']; skip: boolean; updateDateRange?: UpdateDateRange; hideHistogramIfEmpty?: boolean; diff --git a/x-pack/plugins/security_solution/public/common/containers/global_time/index.tsx b/x-pack/plugins/security_solution/public/common/containers/global_time/index.tsx deleted file mode 100644 index 9c9778c7074ee..0000000000000 --- a/x-pack/plugins/security_solution/public/common/containers/global_time/index.tsx +++ /dev/null @@ -1,98 +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, { useCallback, useState, useEffect } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; - -import { inputsModel, inputsSelectors, State } from '../../store'; -import { inputsActions } from '../../store/actions'; - -interface SetQuery { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch | inputsModel.RefetchKql; -} - -export interface GlobalTimeArgs { - from: number; - to: number; - setQuery: ({ id, inspect, loading, refetch }: SetQuery) => void; - deleteQuery?: ({ id }: { id: string }) => void; - isInitializing: boolean; -} - -interface OwnProps { - children: (args: GlobalTimeArgs) => React.ReactNode; -} - -type GlobalTimeProps = OwnProps & PropsFromRedux; - -export const GlobalTimeComponent: React.FC = ({ - children, - deleteAllQuery, - deleteOneQuery, - from, - to, - setGlobalQuery, -}) => { - const [isInitializing, setIsInitializing] = useState(true); - - const setQuery = useCallback( - ({ id, inspect, loading, refetch }: SetQuery) => - setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), - [setGlobalQuery] - ); - - const deleteQuery = useCallback( - ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), - [deleteOneQuery] - ); - - useEffect(() => { - if (isInitializing) { - setIsInitializing(false); - } - return () => { - deleteAllQuery({ id: 'global' }); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - <> - {children({ - isInitializing, - from, - to, - setQuery, - deleteQuery, - })} - - ); -}; - -const mapStateToProps = (state: State) => { - const timerange: inputsModel.TimeRange = inputsSelectors.globalTimeRangeSelector(state); - return { - from: timerange.from, - to: timerange.to, - }; -}; - -const mapDispatchToProps = { - deleteAllQuery: inputsActions.deleteAllQuery, - deleteOneQuery: inputsActions.deleteOneQuery, - setGlobalQuery: inputsActions.setQuery, -}; - -export const connector = connect(mapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; - -export const GlobalTime = connector(React.memo(GlobalTimeComponent)); - -GlobalTime.displayName = 'GlobalTime'; diff --git a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx new file mode 100644 index 0000000000000..9d5f1740b0276 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx @@ -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 { act, renderHook } from '@testing-library/react-hooks'; + +import { useGlobalTime } from '.'; + +jest.mock('react-redux', () => { + const originalModule = jest.requireActual('react-redux'); + + return { + ...originalModule, + useDispatch: jest.fn().mockReturnValue(jest.fn()), + useSelector: jest.fn().mockReturnValue({ from: 0, to: 0 }), + }; +}); + +describe('useGlobalTime', () => { + test('returns memoized value', () => { + const { result, rerender } = renderHook(() => useGlobalTime()); + + const result1 = result.current; + act(() => rerender()); + const result2 = result.current; + + expect(result1).toBe(result2); + expect(result1.from).toBe(0); + expect(result1.to).toBe(0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx new file mode 100644 index 0000000000000..b63616ecbcf56 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useCallback, useState, useEffect, useMemo } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { inputsSelectors } from '../../store'; +import { inputsActions } from '../../store/actions'; +import { SetQuery, DeleteQuery } from './types'; + +export const useGlobalTime = () => { + const dispatch = useDispatch(); + const { from, to } = useSelector(inputsSelectors.globalTimeRangeSelector); + const [isInitializing, setIsInitializing] = useState(true); + + const setQuery = useCallback( + ({ id, inspect, loading, refetch }: SetQuery) => + dispatch(inputsActions.setQuery({ inputId: 'global', id, inspect, loading, refetch })), + [dispatch] + ); + + const deleteQuery = useCallback( + ({ id }: DeleteQuery) => dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id })), + [dispatch] + ); + + useEffect(() => { + if (isInitializing) { + setIsInitializing(false); + } + return () => { + dispatch(inputsActions.deleteAllQuery({ id: 'global' })); + }; + }, [dispatch, isInitializing]); + + const memoizedReturn = useMemo( + () => ({ + isInitializing, + from, + to, + setQuery, + deleteQuery, + }), + [deleteQuery, from, isInitializing, setQuery, to] + ); + + return memoizedReturn; +}; + +export type GlobalTimeArgs = Omit, 'deleteQuery'> & + Partial, 'deleteQuery'>>; diff --git a/x-pack/plugins/security_solution/public/common/containers/use_global_time/types.ts b/x-pack/plugins/security_solution/public/common/containers/use_global_time/types.ts new file mode 100644 index 0000000000000..9903c29202b29 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/use_global_time/types.ts @@ -0,0 +1,14 @@ +/* + * 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 { inputsActions } from '../../store/actions'; + +export type SetQuery = Pick< + Parameters[0], + 'id' | 'inspect' | 'loading' | 'refetch' +>; + +export type DeleteQuery = Pick[0], 'id'>; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx index e520facf285c2..cce48a1e605b2 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx @@ -21,6 +21,12 @@ jest.mock('../../../common/containers/source', () => ({ useWithSource: jest.fn().mockReturnValue({ indicesExist: true, indexPattern: mockIndexPattern }), })); +jest.mock('../../../common/containers/use_global_time', () => ({ + useGlobalTime: jest + .fn() + .mockReturnValue({ from: 0, isInitializing: false, to: 0, setQuery: jest.fn() }), +})); + // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar jest.mock('../../../common/components/search_bar', () => ({ diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx index 505d0f37ca039..acde0cbe1d42b 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx @@ -12,6 +12,7 @@ import { scoreIntervalToDateTime } from '../../../common/components/ml/score/sco import { Anomaly } from '../../../common/components/ml/types'; import { HostsTableType } from '../../store/model'; import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anomalies_query_tab_body'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; import { AnomaliesHostTable } from '../../../common/components/ml/tables/anomalies_host_table'; import { HostDetailsTabsProps } from './types'; @@ -28,17 +29,13 @@ import { export const HostDetailsTabs = React.memo( ({ pageFilters, - deleteQuery, filterQuery, - from, - isInitializing, detailName, setAbsoluteRangeDatePicker, - setQuery, - to, indexPattern, hostDetailsPagePath, }) => { + const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime(); const narrowDateRange = useCallback( (score: Anomaly, interval: string) => { const fromTo = scoreIntervalToDateTime(score, interval); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index 1c66a9edc1947..46823f037b61c 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -27,6 +27,7 @@ import { SiemSearchBar } from '../../../common/components/search_bar'; import { WrapperPage } from '../../../common/components/wrapper_page'; import { HostOverviewByNameQuery } from '../../containers/hosts/overview'; import { KpiHostDetailsQuery } from '../../containers/kpi_host_details'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useWithSource } from '../../../common/containers/source'; import { LastEventIndexKey } from '../../../graphql/types'; import { useKibana } from '../../../common/lib/kibana'; @@ -50,17 +51,13 @@ const KpiHostDetailsManage = manageQuery(KpiHostsComponent); const HostDetailsComponent = React.memo( ({ filters, - from, - isInitializing, query, setAbsoluteRangeDatePicker, setHostDetailsTablesActivePageToZero, - setQuery, - to, detailName, - deleteQuery, hostDetailsPagePath, }) => { + const { to, from, deleteQuery, setQuery, isInitializing } = useGlobalTime(); useEffect(() => { setHostDetailsTablesActivePageToZero(); }, [setHostDetailsTablesActivePageToZero, detailName]); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts index aa6288d473c91..7a440964c31ea 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts @@ -32,7 +32,7 @@ interface HostDetailsComponentDispatchProps extends HostBodyComponentDispatchPro setHostDetailsTablesActivePageToZero: ActionCreator; } -export interface HostDetailsProps extends HostsQueryProps { +export interface HostDetailsProps { detailName: string; hostDetailsPagePath: string; } diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx index 1ea3a3020a1d5..566f8f23efd39 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx @@ -59,15 +59,8 @@ const mockHistory = { listen: jest.fn(), }; -const to = new Date('2018-03-23T18:49:23.132Z').valueOf(); -const from = new Date('2018-03-24T03:33:52.253Z').valueOf(); - describe('Hosts - rendering', () => { const hostProps: HostsComponentProps = { - from, - to, - setQuery: jest.fn(), - isInitializing: false, hostsPagePath: '', }; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index f5cc651a30443..90438aec7c27e 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -22,6 +22,7 @@ import { manageQuery } from '../../common/components/page/manage_query'; import { SiemSearchBar } from '../../common/components/search_bar'; import { WrapperPage } from '../../common/components/wrapper_page'; import { KpiHostsQuery } from '../containers/kpi_hosts'; +import { useGlobalTime } from '../../common/containers/use_global_time'; import { useWithSource } from '../../common/containers/source'; import { LastEventIndexKey } from '../../graphql/types'; import { useKibana } from '../../common/lib/kibana'; @@ -44,17 +45,8 @@ import { HostsTableType } from '../store/model'; const KpiHostsComponentManage = manageQuery(KpiHostsComponent); export const HostsComponent = React.memo( - ({ - deleteQuery, - isInitializing, - filters, - from, - query, - setAbsoluteRangeDatePicker, - setQuery, - to, - hostsPagePath, - }) => { + ({ filters, query, setAbsoluteRangeDatePicker, hostsPagePath }) => { + const { to, from, deleteQuery, setQuery, isInitializing } = useGlobalTime(); const capabilities = useMlCapabilities(); const kibana = useKibana(); const { tabName } = useParams(); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx index c2285cf0a97e1..75cd36924dbba 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx @@ -11,7 +11,6 @@ import { HostDetails } from './details'; import { HostsTableType } from '../store/model'; import { MlHostConditionalContainer } from '../../common/components/ml/conditional_links/ml_host_conditional_container'; -import { GlobalTime } from '../../common/containers/global_time'; import { Hosts } from './hosts'; import { hostsPagePath, hostDetailsPagePath } from './types'; @@ -36,72 +35,49 @@ type Props = Partial> & { url: string }; export const HostsContainer = React.memo(({ url }) => { const history = useHistory(); + return ( - - {({ to, from, setQuery, deleteQuery, isInitializing }) => ( - - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - { - history.replace(`${detailName}/${HostsTableType.authentications}${search}`); - return null; - }} - /> + + ( + + )} + /> + + + + } + /> + { + history.replace(`${detailName}/${HostsTableType.authentications}${search}`); + return null; + }} + /> - { - history.replace(`${HostsTableType.hosts}${search}`); - return null; - }} - /> - - )} - + { + history.replace(`${HostsTableType.hosts}${search}`); + return null; + }} + /> + ); }); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts index 76f56fe1718aa..ddee940d11799 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts @@ -7,8 +7,7 @@ import { ESTermQuery } from '../../../../common/typed_json'; import { Filter, IIndexPattern } from '../../../../../../../src/plugins/data/public'; import { NarrowDateRange } from '../../../common/components/ml/types'; -import { InspectQuery, Refetch } from '../../../common/store/inputs/model'; - +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { HostsTableType, HostsType } from '../../store/model'; import { NavTab } from '../../../common/components/navigation/types'; import { UpdateDateRange } from '../../../common/components/charts/common'; @@ -24,31 +23,19 @@ type KeyHostsNavTab = KeyHostsNavTabWithoutMlPermission | KeyHostsNavTabWithMlPe export type HostsNavTab = Record; -export type SetQuery = ({ - id, - inspect, - loading, - refetch, -}: { - id: string; - inspect: InspectQuery | null; - loading: boolean; - refetch: Refetch; -}) => void; - export interface QueryTabBodyProps { type: HostsType; - startDate: number; - endDate: number; + startDate: GlobalTimeArgs['from']; + endDate: GlobalTimeArgs['to']; filterQuery?: string | ESTermQuery; } export type HostsComponentsQueryProps = QueryTabBodyProps & { - deleteQuery?: ({ id }: { id: string }) => void; + deleteQuery?: GlobalTimeArgs['deleteQuery']; indexPattern: IIndexPattern; pageFilters?: Filter[]; skip: boolean; - setQuery: SetQuery; + setQuery: GlobalTimeArgs['setQuery']; updateDateRange?: UpdateDateRange; narrowDateRange?: NarrowDateRange; }; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/types.ts index ffd17b0ef46f6..2c9ca4e4d27d9 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/types.ts @@ -8,23 +8,26 @@ import { IIndexPattern } from 'src/plugins/data/public'; import { ActionCreator } from 'typescript-fsa'; import { hostsModel } from '../store'; -import { GlobalTimeArgs } from '../../common/containers/global_time'; +import { GlobalTimeArgs } from '../../common/containers/use_global_time'; import { InputsModelId } from '../../common/store/inputs/constants'; export const hostsPagePath = '/'; export const hostDetailsPagePath = `/:detailName`; -export type HostsTabsProps = HostsComponentProps & { - filterQuery: string; - type: hostsModel.HostsType; - indexPattern: IIndexPattern; - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: number; - to: number; - }>; -}; +export type HostsTabsProps = HostsComponentProps & + GlobalTimeArgs & { + filterQuery: string; + type: hostsModel.HostsType; + indexPattern: IIndexPattern; + setAbsoluteRangeDatePicker: ActionCreator<{ + id: InputsModelId; + from: number; + to: number; + }>; + }; export type HostsQueryProps = GlobalTimeArgs; -export type HostsComponentProps = HostsQueryProps & { hostsPagePath: string }; +export interface HostsComponentProps { + hostsPagePath: string; +} diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.test.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.test.tsx index 33eadad9aa774..76e197063fb8a 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.test.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { useIndexPatterns } from '../../../common/hooks/use_index_patterns'; import { EmbeddedMapComponent } from './embedded_map'; -import { SetQuery } from './types'; const mockUseIndexPatterns = useIndexPatterns as jest.Mock; jest.mock('../../../common/hooks/use_index_patterns'); @@ -18,7 +17,7 @@ mockUseIndexPatterns.mockImplementation(() => [true, []]); jest.mock('../../../common/lib/kibana'); describe('EmbeddedMapComponent', () => { - let setQuery: SetQuery; + let setQuery: jest.Mock; beforeEach(() => { setQuery = jest.fn(); diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.tsx index 6470fc270d0bf..81aa4b1671fca 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map.tsx @@ -15,13 +15,13 @@ import { getIndexPatternTitleIdMapping } from '../../../common/hooks/api/helpers import { useIndexPatterns } from '../../../common/hooks/use_index_patterns'; import { Loader } from '../../../common/components/loader'; import { displayErrorToast, useStateToaster } from '../../../common/components/toasters'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { Embeddable } from './embeddable'; import { EmbeddableHeader } from './embeddable_header'; import { createEmbeddable, findMatchingIndexPatterns } from './embedded_map_helpers'; import { IndexPatternsMissingPrompt } from './index_patterns_missing_prompt'; import { MapToolTip } from './map_tool_tip/map_tool_tip'; import * as i18n from './translations'; -import { SetQuery } from './types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { MapEmbeddable } from '../../../../../../plugins/maps/public/embeddable'; import { Query, Filter } from '../../../../../../../src/plugins/data/public'; @@ -73,7 +73,7 @@ export interface EmbeddedMapProps { filters: Filter[]; startDate: number; endDate: number; - setQuery: SetQuery; + setQuery: GlobalTimeArgs['setQuery']; } export const EmbeddedMapComponent = ({ diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx index b0f8e2cc02403..c58e53d07acba 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx @@ -8,7 +8,7 @@ import uuid from 'uuid'; import React from 'react'; import { OutPortal, PortalNode } from 'react-reverse-portal'; import minimatch from 'minimatch'; -import { IndexPatternMapping, SetQuery } from './types'; +import { IndexPatternMapping } from './types'; import { getLayerList } from './map_config'; import { MAP_SAVED_OBJECT_TYPE } from '../../../../../maps/public'; import { @@ -30,6 +30,7 @@ import { ErrorEmbeddable, } from '../../../../../../../src/plugins/embeddable/public'; import { IndexPatternSavedObject } from '../../../common/hooks/types'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; /** * Creates MapEmbeddable with provided initial configuration @@ -49,9 +50,9 @@ export const createEmbeddable = async ( filters: Filter[], indexPatterns: IndexPatternMapping[], query: Query, - startDate: number, - endDate: number, - setQuery: SetQuery, + startDate: GlobalTimeArgs['from'], + endDate: GlobalTimeArgs['to'], + setQuery: GlobalTimeArgs['setQuery'], portalNode: PortalNode, embeddableApi: EmbeddableStart ): Promise => { diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts b/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts index e3ca3c5b84289..700071f88a4b5 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts @@ -6,7 +6,6 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { RenderTooltipContentParams } from '../../../../../maps/public/classes/tooltips/tooltip_property'; -import { inputsModel } from '../../../common/store/inputs'; export interface IndexPatternMapping { title: string; @@ -29,12 +28,10 @@ export interface LayerMappingCollection { [indexPatternTitle: string]: LayerMapping; } -export type SetQuery = (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; -}) => void; +export interface MapFeature { + id: number; + layerId: string; +} export interface FeatureGeometry { coordinates: [number]; diff --git a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx index 2bae19ce89aec..72e3161de5373 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx @@ -36,7 +36,7 @@ import { GetSubTitle, } from '../../../common/components/matrix_histogram/types'; import { UpdateDateRange } from '../../../common/components/charts/common'; -import { SetQuery } from '../../../hosts/pages/navigation/types'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { networkModel, networkSelectors } from '../../store'; const ID = 'networkDnsQuery'; @@ -67,7 +67,7 @@ interface DnsHistogramOwnProps extends QueryTemplatePaginatedProps { isDnsHistogram?: boolean; query: DocumentNode; scaleType: ScaleType; - setQuery: SetQuery; + setQuery: GlobalTimeArgs['setQuery']; showLegend?: boolean; stackByOptions: MatrixHistogramOption[]; subtitle?: string | GetSubTitle; diff --git a/x-pack/plugins/security_solution/public/network/pages/index.tsx b/x-pack/plugins/security_solution/public/network/pages/index.tsx index c7a8a5f705dfe..9ac05cc98bb45 100644 --- a/x-pack/plugins/security_solution/public/network/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/index.tsx @@ -13,7 +13,6 @@ import { FlowTarget } from '../../graphql/types'; import { IPDetails } from './ip_details'; import { Network } from './network'; -import { GlobalTime } from '../../common/containers/global_time'; import { getNetworkRoutePath } from './navigation'; import { NetworkRouteType } from './navigation/types'; import { MlNetworkConditionalContainer } from '../../common/components/ml/conditional_links/ml_network_conditional_container'; @@ -36,71 +35,48 @@ const NetworkContainerComponent: React.FC = () => { ); return ( - - {({ to, from, setQuery, deleteQuery, isInitializing }) => ( - - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - { - history.replace(`ip/${detailName}/${FlowTarget.source}${search}`); - return null; - }} - /> - { - history.replace(`${NetworkRouteType.flows}${search}`); - return null; - }} - /> - - )} - + + ( + + )} + /> + + + + } + /> + { + history.replace(`ip/${detailName}/${FlowTarget.source}${search}`); + return null; + }} + /> + { + history.replace(`${NetworkRouteType.flows}${search}`); + return null; + }} + /> + ); }; diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx b/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx index 962a6269f8488..92f39228f07a7 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx @@ -33,6 +33,11 @@ type GlobalWithFetch = NodeJS.Global & { fetch: jest.Mock }; jest.mock('../../../common/lib/kibana'); jest.mock('../../../common/containers/source'); +jest.mock('../../../common/containers/use_global_time', () => ({ + useGlobalTime: jest + .fn() + .mockReturnValue({ from: 0, isInitializing: false, to: 0, setQuery: jest.fn() }), +})); // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx index 162b3a7c158d5..6686b40e3c429 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx @@ -9,6 +9,7 @@ import React, { useCallback, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; import { FiltersGlobal } from '../../../common/components/filters_global'; import { HeaderPage } from '../../../common/components/header_page'; import { LastEventTime } from '../../../common/components/last_event_time'; @@ -51,14 +52,11 @@ export const IPDetailsComponent: React.FC { + const { to, from, setQuery, isInitializing } = useGlobalTime(); const type = networkModel.NetworkType.details; const narrowDateRange = useCallback( (score, interval) => { diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts b/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts index 02d83208884b4..75fb5007f2701 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts @@ -8,16 +8,15 @@ import { IIndexPattern } from 'src/plugins/data/public'; import { ESTermQuery } from '../../../../common/typed_json'; import { NetworkType } from '../../store/model'; -import { InspectQuery, Refetch } from '../../../common/store/inputs/model'; import { FlowTarget, FlowTargetSourceDest } from '../../../graphql/types'; -import { GlobalTimeArgs } from '../../../common/containers/global_time'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; export const type = NetworkType.details; -export type IPDetailsComponentProps = GlobalTimeArgs & { +export interface IPDetailsComponentProps { detailName: string; flowTarget: FlowTarget; -}; +} export interface OwnProps { type: NetworkType; @@ -26,17 +25,7 @@ export interface OwnProps { filterQuery: string | ESTermQuery; ip: string; skip: boolean; - setQuery: ({ - id, - inspect, - loading, - refetch, - }: { - id: string; - inspect: InspectQuery | null; - loading: boolean; - refetch: Refetch; - }) => void; + setQuery: GlobalTimeArgs['setQuery']; } export type NetworkComponentsQueryProps = OwnProps & { diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts index 433ed7fffd741..6986d10ad3523 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts @@ -10,7 +10,7 @@ import { IIndexPattern } from '../../../../../../../src/plugins/data/common'; import { NavTab } from '../../../common/components/navigation/types'; import { FlowTargetSourceDest } from '../../../graphql/types'; import { networkModel } from '../../store'; -import { GlobalTimeArgs } from '../../../common/containers/global_time'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { SetAbsoluteRangeDatePicker } from '../types'; import { NarrowDateRange } from '../../../common/components/ml/types'; diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx index 4275c1641f517..bdaac1ac049e5 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx @@ -23,6 +23,7 @@ import { KpiNetworkComponent } from '..//components/kpi_network'; import { SiemSearchBar } from '../../common/components/search_bar'; import { WrapperPage } from '../../common/components/wrapper_page'; import { KpiNetworkQuery } from '../../network/containers/kpi_network'; +import { useGlobalTime } from '../../common/containers/use_global_time'; import { useWithSource } from '../../common/containers/source'; import { LastEventIndexKey } from '../../graphql/types'; import { useKibana } from '../../common/lib/kibana'; @@ -47,13 +48,10 @@ const NetworkComponent = React.memo( query, setAbsoluteRangeDatePicker, networkPagePath, - to, - from, - setQuery, - isInitializing, hasMlUserPermissions, capabilitiesFetched, }) => { + const { to, from, setQuery, isInitializing } = useGlobalTime(); const kibana = useKibana(); const { tabName } = useParams(); diff --git a/x-pack/plugins/security_solution/public/network/pages/types.ts b/x-pack/plugins/security_solution/public/network/pages/types.ts index e4170ee4b908b..54ff5a8d50b8e 100644 --- a/x-pack/plugins/security_solution/public/network/pages/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/types.ts @@ -7,7 +7,6 @@ import { RouteComponentProps } from 'react-router-dom'; import { ActionCreator } from 'typescript-fsa'; import { InputsModelId } from '../../common/store/inputs/constants'; -import { GlobalTimeArgs } from '../../common/containers/global_time'; export type SetAbsoluteRangeDatePicker = ActionCreator<{ id: InputsModelId; @@ -15,9 +14,8 @@ export type SetAbsoluteRangeDatePicker = ActionCreator<{ to: number; }>; -export type NetworkComponentProps = Partial> & - GlobalTimeArgs & { - networkPagePath: string; - hasMlUserPermissions: boolean; - capabilitiesFetched: boolean; - }; +export type NetworkComponentProps = Partial> & { + networkPagePath: string; + hasMlUserPermissions: boolean; + capabilitiesFetched: boolean; +}; diff --git a/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx b/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx index 03e8279f01db7..6e59d81a1eae9 100644 --- a/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx @@ -19,7 +19,6 @@ import { IIndexPattern, Query, } from '../../../../../../../src/plugins/data/public'; -import { inputsModel } from '../../../common/store'; import { HostsTableType, HostsType } from '../../../hosts/store/model'; import * as i18n from '../../pages/translations'; @@ -29,6 +28,7 @@ import { } from '../../../common/components/alerts_viewer/histogram_configs'; import { MatrixHisrogramConfigs } from '../../../common/components/matrix_histogram/types'; import { getTabsOnHostsUrl } from '../../../common/components/link_to/redirect_to_hosts'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { SecurityPageName } from '../../../app/types'; import { useFormatUrl } from '../../../common/components/link_to'; import { LinkButton } from '../../../common/components/links'; @@ -39,20 +39,11 @@ const NO_FILTERS: Filter[] = []; const DEFAULT_QUERY: Query = { query: '', language: 'kuery' }; const DEFAULT_STACK_BY = 'event.module'; -interface Props { - deleteQuery?: ({ id }: { id: string }) => void; +interface Props extends Pick { filters?: Filter[]; - from: number; hideHeaderChildren?: boolean; indexPattern: IIndexPattern; query?: Query; - setQuery: (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; - to: number; } const AlertsByCategoryComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx index 1773af86a382f..23f5998f44111 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -20,7 +20,7 @@ import { IIndexPattern, Query, } from '../../../../../../../src/plugins/data/public'; -import { inputsModel } from '../../../common/store'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; const HorizontalSpacer = styled(EuiFlexItem)` width: 24px; @@ -29,18 +29,10 @@ const HorizontalSpacer = styled(EuiFlexItem)` const NO_FILTERS: Filter[] = []; const DEFAULT_QUERY: Query = { query: '', language: 'kuery' }; -interface Props { +interface Props extends Pick { filters?: Filter[]; - from: number; indexPattern: IIndexPattern; query?: Query; - setQuery: (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; - to: number; } const EventCountsComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx index 7d42f744a2613..f18fccee50e22 100644 --- a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx @@ -27,9 +27,9 @@ import { IIndexPattern, Query, } from '../../../../../../../src/plugins/data/public'; -import { inputsModel } from '../../../common/store'; import { HostsTableType, HostsType } from '../../../hosts/store/model'; import { InputsModelId } from '../../../common/store/inputs/constants'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import * as i18n from '../../pages/translations'; import { SecurityPageName } from '../../../app/types'; @@ -42,26 +42,17 @@ const DEFAULT_STACK_BY = 'event.dataset'; const ID = 'eventsByDatasetOverview'; -interface Props { +interface Props extends Pick { combinedQueries?: string; - deleteQuery?: ({ id }: { id: string }) => void; filters?: Filter[]; - from: number; headerChildren?: React.ReactNode; indexPattern: IIndexPattern; indexToAdd?: string[] | null; onlyField?: string; query?: Query; setAbsoluteRangeDatePickerTarget?: InputsModelId; - setQuery: (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; showSpacer?: boolean; timelineId?: string; - to: number; } const getHistogramOption = (fieldName: string): MatrixHistogramOption => ({ diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_host/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_host/index.tsx index 195bb4fa0807a..583c76d1464a8 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_host/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_host/index.tsx @@ -18,26 +18,16 @@ import { useUiSetting$, useKibana } from '../../../common/lib/kibana'; import { getHostsUrl, useFormatUrl } from '../../../common/components/link_to'; import { getOverviewHostStats, OverviewHostStats } from '../overview_host_stats'; import { manageQuery } from '../../../common/components/page/manage_query'; -import { inputsModel } from '../../../common/store/inputs'; import { InspectButtonContainer } from '../../../common/components/inspect'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { SecurityPageName } from '../../../app/types'; import { LinkButton } from '../../../common/components/links'; export interface OwnProps { - startDate: number; - endDate: number; + startDate: GlobalTimeArgs['from']; + endDate: GlobalTimeArgs['to']; filterQuery?: ESQuery | string; - setQuery: ({ - id, - inspect, - loading, - refetch, - }: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; + setQuery: GlobalTimeArgs['setQuery']; } const OverviewHostStatsManage = manageQuery(OverviewHostStats); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_network/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_network/index.tsx index a3760863bcb62..8282eaeb63c28 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_network/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_network/index.tsx @@ -19,28 +19,18 @@ import { ID as OverviewNetworkQueryId, OverviewNetworkQuery, } from '../../containers/overview_network'; -import { inputsModel } from '../../../common/store/inputs'; import { getOverviewNetworkStats, OverviewNetworkStats } from '../overview_network_stats'; import { getNetworkUrl, useFormatUrl } from '../../../common/components/link_to'; import { InspectButtonContainer } from '../../../common/components/inspect'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { SecurityPageName } from '../../../app/types'; import { LinkButton } from '../../../common/components/links'; export interface OverviewNetworkProps { - startDate: number; - endDate: number; + startDate: GlobalTimeArgs['from']; + endDate: GlobalTimeArgs['to']; filterQuery?: ESQuery | string; - setQuery: ({ - id, - inspect, - loading, - refetch, - }: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; + setQuery: GlobalTimeArgs['setQuery']; } const OverviewNetworkStatsManage = manageQuery(OverviewNetworkStats); diff --git a/x-pack/plugins/security_solution/public/overview/components/signals_by_category/index.tsx b/x-pack/plugins/security_solution/public/overview/components/signals_by_category/index.tsx index 41152dabe2ad8..8b62df60b257f 100644 --- a/x-pack/plugins/security_solution/public/overview/components/signals_by_category/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/signals_by_category/index.tsx @@ -11,19 +11,17 @@ import { alertsHistogramOptions } from '../../../alerts/components/alerts_histog import { useSignalIndex } from '../../../alerts/containers/detection_engine/alerts/use_signal_index'; import { SetAbsoluteRangeDatePicker } from '../../../network/pages/types'; import { Filter, IIndexPattern, Query } from '../../../../../../../src/plugins/data/public'; -import { inputsModel } from '../../../common/store'; import { InputsModelId } from '../../../common/store/inputs/constants'; import * as i18n from '../../pages/translations'; import { UpdateDateRange } from '../../../common/components/charts/common'; +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; const DEFAULT_QUERY: Query = { query: '', language: 'kuery' }; const DEFAULT_STACK_BY = 'signal.rule.threat.tactic.name'; const NO_FILTERS: Filter[] = []; -interface Props { - deleteQuery?: ({ id }: { id: string }) => void; +interface Props extends Pick { filters?: Filter[]; - from: number; headerChildren?: React.ReactNode; indexPattern: IIndexPattern; /** Override all defaults, and only display this field */ @@ -31,14 +29,7 @@ interface Props { query?: Query; setAbsoluteRangeDatePicker: SetAbsoluteRangeDatePicker; setAbsoluteRangeDatePickerTarget?: InputsModelId; - setQuery: (params: { - id: string; - inspect: inputsModel.InspectQuery | null; - loading: boolean; - refetch: inputsModel.Refetch; - }) => void; timelineId?: string; - to: number; } const SignalsByCategoryComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx index bf5e7f0c211b1..9613a1e7210a3 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx @@ -19,6 +19,11 @@ import { Overview } from './index'; jest.mock('../../common/lib/kibana'); jest.mock('../../common/containers/source'); +jest.mock('../../common/containers/use_global_time', () => ({ + useGlobalTime: jest + .fn() + .mockReturnValue({ from: 0, isInitializing: false, to: 0, setQuery: jest.fn() }), +})); // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index b8b8a67024c9f..2a522d3ea8fde 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -5,7 +5,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import React, { useState, useMemo } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { Query, Filter } from 'src/plugins/data/public'; @@ -15,7 +15,7 @@ import { AlertsByCategory } from '../components/alerts_by_category'; import { FiltersGlobal } from '../../common/components/filters_global'; import { SiemSearchBar } from '../../common/components/search_bar'; import { WrapperPage } from '../../common/components/wrapper_page'; -import { GlobalTime } from '../../common/containers/global_time'; +import { useGlobalTime } from '../../common/containers/use_global_time'; import { useWithSource } from '../../common/containers/source'; import { EventsByDataset } from '../components/events_by_dataset'; import { EventCounts } from '../components/event_counts'; @@ -46,6 +46,7 @@ const OverviewComponent: React.FC = ({ return [ENDPOINT_METADATA_INDEX]; }, []); + const { from, deleteQuery, setQuery, to } = useGlobalTime(); const { indicesExist, indexPattern } = useWithSource(); const { indicesExist: metadataIndexExists } = useWithSource( 'default', @@ -59,10 +60,10 @@ const OverviewComponent: React.FC = ({ ); const [dismissMessage, setDismissMessage] = useState(hasDismissEndpointNoticeMessage); - const dismissEndpointNotice = () => { + const dismissEndpointNotice = useCallback(() => { setDismissMessage(true); addMessage('management', 'dismissEndpointNotice'); - }; + }, [addMessage]); return ( <> @@ -85,59 +86,55 @@ const OverviewComponent: React.FC = ({ - - {({ from, deleteQuery, setQuery, to }) => ( - - - - - - - - - - - - - - - - - - - )} - + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index 2af5506436e20..d2003d982e0b6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -411,7 +411,7 @@ export const ActionForm = ({ const noConnectorsLabel = ( Promise; + findTest: (term: string) => Promise; + findReal: (term: string) => Promise; } export interface GlobalSearchTestPluginSetupDeps { @@ -74,7 +75,7 @@ export class GlobalSearchTestPlugin { globalSearch }: GlobalSearchTestPluginStartDeps ): GlobalSearchTestPluginStart { return { - findAll: (term) => + findTest: (term) => globalSearch .find(term, {}) .pipe( @@ -84,6 +85,16 @@ export class GlobalSearchTestPlugin reduce((memo, results) => [...memo, ...results]) ) .toPromise(), + findReal: (term) => + globalSearch + .find(term, {}) + .pipe( + map((batch) => batch.results), + // remove test types + map((results) => results.filter((r) => !r.type.startsWith('test_'))), + reduce((memo, results) => [...memo, ...results]) + ) + .toPromise(), }; } } diff --git a/x-pack/test/plugin_functional/test_suites/global_search/global_search_api.ts b/x-pack/test/plugin_functional/test_suites/global_search/global_search_api.ts index ee1745436b735..841c4d2967e21 100644 --- a/x-pack/test/plugin_functional/test_suites/global_search/global_search_api.ts +++ b/x-pack/test/plugin_functional/test_suites/global_search/global_search_api.ts @@ -17,7 +17,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { return browser.executeAsync(async (term, cb) => { const { start } = window.__coreProvider; const globalSearchTestApi: GlobalSearchTestApi = start.plugins.globalSearchTest; - globalSearchTestApi.findAll(term).then(cb); + globalSearchTestApi.findTest(term).then(cb); }, t); }; diff --git a/x-pack/test/plugin_functional/test_suites/global_search/global_search_providers.ts b/x-pack/test/plugin_functional/test_suites/global_search/global_search_providers.ts new file mode 100644 index 0000000000000..4e4f42578d11a --- /dev/null +++ b/x-pack/test/plugin_functional/test_suites/global_search/global_search_providers.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { GlobalSearchResult } from '../../../../plugins/global_search/common/types'; +import { GlobalSearchTestApi } from '../../plugins/global_search_test/public/types'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['common']); + const browser = getService('browser'); + const esArchiver = getService('esArchiver'); + + const findResultsWithAPI = async (t: string): Promise => { + return browser.executeAsync(async (term, cb) => { + const { start } = window.__coreProvider; + const globalSearchTestApi: GlobalSearchTestApi = start.plugins.globalSearchTest; + globalSearchTestApi.findReal(term).then(cb); + }, t); + }; + + describe('GlobalSearch - SavedObject provider', function () { + before(async () => { + await esArchiver.load('global_search/basic'); + }); + + after(async () => { + await esArchiver.unload('global_search/basic'); + }); + + beforeEach(async () => { + await pageObjects.common.navigateToApp('globalSearchTestApp'); + }); + + it('can search for index patterns', async () => { + const results = await findResultsWithAPI('logstash'); + expect(results.length).to.be(1); + expect(results[0].type).to.be('index-pattern'); + expect(results[0].title).to.be('logstash-*'); + expect(results[0].score).to.be.greaterThan(1); + }); + + it('can search for visualizations', async () => { + const results = await findResultsWithAPI('pie'); + expect(results.length).to.be(1); + expect(results[0].type).to.be('visualization'); + expect(results[0].title).to.be('A Pie'); + }); + + it('can search for maps', async () => { + const results = await findResultsWithAPI('just'); + expect(results.length).to.be(1); + expect(results[0].type).to.be('map'); + expect(results[0].title).to.be('just a map'); + }); + + it('can search for dashboards', async () => { + const results = await findResultsWithAPI('Amazing'); + expect(results.length).to.be(1); + expect(results[0].type).to.be('dashboard'); + expect(results[0].title).to.be('Amazing Dashboard'); + }); + + it('returns all objects matching the search', async () => { + const results = await findResultsWithAPI('dashboard'); + expect(results.length).to.be.greaterThan(2); + expect(results.map((r) => r.title)).to.contain('dashboard with map'); + expect(results.map((r) => r.title)).to.contain('Amazing Dashboard'); + }); + }); +} diff --git a/x-pack/test/plugin_functional/test_suites/global_search/index.ts b/x-pack/test/plugin_functional/test_suites/global_search/index.ts index 1e5a765612f45..d765e87add105 100644 --- a/x-pack/test/plugin_functional/test_suites/global_search/index.ts +++ b/x-pack/test/plugin_functional/test_suites/global_search/index.ts @@ -10,5 +10,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('GlobalSearch API', function () { this.tags('ciGroup7'); loadTestFile(require.resolve('./global_search_api')); + loadTestFile(require.resolve('./global_search_providers')); }); }