diff --git a/.ci/end2end.groovy b/.ci/end2end.groovy index ed642f22cfeb4..97099c6f87448 100644 --- a/.ci/end2end.groovy +++ b/.ci/end2end.groovy @@ -14,6 +14,7 @@ pipeline { HOME = "${env.WORKSPACE}" E2E_DIR = 'x-pack/plugins/apm/e2e' PIPELINE_LOG_LEVEL = 'DEBUG' + KBN_OPTIMIZER_THEMES = 'v7light' } options { timeout(time: 1, unit: 'HOURS') 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 {i18n.translate('data.noDataPopover.content', { defaultMessage: - "This time range doesn't contain any data. Increase or adjust the time range to see more fields and create charts", + "This time range doesn't contain any data. Increase or adjust the time range to see more fields and create charts.", })}

@@ -66,11 +66,13 @@ export function NoDataPopover({ step={1} stepsTotal={1} isStepOpen={noDataPopoverVisible} - subtitle={i18n.translate('data.noDataPopover.title', { defaultMessage: 'Tip' })} - title="" + subtitle={i18n.translate('data.noDataPopover.subtitle', { defaultMessage: 'Tip' })} + title={i18n.translate('data.noDataPopover.title', { defaultMessage: 'Empty dataset' })} footerAction={ { storage.set(NO_DATA_POPOVER_STORAGE_KEY, true); diff --git a/src/plugins/data/server/saved_objects/index.ts b/src/plugins/data/server/saved_objects/index.ts index 4326200141179..102183fc1c5ed 100644 --- a/src/plugins/data/server/saved_objects/index.ts +++ b/src/plugins/data/server/saved_objects/index.ts @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - -export { searchSavedObjectType } from './search'; export { querySavedObjectType } from './query'; export { indexPatternSavedObjectType } from './index_patterns'; export { kqlTelemetry } from './kql_telementry'; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index df809b425eb9e..34ed8c6c6f401 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -27,7 +27,6 @@ import { } from './types'; import { registerSearchRoute } from './routes'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; -import { searchSavedObjectType } from '../saved_objects'; import { DataPluginStart } from '../plugin'; export class SearchService implements Plugin { @@ -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/infra/common/log_analysis/log_analysis.ts b/x-pack/plugins/infra/common/log_analysis/log_analysis.ts index f0aa2067a24c2..b8fba7a14e243 100644 --- a/x-pack/plugins/infra/common/log_analysis/log_analysis.ts +++ b/x-pack/plugins/infra/common/log_analysis/log_analysis.ts @@ -35,7 +35,7 @@ export type SetupStatus = | { type: 'skipped'; newlyCreated?: boolean; - }; // setup is hidden + }; // setup is not necessary /** * Maps a job status to the possibility that results have already been produced diff --git a/x-pack/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx b/x-pack/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx deleted file mode 100644 index 9f55126a1440a..0000000000000 --- a/x-pack/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx +++ /dev/null @@ -1,161 +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 { EuiBadge, EuiButton, EuiPopover, EuiPopoverTitle, EuiSelectable } from '@elastic/eui'; -import { EuiSelectableOption } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useCallback, useMemo } from 'react'; -import { v4 as uuidv4 } from 'uuid'; - -import { LogColumnConfiguration } from '../../utils/source_configuration'; -import { useVisibilityState } from '../../utils/use_visibility_state'; -import { euiStyled } from '../../../../observability/public'; - -interface SelectableColumnOption { - optionProps: EuiSelectableOption; - columnConfiguration: LogColumnConfiguration; -} - -export const AddLogColumnButtonAndPopover: React.FunctionComponent<{ - addLogColumn: (logColumnConfiguration: LogColumnConfiguration) => void; - availableFields: string[]; - isDisabled?: boolean; -}> = ({ addLogColumn, availableFields, isDisabled }) => { - const { isVisible: isOpen, show: openPopover, hide: closePopover } = useVisibilityState(false); - - const availableColumnOptions = useMemo( - () => [ - { - optionProps: { - append: , - 'data-test-subj': 'addTimestampLogColumn', - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with field names - key: 'timestamp', - label: 'Timestamp', - }, - columnConfiguration: { - timestampColumn: { - id: uuidv4(), - }, - }, - }, - { - optionProps: { - 'data-test-subj': 'addMessageLogColumn', - append: , - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with field names - key: 'message', - label: 'Message', - }, - columnConfiguration: { - messageColumn: { - id: uuidv4(), - }, - }, - }, - ...availableFields.map((field) => ({ - optionProps: { - 'data-test-subj': `addFieldLogColumn addFieldLogColumn:${field}`, - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with fields that only differ in the - // case (e.g. the metricbeat mongodb module) - key: `field-${field}`, - label: field, - }, - columnConfiguration: { - fieldColumn: { - id: uuidv4(), - field, - }, - }, - })), - ], - [availableFields] - ); - - const availableOptions = useMemo( - () => availableColumnOptions.map((availableColumnOption) => availableColumnOption.optionProps), - [availableColumnOptions] - ); - - const handleColumnSelection = useCallback( - (selectedOptions: EuiSelectableOption[]) => { - closePopover(); - - const selectedOptionIndex = selectedOptions.findIndex( - (selectedOption) => selectedOption.checked === 'on' - ); - const selectedOption = availableColumnOptions[selectedOptionIndex]; - - addLogColumn(selectedOption.columnConfiguration); - }, - [addLogColumn, availableColumnOptions, closePopover] - ); - - return ( - - - - } - closePopover={closePopover} - id="addLogColumn" - isOpen={isOpen} - ownFocus - panelPaddingSize="none" - > - - {(list, search) => ( - - {search} - {list} - - )} - - - ); -}; - -const searchProps = { - 'data-test-subj': 'fieldSearchInput', -}; - -const selectableListProps = { - showIcons: false, -}; - -const SystemColumnBadge: React.FunctionComponent = () => ( - - - -); - -const SelectableContent = euiStyled.div` - width: 400px; -`; diff --git a/x-pack/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx b/x-pack/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx index 369f07be67bf4..5ad05deafd69d 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx @@ -27,9 +27,7 @@ interface FieldsConfigurationPanelProps { isLoading: boolean; readOnly: boolean; podFieldProps: InputFieldProps; - tiebreakerFieldProps: InputFieldProps; timestampFieldProps: InputFieldProps; - displaySettings: 'metrics' | 'logs'; } export const FieldsConfigurationPanel = ({ @@ -38,15 +36,12 @@ export const FieldsConfigurationPanel = ({ isLoading, readOnly, podFieldProps, - tiebreakerFieldProps, timestampFieldProps, - displaySettings, }: FieldsConfigurationPanelProps) => { const isHostValueDefault = hostFieldProps.value === 'host.name'; const isContainerValueDefault = containerFieldProps.value === 'container.id'; const isPodValueDefault = podFieldProps.value === 'kubernetes.pod.uid'; const isTimestampValueDefault = timestampFieldProps.value === '@timestamp'; - const isTiebreakerValueDefault = tiebreakerFieldProps.value === '_doc'; return ( @@ -139,194 +134,141 @@ export const FieldsConfigurationPanel = ({ /> - {displaySettings === 'logs' && ( - <> - - - - } - description={ - - } - > - _doc, - }} - /> - } - isInvalid={tiebreakerFieldProps.isInvalid} - label={ - - } - > - - - - - )} - {displaySettings === 'metrics' && ( - <> - - - - } - description={ - - } - > - container.id, - }} - /> - } - isInvalid={containerFieldProps.isInvalid} - label={ - - } - > - - - - - - - } - description={ - - } - > - host.name, - }} - /> - } - isInvalid={hostFieldProps.isInvalid} - label={ - - } - > - - - - - - - } - description={ - - } - > - kubernetes.pod.uid, - }} - /> - } - isInvalid={podFieldProps.isInvalid} - label={ - - } - > - - - - - )} + + + + } + description={ + + } + > + container.id, + }} + /> + } + isInvalid={containerFieldProps.isInvalid} + label={ + + } + > + + + + + + + } + description={ + + } + > + host.name, + }} + /> + } + isInvalid={hostFieldProps.isInvalid} + label={ + + } + > + + + + + + + } + description={ + + } + > + kubernetes.pod.uid, + }} + /> + } + isInvalid={podFieldProps.isInvalid} + label={ + + } + > + + + ); }; diff --git a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx index 1d634b781bd34..e9817331ace93 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx @@ -21,17 +21,13 @@ import { InputFieldProps } from './input_fields'; interface IndicesConfigurationPanelProps { isLoading: boolean; readOnly: boolean; - logAliasFieldProps: InputFieldProps; metricAliasFieldProps: InputFieldProps; - displaySettings: 'metrics' | 'logs'; } export const IndicesConfigurationPanel = ({ isLoading, readOnly, - logAliasFieldProps, metricAliasFieldProps, - displaySettings, }: IndicesConfigurationPanelProps) => ( @@ -43,101 +39,51 @@ export const IndicesConfigurationPanel = ({ - {displaySettings === 'metrics' && ( - - - - } - description={ + - } - > - metricbeat-*, - }} - /> - } - isInvalid={metricAliasFieldProps.isInvalid} - label={ - - } - > - + } + description={ + + } + > + metrics-*,metricbeat-*, + }} /> - - - )} - {displaySettings === 'logs' && ( - - - } - description={ + isInvalid={metricAliasFieldProps.isInvalid} + label={ } > - filebeat-*, - }} - /> - } - isInvalid={logAliasFieldProps.isInvalid} - label={ - - } - > - - - - )} + disabled={isLoading} + readOnly={readOnly} + isLoading={isLoading} + {...metricAliasFieldProps} + /> + + ); diff --git a/x-pack/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx b/x-pack/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx deleted file mode 100644 index 46ab1e65c29d1..0000000000000 --- a/x-pack/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx +++ /dev/null @@ -1,279 +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 { - EuiButtonIcon, - EuiEmptyPrompt, - EuiForm, - EuiPanel, - EuiSpacer, - EuiText, - EuiTitle, - EuiFlexGroup, - EuiFlexItem, - EuiDragDropContext, - EuiDraggable, - EuiDroppable, - EuiIcon, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useCallback } from 'react'; -import { DragHandleProps, DropResult } from '../../../../observability/public'; - -import { AddLogColumnButtonAndPopover } from './add_log_column_popover'; -import { - FieldLogColumnConfigurationProps, - LogColumnConfigurationProps, -} from './log_columns_configuration_form_state'; -import { LogColumnConfiguration } from '../../utils/source_configuration'; - -interface LogColumnsConfigurationPanelProps { - availableFields: string[]; - isLoading: boolean; - logColumnConfiguration: LogColumnConfigurationProps[]; - addLogColumn: (logColumn: LogColumnConfiguration) => void; - moveLogColumn: (sourceIndex: number, destinationIndex: number) => void; -} - -export const LogColumnsConfigurationPanel: React.FunctionComponent = ({ - addLogColumn, - moveLogColumn, - availableFields, - isLoading, - logColumnConfiguration, -}) => { - const onDragEnd = useCallback( - ({ source, destination }: DropResult) => - destination && moveLogColumn(source.index, destination.index), - [moveLogColumn] - ); - - return ( - - - - -

- -

-
-
- - - -
- {logColumnConfiguration.length > 0 ? ( - - - <> - {/* Fragment here necessary for typechecking */} - {logColumnConfiguration.map((column, index) => ( - - {(provided) => ( - - )} - - ))} - - - - ) : ( - - )} -
- ); -}; - -interface LogColumnConfigurationPanelProps { - logColumnConfigurationProps: LogColumnConfigurationProps; - dragHandleProps: DragHandleProps; -} - -const LogColumnConfigurationPanel: React.FunctionComponent = ( - props -) => ( - <> - - {props.logColumnConfigurationProps.type === 'timestamp' ? ( - - ) : props.logColumnConfigurationProps.type === 'message' ? ( - - ) : ( - - )} - -); - -const TimestampLogColumnConfigurationPanel: React.FunctionComponent = ({ - logColumnConfigurationProps, - dragHandleProps, -}) => ( - timestamp, - }} - /> - } - removeColumn={logColumnConfigurationProps.remove} - dragHandleProps={dragHandleProps} - /> -); - -const MessageLogColumnConfigurationPanel: React.FunctionComponent = ({ - logColumnConfigurationProps, - dragHandleProps, -}) => ( - - } - removeColumn={logColumnConfigurationProps.remove} - dragHandleProps={dragHandleProps} - /> -); - -const FieldLogColumnConfigurationPanel: React.FunctionComponent<{ - logColumnConfigurationProps: FieldLogColumnConfigurationProps; - dragHandleProps: DragHandleProps; -}> = ({ - logColumnConfigurationProps: { - logColumnConfiguration: { field }, - remove, - }, - dragHandleProps, -}) => { - const fieldLogColumnTitle = i18n.translate( - 'xpack.infra.sourceConfiguration.fieldLogColumnTitle', - { - defaultMessage: 'Field', - } - ); - return ( - - - -
- -
-
- {fieldLogColumnTitle} - - {field} - - - - -
-
- ); -}; - -const ExplainedLogColumnConfigurationPanel: React.FunctionComponent<{ - fieldName: React.ReactNode; - helpText: React.ReactNode; - removeColumn: () => void; - dragHandleProps: DragHandleProps; -}> = ({ fieldName, helpText, removeColumn, dragHandleProps }) => ( - - - -
- -
-
- {fieldName} - - - {helpText} - - - - - -
-
-); - -const RemoveLogColumnButton: React.FunctionComponent<{ - onClick?: () => void; - columnDescription: string; -}> = ({ onClick, columnDescription }) => { - const removeColumnLabel = i18n.translate( - 'xpack.infra.sourceConfiguration.removeLogColumnButtonLabel', - { - defaultMessage: 'Remove {columnDescription} column', - values: { columnDescription }, - } - ); - - return ( - - ); -}; - -const LogColumnConfigurationEmptyPrompt: React.FunctionComponent = () => ( - - - - } - body={ -

- -

- } - /> -); diff --git a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx index 43bdc1f4cedcc..53b62f8dda04c 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx @@ -22,19 +22,16 @@ import { Source } from '../../containers/source'; import { FieldsConfigurationPanel } from './fields_configuration_panel'; import { IndicesConfigurationPanel } from './indices_configuration_panel'; import { NameConfigurationPanel } from './name_configuration_panel'; -import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel'; import { useSourceConfigurationFormState } from './source_configuration_form_state'; import { SourceLoadingPage } from '../source_loading_page'; import { Prompt } from '../../utils/navigation_warning_prompt'; interface SourceConfigurationSettingsProps { shouldAllowEdit: boolean; - displaySettings: 'metrics' | 'logs'; } export const SourceConfigurationSettings = ({ shouldAllowEdit, - displaySettings, }: SourceConfigurationSettingsProps) => { const { createSourceConfiguration, @@ -45,16 +42,8 @@ export const SourceConfigurationSettings = ({ updateSourceConfiguration, } = useContext(Source.Context); - const availableFields = useMemo( - () => (source && source.status ? source.status.indexFields.map((field) => field.name) : []), - [source] - ); - const { - addLogColumn, - moveLogColumn, indicesConfigurationProps, - logColumnConfigurationProps, errors, resetForm, isFormDirty, @@ -119,10 +108,8 @@ export const SourceConfigurationSettings = ({ @@ -133,23 +120,10 @@ export const SourceConfigurationSettings = ({ isLoading={isLoading} podFieldProps={indicesConfigurationProps.podField} readOnly={!isWriteable} - tiebreakerFieldProps={indicesConfigurationProps.tiebreakerField} timestampFieldProps={indicesConfigurationProps.timestampField} - displaySettings={displaySettings} /> - {displaySettings === 'logs' && ( - - - - )} {errors.length > 0 ? ( <> diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx index 10205e9684ef2..a0046b630bfe1 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx @@ -252,7 +252,7 @@ const getSetupStatus = (everyJobStatus: Record(everyJobStatus).reduce((setupStatus, [, jobStatus]) => { if (jobStatus === 'missing') { return { type: 'required', reason: 'missing' }; - } else if (setupStatus.type === 'required') { + } else if (setupStatus.type === 'required' || setupStatus.type === 'succeeded') { return setupStatus; } else if (setupStatus.type === 'skipped' || isJobStatusWithResults(jobStatus)) { return { diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx index 5d9adb8a4f6ec..26633cd190a07 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx @@ -5,8 +5,8 @@ */ import { i18n } from '@kbn/i18n'; -import React, { useEffect } from 'react'; -import { isSetupStatusWithResults } from '../../../../common/log_analysis'; +import React, { useEffect, useState, useCallback } from 'react'; +import { isJobStatusWithResults } from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, @@ -21,6 +21,7 @@ import { useLogSourceContext } from '../../../containers/logs/log_source'; import { LogEntryCategoriesResultsContent } from './page_results_content'; import { LogEntryCategoriesSetupContent } from './page_setup_content'; import { useLogEntryCategoriesModuleContext } from './use_log_entry_categories_module'; +import { LogEntryCategoriesSetupFlyout } from './setup_flyout'; export const LogEntryCategoriesPageContent = () => { const { @@ -37,7 +38,11 @@ export const LogEntryCategoriesPageContent = () => { hasLogAnalysisSetupCapabilities, } = useLogAnalysisCapabilitiesContext(); - const { fetchJobStatus, setupStatus } = useLogEntryCategoriesModuleContext(); + const { fetchJobStatus, setupStatus, jobStatus } = useLogEntryCategoriesModuleContext(); + + const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); + const openFlyout = useCallback(() => setIsFlyoutOpen(true), []); + const closeFlyout = useCallback(() => setIsFlyoutOpen(false), []); useEffect(() => { if (hasLogAnalysisReadCapabilities) { @@ -45,6 +50,13 @@ export const LogEntryCategoriesPageContent = () => { } }, [fetchJobStatus, hasLogAnalysisReadCapabilities]); + // Open flyout if there are no ML jobs + useEffect(() => { + if (setupStatus.type === 'required' && setupStatus.reason === 'missing') { + openFlyout(); + } + }, [setupStatus, openFlyout]); + if (isLoading || isUninitialized) { return ; } else if (hasFailedLoadingSource) { @@ -63,11 +75,21 @@ export const LogEntryCategoriesPageContent = () => { ); } else if (setupStatus.type === 'unknown') { return ; - } else if (isSetupStatusWithResults(setupStatus)) { - return ; + } else if (isJobStatusWithResults(jobStatus['log-entry-categories-count'])) { + return ( + <> + + + + ); } else if (!hasLogAnalysisSetupCapabilities) { return ; } else { - return ; + return ( + <> + + + + ); } }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx index a00351551e2d7..b4c044fe1cfcb 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx @@ -24,7 +24,13 @@ import { const JOB_STATUS_POLLING_INTERVAL = 30000; -export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => { +interface LogEntryCategoriesResultsContentProps { + onOpenSetup: () => void; +} + +export const LogEntryCategoriesResultsContent: React.FunctionComponent = ({ + onOpenSetup, +}) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results', delay: 15000 }); @@ -123,12 +129,25 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => { [setAutoRefresh] ); + const viewSetupFlyoutForReconfiguration = useCallback(() => { + viewSetupForReconfiguration(); + onOpenSetup(); + }, [onOpenSetup, viewSetupForReconfiguration]); + + const viewSetupFlyoutForUpdate = useCallback(() => { + viewSetupForUpdate(); + onOpenSetup(); + }, [onOpenSetup, viewSetupForUpdate]); + const hasResults = useMemo(() => topLogEntryCategories.length > 0, [ topLogEntryCategories.length, ]); const isFirstUse = useMemo( - () => setupStatus.type === 'skipped' && !!setupStatus.newlyCreated && !hasResults, + () => + ((setupStatus.type === 'skipped' && !!setupStatus.newlyCreated) || + setupStatus.type === 'succeeded') && + !hasResults, [hasResults, setupStatus] ); @@ -184,8 +203,8 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => { hasOutdatedJobDefinitions={hasOutdatedJobDefinitions} hasStoppedJobs={hasStoppedJobs} isFirstUse={isFirstUse} - onRecreateMlJobForReconfiguration={viewSetupForReconfiguration} - onRecreateMlJobForUpdate={viewSetupForUpdate} + onRecreateMlJobForReconfiguration={viewSetupFlyoutForReconfiguration} + onRecreateMlJobForUpdate={viewSetupFlyoutForUpdate} qualityWarnings={categoryQualityWarnings} /> @@ -197,7 +216,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => { isLoadingTopCategories={isLoadingTopLogEntryCategories} jobId={jobIds['log-entry-categories-count']} onChangeDatasetSelection={setCategoryQueryDatasets} - onRequestRecreateMlJob={viewSetupForReconfiguration} + onRequestRecreateMlJob={viewSetupFlyoutForReconfiguration} selectedDatasets={categoryQueryDatasets} sourceId={sourceId} timeRange={categoryQueryTimeRange.timeRange} diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_setup_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_setup_content.tsx index 7ae38234ae221..8d5d8a42200e6 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_setup_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_setup_content.tsx @@ -4,98 +4,51 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiSpacer, EuiSteps, EuiText } from '@elastic/eui'; +import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useMemo } from 'react'; +import { EuiText, EuiButton, EuiSpacer } from '@elastic/eui'; -import { BetaBadge } from '../../../components/beta_badge'; import { - createInitialConfigurationStep, - createProcessStep, LogAnalysisSetupPage, LogAnalysisSetupPageContent, LogAnalysisSetupPageHeader, } from '../../../components/logging/log_analysis_setup'; import { useTrackPageview } from '../../../../../observability/public'; -import { useLogEntryCategoriesSetup } from './use_log_entry_categories_setup'; -export const LogEntryCategoriesSetupContent: React.FunctionComponent = () => { +interface LogEntryCategoriesSetupContentProps { + onOpenSetup: () => void; +} + +export const LogEntryCategoriesSetupContent: React.FunctionComponent = ({ + onOpenSetup, +}) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_setup' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_setup', delay: 15000 }); - const { - cleanUpAndSetUp, - endTime, - isValidating, - lastSetupErrorMessages, - setEndTime, - setStartTime, - setValidatedIndices, - setUp, - setupStatus, - startTime, - validatedIndices, - validationErrors, - viewResults, - } = useLogEntryCategoriesSetup(); - - const steps = useMemo( - () => [ - createInitialConfigurationStep({ - setStartTime, - setEndTime, - startTime, - endTime, - isValidating, - validatedIndices, - setupStatus, - setValidatedIndices, - validationErrors, - }), - createProcessStep({ - cleanUpAndSetUp, - errorMessages: lastSetupErrorMessages, - isConfigurationValid: validationErrors.length <= 0 && !isValidating, - setUp, - setupStatus, - viewResults, - }), - ], - [ - cleanUpAndSetUp, - endTime, - isValidating, - lastSetupErrorMessages, - setEndTime, - setStartTime, - setUp, - setValidatedIndices, - setupStatus, - startTime, - validatedIndices, - validationErrors, - viewResults, - ] - ); - return ( {' '} - + defaultMessage="Set up log category analysis" + /> - +

+ +

- + + +
); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/setup_flyout.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/setup_flyout.tsx new file mode 100644 index 0000000000000..ab5eae1ab3004 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/setup_flyout.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useMemo, useCallback } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiTitle, + EuiText, + EuiSpacer, + EuiSteps, +} from '@elastic/eui'; + +import { + createInitialConfigurationStep, + createProcessStep, +} from '../../../components/logging/log_analysis_setup'; +import { useLogEntryCategoriesSetup } from './use_log_entry_categories_setup'; + +interface LogEntryCategoriesSetupFlyoutProps { + isOpen: boolean; + onClose: () => void; +} + +export const LogEntryCategoriesSetupFlyout: React.FC = ({ + isOpen, + onClose, +}) => { + const { + cleanUpAndSetUp, + endTime, + isValidating, + lastSetupErrorMessages, + setEndTime, + setStartTime, + setValidatedIndices, + setUp, + setupStatus, + startTime, + validatedIndices, + validationErrors, + viewResults, + } = useLogEntryCategoriesSetup(); + + const viewResultsAndClose = useCallback(() => { + viewResults(); + onClose(); + }, [viewResults, onClose]); + + const steps = useMemo( + () => [ + createInitialConfigurationStep({ + setStartTime, + setEndTime, + startTime, + endTime, + isValidating, + validatedIndices, + setupStatus, + setValidatedIndices, + validationErrors, + }), + createProcessStep({ + cleanUpAndSetUp, + errorMessages: lastSetupErrorMessages, + isConfigurationValid: validationErrors.length <= 0 && !isValidating, + setUp, + setupStatus, + viewResults: viewResultsAndClose, + }), + ], + [ + cleanUpAndSetUp, + endTime, + isValidating, + lastSetupErrorMessages, + setEndTime, + setStartTime, + setUp, + setValidatedIndices, + setupStatus, + startTime, + validatedIndices, + validationErrors, + viewResultsAndClose, + ] + ); + + if (!isOpen) { + return null; + } + return ( + + + +

+ +

+
+
+ + +

+ +

+
+ + + + + +
+
+ ); +}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx index 4ec05a9778512..012b694bdbd25 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx @@ -5,8 +5,8 @@ */ import { i18n } from '@kbn/i18n'; -import React, { useEffect } from 'react'; -import { isSetupStatusWithResults } from '../../../../common/log_analysis'; +import React, { useEffect, useState, useCallback } from 'react'; +import { isJobStatusWithResults } from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, @@ -21,6 +21,7 @@ import { useLogSourceContext } from '../../../containers/logs/log_source'; import { LogEntryRateResultsContent } from './page_results_content'; import { LogEntryRateSetupContent } from './page_setup_content'; import { useLogEntryRateModuleContext } from './use_log_entry_rate_module'; +import { LogEntryRateSetupFlyout } from './setup_flyout'; export const LogEntryRatePageContent = () => { const { @@ -37,7 +38,11 @@ export const LogEntryRatePageContent = () => { hasLogAnalysisSetupCapabilities, } = useLogAnalysisCapabilitiesContext(); - const { fetchJobStatus, setupStatus } = useLogEntryRateModuleContext(); + const { fetchJobStatus, setupStatus, jobStatus } = useLogEntryRateModuleContext(); + + const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); + const openFlyout = useCallback(() => setIsFlyoutOpen(true), []); + const closeFlyout = useCallback(() => setIsFlyoutOpen(false), []); useEffect(() => { if (hasLogAnalysisReadCapabilities) { @@ -45,6 +50,13 @@ export const LogEntryRatePageContent = () => { } }, [fetchJobStatus, hasLogAnalysisReadCapabilities]); + // Open flyout if there are no ML jobs + useEffect(() => { + if (setupStatus.type === 'required' && setupStatus.reason === 'missing') { + openFlyout(); + } + }, [setupStatus, openFlyout]); + if (isLoading || isUninitialized) { return ; } else if (hasFailedLoadingSource) { @@ -63,11 +75,21 @@ export const LogEntryRatePageContent = () => { ); } else if (setupStatus.type === 'unknown') { return ; - } else if (isSetupStatusWithResults(setupStatus)) { - return ; + } else if (isJobStatusWithResults(jobStatus['log-entry-rate'])) { + return ( + <> + + + + ); } else if (!hasLogAnalysisSetupCapabilities) { return ; } else { - return ; + return ( + <> + + + + ); } }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx index 3c8db3f8246c0..bf4dbcd87cc41 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx @@ -36,7 +36,13 @@ import { const JOB_STATUS_POLLING_INTERVAL = 30000; -export const LogEntryRateResultsContent: React.FunctionComponent = () => { +interface LogEntryRateResultsContentProps { + onOpenSetup: () => void; +} + +export const LogEntryRateResultsContent: React.FunctionComponent = ({ + onOpenSetup, +}) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results', delay: 15000 }); @@ -127,13 +133,26 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { [setAutoRefresh] ); + const viewSetupFlyoutForReconfiguration = useCallback(() => { + viewSetupForReconfiguration(); + onOpenSetup(); + }, [viewSetupForReconfiguration, onOpenSetup]); + + const viewSetupFlyoutForUpdate = useCallback(() => { + viewSetupForUpdate(); + onOpenSetup(); + }, [viewSetupForUpdate, onOpenSetup]); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ const hasResults = useMemo(() => (logEntryRate?.histogramBuckets?.length ?? 0) > 0, [ logEntryRate, ]); const isFirstUse = useMemo( - () => setupStatus.type === 'skipped' && !!setupStatus.newlyCreated && !hasResults, + () => + ((setupStatus.type === 'skipped' && !!setupStatus.newlyCreated) || + setupStatus.type === 'succeeded') && + !hasResults, [hasResults, setupStatus] ); @@ -209,8 +228,8 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { hasOutdatedJobDefinitions={hasOutdatedJobDefinitions} hasStoppedJobs={hasStoppedJobs} isFirstUse={isFirstUse} - onRecreateMlJobForReconfiguration={viewSetupForReconfiguration} - onRecreateMlJobForUpdate={viewSetupForUpdate} + onRecreateMlJobForReconfiguration={viewSetupFlyoutForReconfiguration} + onRecreateMlJobForUpdate={viewSetupFlyoutForUpdate} /> @@ -227,7 +246,7 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { { +interface LogEntryRateSetupContentProps { + onOpenSetup: () => void; +} + +export const LogEntryRateSetupContent: React.FunctionComponent = ({ + onOpenSetup, +}) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup', delay: 15000 }); - const { - cleanUpAndSetUp, - endTime, - isValidating, - lastSetupErrorMessages, - setEndTime, - setStartTime, - setValidatedIndices, - setUp, - setupStatus, - startTime, - validatedIndices, - validationErrors, - viewResults, - } = useLogEntryRateSetup(); - - const steps = useMemo( - () => [ - createInitialConfigurationStep({ - setStartTime, - setEndTime, - startTime, - endTime, - isValidating, - validatedIndices, - setupStatus, - setValidatedIndices, - validationErrors, - }), - createProcessStep({ - cleanUpAndSetUp, - errorMessages: lastSetupErrorMessages, - isConfigurationValid: validationErrors.length <= 0 && !isValidating, - setUp, - setupStatus, - viewResults, - }), - ], - [ - cleanUpAndSetUp, - endTime, - isValidating, - lastSetupErrorMessages, - setEndTime, - setStartTime, - setUp, - setValidatedIndices, - setupStatus, - startTime, - validatedIndices, - validationErrors, - viewResults, - ] - ); - return ( {' '} - + id="xpack.infra.logs.logEntryRate.setupTitle" + defaultMessage="Set up log anomaly analysis" + /> - +

+ +

- + + +
); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/setup_flyout.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/setup_flyout.tsx new file mode 100644 index 0000000000000..0e9e34432f28b --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/setup_flyout.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useMemo, useCallback } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiTitle, + EuiText, + EuiSpacer, + EuiSteps, +} from '@elastic/eui'; + +import { + createInitialConfigurationStep, + createProcessStep, +} from '../../../components/logging/log_analysis_setup'; +import { useLogEntryRateSetup } from './use_log_entry_rate_setup'; + +interface LogEntryRateSetupFlyoutProps { + isOpen: boolean; + onClose: () => void; +} + +export const LogEntryRateSetupFlyout: React.FC = ({ + isOpen, + onClose, +}) => { + const { + cleanUpAndSetUp, + endTime, + isValidating, + lastSetupErrorMessages, + setEndTime, + setStartTime, + setValidatedIndices, + setUp, + setupStatus, + startTime, + validatedIndices, + validationErrors, + viewResults, + } = useLogEntryRateSetup(); + + const viewResultsAndClose = useCallback(() => { + viewResults(); + onClose(); + }, [viewResults, onClose]); + + const steps = useMemo( + () => [ + createInitialConfigurationStep({ + setStartTime, + setEndTime, + startTime, + endTime, + isValidating, + validatedIndices, + setupStatus, + setValidatedIndices, + validationErrors, + }), + createProcessStep({ + cleanUpAndSetUp, + errorMessages: lastSetupErrorMessages, + isConfigurationValid: validationErrors.length <= 0 && !isValidating, + setUp, + setupStatus, + viewResults: viewResultsAndClose, + }), + ], + [ + cleanUpAndSetUp, + endTime, + isValidating, + lastSetupErrorMessages, + setEndTime, + setStartTime, + setUp, + setValidatedIndices, + setupStatus, + startTime, + validatedIndices, + validationErrors, + viewResultsAndClose, + ] + ); + + if (!isOpen) { + return null; + } + return ( + + + +

+ +

+
+
+ + +

+ +

+
+ + + + + +
+
+ ); +}; diff --git a/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx b/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx index 83effaa3d51a5..b1dc55fe5c184 100644 --- a/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx +++ b/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx @@ -62,7 +62,7 @@ export const IndicesConfigurationPanel = ({ id="xpack.infra.sourceConfiguration.logIndicesRecommendedValue" defaultMessage="The recommended value is {defaultValue}" values={{ - defaultValue: filebeat-*, + defaultValue: logs-*,filebeat-*, }} /> } diff --git a/x-pack/plugins/infra/public/pages/metrics/settings.tsx b/x-pack/plugins/infra/public/pages/metrics/settings.tsx index 7d4f35b19da7d..b0aa67b5f0816 100644 --- a/x-pack/plugins/infra/public/pages/metrics/settings.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/settings.tsx @@ -15,7 +15,6 @@ export const MetricsSettingsPage = () => { ); diff --git a/x-pack/plugins/infra/server/lib/sources/defaults.ts b/x-pack/plugins/infra/server/lib/sources/defaults.ts index ba22b4db62d61..b096bed84fa9a 100644 --- a/x-pack/plugins/infra/server/lib/sources/defaults.ts +++ b/x-pack/plugins/infra/server/lib/sources/defaults.ts @@ -9,8 +9,8 @@ import { InfraSourceConfiguration } from '../../../common/http_api/source_api'; export const defaultSourceConfiguration: InfraSourceConfiguration = { name: 'Default', description: '', - metricAlias: 'metricbeat-*', - logAlias: 'filebeat-*,kibana_sample_data_logs*', + metricAlias: 'metrics-*,metricbeat-*', + logAlias: 'logs-*,filebeat-*,kibana_sample_data_logs*', fields: { container: 'container.id', host: 'host.name', diff --git a/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts new file mode 100644 index 0000000000000..59a22d33de858 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { migrationMocks } from 'src/core/server/mocks'; +import { addNewIndexingStrategyIndexNames } from './7_9_0_add_new_indexing_strategy_index_names'; +import { infraSourceConfigurationSavedObjectName } from '../saved_object_type'; + +describe('infra source configuration migration function for 7.9.0', () => { + test('adds "logs-*" when the logAlias contains "filebeat-*"', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'filebeat-*,custom-log-index-*', + 'custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual( + createTestSourceConfiguration('filebeat-*,custom-log-index-*,logs-*', 'custom-metric-index-*') + ); + }); + + test('doesn\'t add "logs-*" when the logAlias doesn\'t contain "filebeat-*"', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'custom-log-index-*', + 'custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration); + }); + + test('doesn\'t add "logs-*" when the logAlias already contains it', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'filebeat-*,logs-*,custom-log-index-*', + 'custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration); + }); + + test('adds "metrics-*" when the logAlias contains "metricbeat-*"', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'custom-log-index-*', + 'metricbeat-*,custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual( + createTestSourceConfiguration( + 'custom-log-index-*', + 'metricbeat-*,custom-metric-index-*,metrics-*' + ) + ); + }); + + test('doesn\'t add "metrics-*" when the logAlias doesn\'t contain "metricbeat-*"', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'custom-log-index-*', + 'custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration); + }); + + test('doesn\'t add "metrics-*" when the metricAlias already contains it', () => { + const unmigratedConfiguration = createTestSourceConfiguration( + 'custom-log-index-*', + 'metrics-*,metricbeat-*,custom-metric-index-*' + ); + + const migratedConfiguration = addNewIndexingStrategyIndexNames( + unmigratedConfiguration, + migrationMocks.createContext() + ); + + expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration); + }); +}); + +const createTestSourceConfiguration = (logAlias: string, metricAlias: string) => ({ + attributes: { + name: 'TEST CONFIGURATION', + description: '', + fields: { + pod: 'TEST POD FIELD', + host: 'TEST HOST FIELD', + message: ['TEST MESSAGE FIELD'], + container: 'TEST CONTAINER FIELD', + timestamp: 'TEST TIMESTAMP FIELD', + tiebreaker: 'TEST TIEBREAKER FIELD', + }, + inventoryDefaultView: '0', + metricsExplorerDefaultView: '0', + logColumns: [ + { + fieldColumn: { + id: 'TEST FIELD COLUMN ID', + field: 'TEST FIELD COLUMN FIELD', + }, + }, + ], + logAlias, + metricAlias, + }, + id: 'TEST_ID', + type: infraSourceConfigurationSavedObjectName, +}); diff --git a/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.ts b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.ts new file mode 100644 index 0000000000000..0d5563191d1b9 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectMigrationFn } from 'src/core/server'; +import { InfraSourceConfiguration } from '../../../../common/http_api/source_api'; + +export const addNewIndexingStrategyIndexNames: SavedObjectMigrationFn< + InfraSourceConfiguration, + InfraSourceConfiguration +> = (sourceConfigurationDocument) => { + const oldLogAliasSegments = sourceConfigurationDocument.attributes.logAlias.split(','); + const oldMetricAliasSegments = sourceConfigurationDocument.attributes.metricAlias.split(','); + + const newLogAliasSegment = 'logs-*'; + const newMetricAliasSegment = 'metrics-*'; + + return { + ...sourceConfigurationDocument, + attributes: { + ...sourceConfigurationDocument.attributes, + logAlias: + oldLogAliasSegments.includes('filebeat-*') && + !oldLogAliasSegments.includes(newLogAliasSegment) + ? [...oldLogAliasSegments, newLogAliasSegment].join(',') + : sourceConfigurationDocument.attributes.logAlias, + metricAlias: + oldMetricAliasSegments.includes('metricbeat-*') && + !oldMetricAliasSegments.includes(newMetricAliasSegment) + ? [...oldMetricAliasSegments, newMetricAliasSegment].join(',') + : sourceConfigurationDocument.attributes.metricAlias, + }, + }; +}; diff --git a/x-pack/plugins/infra/server/lib/sources/saved_object_type.ts b/x-pack/plugins/infra/server/lib/sources/saved_object_type.ts index a36ef8d1a8921..11db18d6bf799 100644 --- a/x-pack/plugins/infra/server/lib/sources/saved_object_type.ts +++ b/x-pack/plugins/infra/server/lib/sources/saved_object_type.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { SavedObjectsType } from 'src/core/server'; +import { addNewIndexingStrategyIndexNames } from './migrations/7_9_0_add_new_indexing_strategy_index_names'; export const infraSourceConfigurationSavedObjectName = 'infrastructure-ui-source'; @@ -86,4 +86,7 @@ export const infraSourceConfigurationSavedObjectType: SavedObjectsType = { }, }, }, + migrations: { + '7.9.0': addNewIndexingStrategyIndexNames, + }, }; diff --git a/x-pack/plugins/rollup/server/collectors/register.ts b/x-pack/plugins/rollup/server/collectors/register.ts index 35c40e42efc19..aa06d3f696d00 100644 --- a/x-pack/plugins/rollup/server/collectors/register.ts +++ b/x-pack/plugins/rollup/server/collectors/register.ts @@ -137,27 +137,30 @@ async function fetchRollupVisualizations( let rollupVisualizationsFromSavedSearches = 0; visualizations.forEach((visualization: any) => { - const { - _source: { - visualization: { - savedSearchRefName, - kibanaSavedObjectMeta: { searchSourceJSON }, - }, - references = [] as any[], - }, - } = visualization; - - const searchSource = JSON.parse(searchSourceJSON); - - if (savedSearchRefName) { + const references: Array<{ name: string; id: string }> | undefined = get( + visualization, + '_source.references' + ); + const savedSearchRefName: string | undefined = get( + visualization, + '_source.visualization.savedSearchRefName' + ); + const searchSourceJSON: string | undefined = get( + visualization, + '_source.visualization.kibanaSavedObjectMeta.searchSourceJSON' + ); + + if (savedSearchRefName && references?.length) { // This visualization depends upon a saved search. - const savedSearch = references.find((ref: any) => ref.name === savedSearchRefName); - if (rollupSavedSearchesToFlagMap[savedSearch.id]) { + const savedSearch = references.find(({ name }) => name === savedSearchRefName); + if (savedSearch && rollupSavedSearchesToFlagMap[savedSearch.id]) { rollupVisualizations++; rollupVisualizationsFromSavedSearches++; } - } else { + } else if (searchSourceJSON) { // This visualization depends upon an index pattern. + const searchSource = JSON.parse(searchSourceJSON); + if (rollupIndexPatternToFlagMap[searchSource.index]) { rollupVisualizations++; } diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index 6bc829f766e58..2a0922d614f1d 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -846,4 +846,43 @@ describe('FeatureTable', () => { }, }); }); + + it('does not render features which lack privileges', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: {}, + }, + ]); + + const featureWithoutPrivileges = createFeature({ + id: 'no_privs', + name: 'No Privileges Feature', + privileges: null, + }); + + const { displayedPrivileges } = setup({ + role, + features: [...kibanaFeatures, featureWithoutPrivileges], + privilegeIndex: 0, + calculateDisplayedPrivileges: true, + canCustomizeSubFeaturePrivileges: false, + }); + + expect(displayedPrivileges).toEqual({ + excluded_from_base: { + primaryFeaturePrivilege: 'none', + }, + no_sub_features: { + primaryFeaturePrivilege: 'none', + }, + with_excluded_sub_features: { + primaryFeaturePrivilege: 'none', + }, + with_sub_features: { + primaryFeaturePrivilege: 'none', + }, + }); + }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index a371a9ec9ba1e..57e24f2838226 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -63,7 +63,9 @@ export class FeatureTable extends Component { public render() { const { role, kibanaPrivileges } = this.props; - const featurePrivileges = kibanaPrivileges.getSecuredFeatures(); + const featurePrivileges = kibanaPrivileges + .getSecuredFeatures() + .filter((feature) => feature.privileges != null || feature.reserved != null); const items: TableRow[] = featurePrivileges .sort((feature1, feature2) => { diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts index a1bedea9f7deb..45f55b34baf96 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts @@ -50,7 +50,7 @@ describe('usingPrivileges', () => { new Feature({ id: 'fooFeature', name: 'Foo Feature', - app: [], + app: ['fooApp'], navLinkId: 'foo', privileges: null, }), @@ -63,6 +63,7 @@ describe('usingPrivileges', () => { Object.freeze({ navLinks: { foo: true, + fooApp: true, bar: true, }, management: { @@ -85,6 +86,7 @@ describe('usingPrivileges', () => { expect(result).toEqual({ navLinks: { foo: false, + fooApp: false, bar: true, }, management: { diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts index 183ad9169a123..a9b3fa54d3617 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts @@ -18,8 +18,12 @@ export function disableUICapabilitiesFactory( logger: Logger, authz: AuthorizationServiceSetup ) { + // nav links are sourced from two places: + // 1) The `navLinkId` property. This is deprecated and will be removed (https://github.com/elastic/kibana/issues/66217) + // 2) The apps property. The Kibana Platform associates nav links to the app which registers it, in a 1:1 relationship. + // This behavior is replacing the `navLinkId` property above. const featureNavLinkIds = features - .map((feature) => feature.navLinkId) + .flatMap((feature) => [feature.navLinkId, ...feature.app]) .filter((navLinkId) => navLinkId != null); const shouldDisableFeatureUICapability = ( diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts index c8c18696359f7..fd52fb6734ef2 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts @@ -30,7 +30,8 @@ import { loginAndWaitForPage } from '../tasks/login'; import { ALERTS_URL } from '../urls/navigation'; -describe('Alerts', () => { +// Flaky: https://github.com/elastic/kibana/issues/70727 +describe.skip('Alerts', () => { context('Closing alerts', () => { beforeEach(() => { esArchiverLoad('alerts'); 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/spaces/server/capabilities/capabilities_switcher.test.ts b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts index 1e01e04332f43..babd25dd3ec4b 100644 --- a/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts +++ b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts @@ -43,7 +43,7 @@ const features = ([ id: 'feature_3', name: 'Feature 3', navLinkId: 'feature3', - app: [], + app: ['feature3_app'], catalogue: ['feature3Entry'], management: { kibana: ['indices'], @@ -67,6 +67,7 @@ const buildCapabilities = () => feature1: true, feature2: true, feature3: true, + feature3_app: true, unknownFeature: true, }, catalogue: { @@ -241,6 +242,7 @@ describe('capabilitiesSwitcher', () => { expectedCapabilities.feature_2.foo = false; expectedCapabilities.navLinks.feature3 = false; + expectedCapabilities.navLinks.feature3_app = false; expectedCapabilities.catalogue.feature3Entry = false; expectedCapabilities.management.kibana.indices = false; expectedCapabilities.feature_3.bar = false; diff --git a/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.ts b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.ts index a0cdd5ad0e931..05d0429596489 100644 --- a/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.ts @@ -68,6 +68,12 @@ function toggleDisabledFeatures( navLinks[feature.navLinkId] = false; } + feature.app.forEach((app) => { + if (navLinks.hasOwnProperty(app)) { + navLinks[app] = false; + } + }); + // Disable associated catalogue entries const privilegeCatalogueEntries = feature.catalogue || []; privilegeCatalogueEntries.forEach((catalogueEntryId) => { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 683d83dde4e0f..51c6b33579f50 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7316,8 +7316,6 @@ "xpack.infra.alerting.logs.manageAlerts": "アラートを管理", "xpack.infra.alerting.manageAlerts": "アラートを管理", "xpack.infra.analysisSetup.actionStepTitle": "MLジョブを作成", - "xpack.infra.analysisSetup.analysisSetupDescription": "機械学習を使用して自動的に異常ログレートカウントを検出します。", - "xpack.infra.analysisSetup.analysisSetupTitle": "機械学習分析を有効にする", "xpack.infra.analysisSetup.configurationStepTitle": "構成", "xpack.infra.analysisSetup.createMlJobButton": "ML ジョブを作成", "xpack.infra.analysisSetup.deleteAnalysisResultsWarning": "これにより以前検出された異常が削除されます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ca065c9523637..8121df6d05090 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7320,8 +7320,6 @@ "xpack.infra.alerting.logs.manageAlerts": "管理告警", "xpack.infra.alerting.manageAlerts": "管理告警", "xpack.infra.analysisSetup.actionStepTitle": "创建 ML 作业", - "xpack.infra.analysisSetup.analysisSetupDescription": "使用 Machine Learning 自动检测异常日志速率计数。", - "xpack.infra.analysisSetup.analysisSetupTitle": "启用 Machine Learning 分析", "xpack.infra.analysisSetup.configurationStepTitle": "配置", "xpack.infra.analysisSetup.createMlJobButton": "创建 ML 作业", "xpack.infra.analysisSetup.deleteAnalysisResultsWarning": "这将移除以前检测到的异常。", diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap index 9496274a69171..823346db3518a 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap @@ -111,13 +111,13 @@ Array [ -

au-heartbeat

-
+
@@ -188,13 +188,13 @@ Array [ -

nyc-heartbeat

-
+
@@ -265,13 +265,13 @@ Array [ -

spa-heartbeat

-
+
@@ -356,18 +356,21 @@ exports[`AvailabilityReporting component shallow renders correctly against snaps "availability": 100, "color": "#d3dae6", "label": "au-heartbeat", + "status": "up", "timestamp": "36m ago", }, Object { "availability": 100, "color": "#d3dae6", "label": "nyc-heartbeat", + "status": "down", "timestamp": "36m ago", }, Object { "availability": 100, "color": "#d3dae6", "label": "spa-heartbeat", + "status": "down", "timestamp": "36m ago", }, ] diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap index 05e0b50a86f35..4d3e85ba18ebe 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap @@ -10,18 +10,21 @@ exports[`LocationStatusTags component renders properly against props 1`] = ` "availability": 100, "color": "#d3dae6", "label": "Berlin", + "status": "up", "timestamp": "1 Mon ago", }, Object { "availability": 100, "color": "#bd271e", "label": "Berlin", + "status": "down", "timestamp": "1 Mon ago", }, Object { "availability": 100, "color": "#d3dae6", "label": "Islamabad", + "status": "up", "timestamp": "1 Mon ago", }, ] @@ -145,13 +148,13 @@ exports[`LocationStatusTags component renders when all locations are down 1`] = -

Berlin

-
+
@@ -222,13 +225,13 @@ exports[`LocationStatusTags component renders when all locations are down 1`] = -

Islamabad

-
+
@@ -393,13 +396,13 @@ exports[`LocationStatusTags component renders when all locations are up 1`] = ` -

Berlin

-
+
@@ -470,13 +473,13 @@ exports[`LocationStatusTags component renders when all locations are up 1`] = ` -

Islamabad

-
+
@@ -641,13 +644,13 @@ exports[`LocationStatusTags component renders when there are many location 1`] = -

Berlin

-
+
@@ -718,13 +721,13 @@ exports[`LocationStatusTags component renders when there are many location 1`] = -

Islamabad

-
+
@@ -795,13 +798,13 @@ exports[`LocationStatusTags component renders when there are many location 1`] = -

New York

-
+
@@ -872,13 +875,13 @@ exports[`LocationStatusTags component renders when there are many location 1`] = -

Paris

-
+
@@ -949,13 +952,13 @@ exports[`LocationStatusTags component renders when there are many location 1`] = -

Sydney

-
+
diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap index 3381efa62286b..28f1f433648c8 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap @@ -26,13 +26,13 @@ exports[`TagLabel component renders correctly against snapshot 1`] = ` -

US-East

-
+
@@ -44,13 +44,13 @@ exports[`TagLabel component shallow render correctly against snapshot 1`] = ` -

US-East

-
+
`; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx index de9f6b0d3b30f..b5fe5d17312c6 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx @@ -19,14 +19,22 @@ describe('AvailabilityReporting component', () => { timestamp: '36m ago', color: '#d3dae6', availability: 100, + status: 'up', }, { label: 'nyc-heartbeat', timestamp: '36m ago', color: '#d3dae6', availability: 100, + status: 'down', + }, + { + label: 'spa-heartbeat', + timestamp: '36m ago', + color: '#d3dae6', + availability: 100, + status: 'down', }, - { label: 'spa-heartbeat', timestamp: '36m ago', color: '#d3dae6', availability: 100 }, ]; }); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx index 3560784122298..8e46196ec3ab7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx @@ -10,12 +10,12 @@ import { TagLabel } from '../tag_label'; describe('TagLabel component', () => { it('shallow render correctly against snapshot', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); }); it('renders correctly against snapshot', () => { - const component = renderWithIntl(); + const component = renderWithIntl(); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx index 8fed5db5e0271..ccf7d41642bfb 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx @@ -30,7 +30,7 @@ export const AvailabilityReporting: React.FC = ({ allLocations }) => { name: LocationLabel, truncateText: true, render: (val: string, item: StatusTag) => { - return ; + return ; }, }, { diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx index 6096499213a10..b48252d4208d2 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx @@ -24,9 +24,10 @@ interface Props { export interface StatusTag { label: string; - timestamp: string; + timestamp?: string; color: string; - availability: number; + availability?: number; + status: 'up' | 'down'; } export const LocationStatusTags = ({ locations }: Props) => { @@ -48,6 +49,7 @@ export const LocationStatusTags = ({ locations }: Props) => { timestamp: moment(new Date(item.timestamp).valueOf()).fromNow(), color: item.summary.down === 0 ? gray : danger, availability: (item.up_history / (item.up_history + item.down_history)) * 100, + status: item.summary.down === 0 ? 'up' : 'down', }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx index dbd73fc7d440b..ec5718415595d 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx @@ -6,7 +6,8 @@ import React from 'react'; import styled from 'styled-components'; -import { EuiBadge, EuiText } from '@elastic/eui'; +import { EuiBadge, EuiTextColor } from '@elastic/eui'; +import { StatusTag } from './location_status_tags'; const BadgeItem = styled.div` white-space: nowrap; @@ -17,18 +18,13 @@ const BadgeItem = styled.div` } `; -interface Props { - color: string; - label: string; -} - -export const TagLabel: React.FC = ({ color, label }) => { +export const TagLabel: React.FC = ({ color, label, status }) => { return ( - +

{label}

-
+
); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx index bf403846dcec4..8c66b57de58ac 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx @@ -64,9 +64,9 @@ export const MapToolTipComponent = ({ closeTooltip, features = [] }: MapToolTipP <> {layerId === 'up_points' ? ( - + ) : ( - + )} diff --git a/x-pack/test/api_integration/apis/metrics_ui/log_sources.ts b/x-pack/test/api_integration/apis/metrics_ui/log_sources.ts index d4cdd7316b3fd..00af3f8c25105 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/log_sources.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/log_sources.ts @@ -35,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) { expect(origin).to.be('fallback'); expect(configuration.name).to.be('Default'); - expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(configuration.fields.timestamp).to.be('@timestamp'); expect(configuration.fields.tiebreaker).to.be('_doc'); expect(configuration.logColumns[0]).to.have.key('timestampColumn'); @@ -97,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) { expect(configuration.name).to.be('Default'); expect(origin).to.be('stored'); - expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(configuration.fields.timestamp).to.be('@timestamp'); expect(configuration.fields.tiebreaker).to.be('_doc'); expect(configuration.logColumns).to.have.length(3); @@ -166,7 +166,7 @@ export default function ({ getService }: FtrProviderContext) { expect(configuration.name).to.be('NAME'); expect(origin).to.be('stored'); - expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(configuration.fields.timestamp).to.be('@timestamp'); expect(configuration.fields.tiebreaker).to.be('_doc'); expect(configuration.logColumns).to.have.length(3); diff --git a/x-pack/test/api_integration/apis/metrics_ui/sources.ts b/x-pack/test/api_integration/apis/metrics_ui/sources.ts index 5ed038776625c..5908523af2496 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/sources.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/sources.ts @@ -40,8 +40,8 @@ export default function ({ getService }: FtrProviderContext) { // shipped default values expect(sourceConfiguration.name).to.be('Default'); - expect(sourceConfiguration.metricAlias).to.be('metricbeat-*'); - expect(sourceConfiguration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(sourceConfiguration.metricAlias).to.be('metrics-*,metricbeat-*'); + expect(sourceConfiguration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(sourceConfiguration.fields.container).to.be('container.id'); expect(sourceConfiguration.fields.host).to.be('host.name'); expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid'); @@ -125,8 +125,8 @@ export default function ({ getService }: FtrProviderContext) { expect(updatedAt).to.be.greaterThan(0); expect(configuration.name).to.be('NAME'); expect(configuration.description).to.be(''); - expect(configuration.metricAlias).to.be('metricbeat-*'); - expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(configuration.metricAlias).to.be('metrics-*,metricbeat-*'); + expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(configuration.fields.container).to.be('container.id'); expect(configuration.fields.host).to.be('host.name'); expect(configuration.fields.pod).to.be('kubernetes.pod.uid'); @@ -283,7 +283,7 @@ export default function ({ getService }: FtrProviderContext) { expect(version).to.not.be(initialVersion); expect(updatedAt).to.be.greaterThan(createdAt); expect(configuration.metricAlias).to.be('metricbeat-**'); - expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*'); + expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); expect(status.logIndicesExist).to.be(true); expect(status.metricIndicesExist).to.be(true); }); diff --git a/x-pack/test/functional/apps/security/doc_level_security_roles.js b/x-pack/test/functional/apps/security/doc_level_security_roles.js index 72f463be48fd5..d8a3e40ccc010 100644 --- a/x-pack/test/functional/apps/security/doc_level_security_roles.js +++ b/x-pack/test/functional/apps/security/doc_level_security_roles.js @@ -15,7 +15,8 @@ export default function ({ getService, getPageObjects }) { const screenshot = getService('screenshots'); const PageObjects = getPageObjects(['security', 'common', 'header', 'discover', 'settings']); - describe('dls', function () { + // Skipped as failing on ES Promotion: https://github.com/elastic/kibana/issues/70818 + describe.skip('dls', function () { before('initialize tests', async () => { await esArchiver.load('empty_kibana'); await esArchiver.loadIfNeeded('security/dlstest'); diff --git a/x-pack/test/plugin_functional/es_archives/global_search/basic/data.json b/x-pack/test/plugin_functional/es_archives/global_search/basic/data.json new file mode 100644 index 0000000000000..f121f6859885b --- /dev/null +++ b/x-pack/test/plugin_functional/es_archives/global_search/basic/data.json @@ -0,0 +1,193 @@ +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "index-pattern:logstash-*", + "source": { + "index-pattern": { + "title": "logstash-*", + "timeFieldName": "@timestamp", + "fields": "[{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]" + }, + "type": "index-pattern", + "migrationVersion": { + "index-pattern": "6.5.0" + }, + "updated_at": "2018-12-21T00:43:07.096Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "visualization:75c3e060-1e7c-11e9-8488-65449e65d0ed", + "source": { + "visualization": { + "title": "A Pie", + "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "type": "visualization", + "updated_at": "2019-01-22T19:32:31.206Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "dashboard:i-exist", + "source": { + "dashboard": { + "title": "Amazing Dashboard", + "hits": 0, + "description": "", + "panelsJSON": "[{\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"1\"},\"version\":\"7.0.0\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"id\":\"75c3e060-1e7c-11e9-8488-65449e65d0ed\",\"embeddableConfig\":{}}]", + "optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}", + "version": 1, + "timeRestore": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "type": "dashboard", + "updated_at": "2019-01-22T19:32:47.232Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "config:6.0.0", + "source": { + "config": { + "buildNum": 9007199254740991, + "defaultIndex": "logstash-*" + }, + "type": "config", + "updated_at": "2019-01-22T19:32:02.235Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "map:0b849ed0-70f5-11e9-8625-9580c4904684", + "source": { + "map": { + "title" : "just a map", + "description" : "", + "mapStateJSON" : "{\"zoom\":0.8,\"center\":{\"lon\":0,\"lat\":0},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":false,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"}}", + "layerListJSON" : "[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"id\":\"c7bdee60-5267-459e-83d6-b53acf1b9e67\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"applyGlobalQuery\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\"}]", + "uiStateJSON" : "{\"isLayerTOCOpen\":true}", + "bounds" : { + "type" : "polygon", + "coordinates" : [ + [ + [ + -180, + 85.05113 + ], + [ + -180, + -85.05113 + ], + [ + 180, + -85.05113 + ], + [ + 180, + 85.05113 + ], + [ + -180, + 85.05113 + ] + ] + ] + } + }, + "type": "map", + "references" : [ ], + "migrationVersion" : { + "map" : "7.1.0" + }, + "updated_at" : "2019-05-07T18:22:17.405Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "dashboard:1c1a87f0-70f5-11e9-8625-9580c4904684", + "source": { + "dashboard": { + "title" : "dashboard with map", + "hits" : 0, + "description" : "", + "panelsJSON" : "[{\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1\"},\"version\":\"8.0.0\",\"panelIndex\":\"1\",\"embeddableConfig\":{\"mapCenter\":{\"lat\":0,\"lon\":0,\"zoom\":0.8},\"isLayerTOCOpen\":true},\"panelRefName\":\"panel_0\"}]", + "optionsJSON" : "{\"useMargins\":true,\"hidePanelTitles\":false}", + "version" : 1, + "timeRestore" : false, + "kibanaSavedObjectMeta" : { + "searchSourceJSON" : "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "type": "dashboard", + "references" : [ + { + "name" : "panel_0", + "type" : "map", + "id" : "0b849ed0-70f5-11e9-8625-9580c4904684" + } + ], + "migrationVersion" : { + "dashboard" : "7.0.0" + }, + "updated_at" : "2019-05-07T18:22:45.231Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "query:okjpgs", + "source": { + "query": { + "title": "OKJpgs", + "description": "Ok responses for jpg files", + "query": { + "query": "response:200", + "language": "kuery" + }, + "filters": [{"meta":{"index":"b15b1d40-a8bb-11e9-98cf-2bb06ef63e0b","alias":null,"negate":false,"type":"phrase","key":"extension.raw","value":"jpg","params":{"query":"jpg"},"disabled":false},"query":{"match":{"extension.raw":{"query":"jpg","type":"phrase"}}},"$state":{"store":"appState"}}] + }, + "type": "query", + "updated_at": "2019-07-17T17:54:26.378Z" + } + } +} diff --git a/x-pack/test/plugin_functional/es_archives/global_search/basic/mappings.json b/x-pack/test/plugin_functional/es_archives/global_search/basic/mappings.json new file mode 100644 index 0000000000000..ebb5b19387faf --- /dev/null +++ b/x-pack/test/plugin_functional/es_archives/global_search/basic/mappings.json @@ -0,0 +1,516 @@ +{ + "type": "index", + "value": { + "index": ".kibana", + "settings": { + "index": { + "number_of_shards": "1", + "auto_expand_replicas": "0-1", + "number_of_replicas": "0" + } + }, + "mappings": { + "dynamic": "strict", + "properties": { + "apm-telemetry": { + "properties": { + "has_any_services": { + "type": "boolean" + }, + "services_per_agent": { + "properties": { + "go": { + "type": "long", + "null_value": 0 + }, + "java": { + "type": "long", + "null_value": 0 + }, + "js-base": { + "type": "long", + "null_value": 0 + }, + "nodejs": { + "type": "long", + "null_value": 0 + }, + "python": { + "type": "long", + "null_value": 0 + }, + "ruby": { + "type": "long", + "null_value": 0 + } + } + } + } + }, + "canvas-workpad": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "id": { + "type": "text", + "index": false + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword" + } + } + } + } + }, + "config": { + "dynamic": "true", + "properties": { + "accessibility:disableAnimations": { + "type": "boolean" + }, + "buildNum": { + "type": "keyword" + }, + "dateFormat:tz": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "defaultIndex": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "telemetry:optIn": { + "type": "boolean" + } + } + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "optionsJSON": { + "type": "text" + }, + "panelsJSON": { + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "type": "keyword" + }, + "pause": { + "type": "boolean" + }, + "section": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "timeFrom": { + "type": "keyword" + }, + "timeRestore": { + "type": "boolean" + }, + "timeTo": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "map" : { + "properties" : { + "bounds" : { + "type" : "geo_shape", + "tree" : "quadtree" + }, + "description" : { + "type" : "text" + }, + "layerListJSON" : { + "type" : "text" + }, + "mapStateJSON" : { + "type" : "text" + }, + "title" : { + "type" : "text" + }, + "uiStateJSON" : { + "type" : "text" + }, + "version" : { + "type" : "integer" + } + } + }, + "graph-workspace": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "numLinks": { + "type": "integer" + }, + "numVertices": { + "type": "integer" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "wsState": { + "type": "text" + } + } + }, + "index-pattern": { + "properties": { + "fieldFormatMap": { + "type": "text" + }, + "fields": { + "type": "text" + }, + "intervalName": { + "type": "keyword" + }, + "notExpandable": { + "type": "boolean" + }, + "sourceFilters": { + "type": "text" + }, + "timeFieldName": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + }, + "typeMeta": { + "type": "keyword" + } + } + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "index-pattern": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "space": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "index-pattern": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "namespace": { + "type": "keyword" + }, + "references": { + "type": "nested", + "properties": { + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "id": { + "type": "keyword" + } + } + }, + "search": { + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "server": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "initials": { + "type": "keyword" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 2048 + } + } + } + } + }, + "spaceId": { + "type": "keyword" + }, + "telemetry": { + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "timelion-sheet": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 2048 + } + } + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "savedSearchId": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "type": "text" + } + } + }, + "query": { + "properties": { + "title": { + "type": "text" + }, + "description": { + "type": "text" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "type": "keyword", + "index": false + } + } + }, + "filters": { + "type": "object", + "enabled": false + }, + "timefilter": { + "type": "object", + "enabled": false + } + } + } + } + } + } +} diff --git a/x-pack/test/plugin_functional/plugins/global_search_test/public/plugin.ts b/x-pack/test/plugin_functional/plugins/global_search_test/public/plugin.ts index 27434202d77f1..aba3512788f9c 100644 --- a/x-pack/test/plugin_functional/plugins/global_search_test/public/plugin.ts +++ b/x-pack/test/plugin_functional/plugins/global_search_test/public/plugin.ts @@ -17,7 +17,8 @@ import { createResult } from '../common/utils'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface GlobalSearchTestPluginSetup {} export interface GlobalSearchTestPluginStart { - findAll: (term: string) => 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')); }); }