From 95e6d135906f52269cc5083affe3d9c904fd4624 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Tue, 16 Feb 2021 12:48:30 -0500 Subject: [PATCH 01/46] [CI] Use custom github action for backport (#91523) --- .github/workflows/backport.yml | 42 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 238a21161b1297..79571d51659d6c 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -18,34 +18,20 @@ jobs: ) runs-on: ubuntu-latest steps: - - name: 'Get backport config' - run: | - curl 'https://raw.githubusercontent.com/elastic/kibana/master/.backportrc.json' > .backportrc.json - - - name: Use Node.js 14.x - uses: actions/setup-node@v1 + - name: Checkout Actions + uses: actions/checkout@v2 with: - node-version: 14.x - - - name: Install backport CLI - run: npm install -g backport@5.6.4 + repository: 'elastic/kibana-github-actions' + ref: main + path: ./actions - - name: Backport PR - run: | - git config --global user.name "kibanamachine" - git config --global user.email "42973632+kibanamachine@users.noreply.github.com" - backport --fork true --username kibanamachine --accessToken "${{ secrets.KIBANAMACHINE_TOKEN }}" --ci --pr "$PR_NUMBER" --labels backport --assignee "$PR_OWNER" | tee 'output.log' - env: - PR_NUMBER: ${{ github.event.pull_request.number }} - PR_OWNER: ${{ github.event.pull_request.user.login }} + - name: Install Actions + run: npm install --production --prefix ./actions - - name: Report backport status - run: | - COMMENT="Backport result - \`\`\` - $(cat output.log) - \`\`\`" - - GITHUB_TOKEN="${{ secrets.KIBANAMACHINE_TOKEN }}" gh api -X POST repos/elastic/kibana/issues/$PR_NUMBER/comments -F body="$COMMENT" - env: - PR_NUMBER: ${{ github.event.pull_request.number }} + - name: Run Backport + uses: ./actions/backport + with: + branch: master + github_token: ${{secrets.KIBANAMACHINE_TOKEN}} + commit_user: kibanamachine + commit_email: 42973632+kibanamachine@users.noreply.github.com From a1a9769f83a1fde5b03d02ed99f68c2dbec8ef8e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 16 Feb 2021 18:53:33 +0100 Subject: [PATCH 02/46] [Uptime] increase flaky alert retry time (#91455) --- .github/CODEOWNERS | 9 +++++++-- .../functional_with_es_ssl/apps/uptime/alert_flyout.ts | 5 ++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4b0479eedea988..b45ff51b70da3c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -74,7 +74,13 @@ #CC# /src/plugins/apm_oss/ @elastic/apm-ui #CC# /x-pack/plugins/observability/ @elastic/apm-ui -# Client Side Monitoring (lives in APM directories but owned by Uptime) +# Uptime +/x-pack/plugins/uptime @elastic/uptime +/x-pack/test/functional_with_es_ssl/apps/uptime @elastic/uptime +/x-pack/test/functional/apps/uptime @elastic/uptime +/x-pack/test/api_integration/apis/uptime @elastic/uptime + +# Client Side Monitoring / Uptime (lives in APM directories but owned by Uptime) /x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm @elastic/uptime /x-pack/plugins/apm/e2e/cypress/integration/csm_dashboard.feature @elastic/uptime /x-pack/plugins/apm/public/application/csmApp.tsx @elastic/uptime @@ -106,7 +112,6 @@ /x-pack/plugins/fleet/ @elastic/fleet /x-pack/plugins/observability/ @elastic/observability-ui /x-pack/plugins/monitoring/ @elastic/stack-monitoring-ui -/x-pack/plugins/uptime @elastic/uptime # Machine Learning /x-pack/plugins/ml/ @elastic/ml-ui diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts index 057b43913b939f..7274105413145b 100644 --- a/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/uptime/alert_flyout.ts @@ -9,8 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { - // FLAKY: https://github.com/elastic/kibana/issues/88177 - describe.skip('uptime alerts', () => { + describe('uptime alerts', () => { const pageObjects = getPageObjects(['common', 'uptime']); const supertest = getService('supertest'); const retry = getService('retry'); @@ -90,7 +89,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // the previous line resolves, the API may not be done creating the alert yet, so we // put the fetch code in a retry block with a timeout. let alert: any; - await retry.tryForTime(15000, async () => { + await retry.tryForTime(60 * 1000, async () => { const apiResponse = await supertest.get('/api/alerts/_find?search=uptime-test'); const alertsFromThisTest = apiResponse.body.data.filter( ({ name }: { name: string }) => name === 'uptime-test' From f2e4cce0a2fb5413eccde1a5eaba0aaf56ae44fc Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 16 Feb 2021 10:00:29 -0800 Subject: [PATCH 03/46] [App Search] Set up Curations routes & complete 'Edit Query' action in Analytics tables (#91052) * Set up Curations routes * Update EngineRouter/Nav with Curations * Set up Curations find_or_create API * [bug] Fix view action not working correctly for "" query * Add Edit query action - to call find_or_create curation API & navigate to curation page + fix copy string, only just noticed this :doh: * Add/update unit tests for action column - Refactor out into a single shared test helper file that both AnalyticsTable and RecentQueriesTable simply calls & runs (instead of copying and pasting the same tests twice into 2 diff files) - note: test file can't be `.test.tsx` or Jest tries to automatically run it, which we don't want Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../analytics_tables/analytics_table.test.tsx | 19 ++--- .../recent_queries_table.test.tsx | 19 ++--- .../analytics_tables/shared_columns.tsx | 27 ++++-- .../analytics_tables/shared_columns_tests.tsx | 82 +++++++++++++++++++ .../curations/curations_router.test.tsx | 22 +++++ .../components/curations/curations_router.tsx | 55 +++++++++++++ .../app_search/components/curations/index.ts | 1 + .../components/engine/engine_nav.tsx | 4 +- .../components/engine/engine_router.test.tsx | 10 ++- .../components/engine/engine_router.tsx | 12 ++- .../public/applications/app_search/routes.ts | 7 +- .../routes/app_search/curations.test.ts | 47 +++++++++++ .../server/routes/app_search/curations.ts | 32 ++++++++ .../server/routes/app_search/index.ts | 2 + 14 files changed, 297 insertions(+), 42 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns_tests.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx create mode 100644 x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts create mode 100644 x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx index 2eac65fc210917..593f70cda404c1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx @@ -5,18 +5,18 @@ * 2.0. */ -import { mountWithIntl, mockKibanaValues } from '../../../../../__mocks__'; +import { mountWithIntl } from '../../../../../__mocks__'; import '../../../../__mocks__/engine_logic.mock'; import React from 'react'; import { EuiBasicTable, EuiBadge, EuiEmptyPrompt } from '@elastic/eui'; +import { runActionColumnTests } from './shared_columns_tests'; + import { AnalyticsTable } from './'; describe('AnalyticsTable', () => { - const { navigateToUrl } = mockKibanaValues; - const items = [ { key: 'some search', @@ -69,18 +69,9 @@ describe('AnalyticsTable', () => { expect(tableContent).toContain('0'); }); - it('renders an action column', () => { + describe('renders an action column', () => { const wrapper = mountWithIntl(); - const viewQuery = wrapper.find('[data-test-subj="AnalyticsTableViewQueryButton"]').first(); - const editQuery = wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first(); - - viewQuery.simulate('click'); - expect(navigateToUrl).toHaveBeenCalledWith( - '/engines/some-engine/analytics/query_detail/some%20search' - ); - - editQuery.simulate('click'); - // TODO + runActionColumnTests(wrapper); }); it('renders an empty prompt if no items are passed', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx index a5a582d3747bcc..f90d86908d470e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx @@ -5,18 +5,18 @@ * 2.0. */ -import { mountWithIntl, mockKibanaValues } from '../../../../../__mocks__'; +import { mountWithIntl } from '../../../../../__mocks__'; import '../../../../__mocks__/engine_logic.mock'; import React from 'react'; import { EuiBasicTable, EuiBadge, EuiEmptyPrompt } from '@elastic/eui'; +import { runActionColumnTests } from './shared_columns_tests'; + import { RecentQueriesTable } from './'; describe('RecentQueriesTable', () => { - const { navigateToUrl } = mockKibanaValues; - const items = [ { query_string: 'some search', @@ -63,18 +63,9 @@ describe('RecentQueriesTable', () => { expect(tableContent).toContain('3'); }); - it('renders an action column', () => { + describe('renders an action column', () => { const wrapper = mountWithIntl(); - const viewQuery = wrapper.find('[data-test-subj="AnalyticsTableViewQueryButton"]').first(); - const editQuery = wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first(); - - viewQuery.simulate('click'); - expect(navigateToUrl).toHaveBeenCalledWith( - '/engines/some-engine/analytics/query_detail/some%20search' - ); - - editQuery.simulate('click'); - // TODO + runActionColumnTests(wrapper); }); it('renders an empty prompt if no items are passed', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx index 9d8365a2f7af10..6c3d2539035aee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx @@ -9,10 +9,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; +import { flashAPIErrors } from '../../../../../shared/flash_messages'; +import { HttpLogic } from '../../../../../shared/http'; import { KibanaLogic } from '../../../../../shared/kibana'; import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; -import { ENGINE_ANALYTICS_QUERY_DETAIL_PATH } from '../../../../routes'; -import { generateEnginePath } from '../../../engine'; +import { ENGINE_ANALYTICS_QUERY_DETAIL_PATH, ENGINE_CURATION_PATH } from '../../../../routes'; +import { generateEnginePath, EngineLogic } from '../../../engine'; import { Query, RecentQuery } from '../../types'; import { InlineTagsList } from './inline_tags_list'; @@ -63,7 +65,7 @@ export const ACTIONS_COLUMN = { onClick: (item: Query | RecentQuery) => { const { navigateToUrl } = KibanaLogic.values; - const query = (item as Query).key || (item as RecentQuery).query_string; + const query = (item as Query).key || (item as RecentQuery).query_string || '""'; navigateToUrl(generateEnginePath(ENGINE_ANALYTICS_QUERY_DETAIL_PATH, { query })); }, 'data-test-subj': 'AnalyticsTableViewQueryButton', @@ -74,12 +76,25 @@ export const ACTIONS_COLUMN = { }), description: i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.analytics.table.editTooltip', - { defaultMessage: 'Edit query analytics' } + { defaultMessage: 'Edit query' } ), type: 'icon', icon: 'pencil', - onClick: () => { - // TODO: CurationsLogic + onClick: async (item: Query | RecentQuery) => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const { engineName } = EngineLogic.values; + + try { + const query = (item as Query).key || (item as RecentQuery).query_string || '""'; + const response = await http.get( + `/api/app_search/engines/${engineName}/curations/find_or_create`, + { query: { query } } + ); + navigateToUrl(generateEnginePath(ENGINE_CURATION_PATH, { curationId: response.id })); + } catch (e) { + flashAPIErrors(e); + } }, 'data-test-subj': 'AnalyticsTableEditQueryButton', }, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns_tests.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns_tests.tsx new file mode 100644 index 00000000000000..cb78a6585e43c8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns_tests.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + mockHttpValues, + mockKibanaValues, + mockFlashMessageHelpers, +} from '../../../../../__mocks__'; +import '../../../../__mocks__/engine_logic.mock'; + +import { ReactWrapper } from 'enzyme'; + +import { nextTick } from '@kbn/test/jest'; + +export const runActionColumnTests = (wrapper: ReactWrapper) => { + const { http } = mockHttpValues; + const { navigateToUrl } = mockKibanaValues; + const { flashAPIErrors } = mockFlashMessageHelpers; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('view action', () => { + it('navigates to the query detail view', () => { + wrapper.find('[data-test-subj="AnalyticsTableViewQueryButton"]').first().simulate('click'); + + expect(navigateToUrl).toHaveBeenCalledWith( + '/engines/some-engine/analytics/query_detail/some%20search' + ); + }); + + it('falls back to "" for the empty query', () => { + wrapper.find('[data-test-subj="AnalyticsTableViewQueryButton"]').last().simulate('click'); + expect(navigateToUrl).toHaveBeenCalledWith( + '/engines/some-engine/analytics/query_detail/%22%22' + ); + }); + }); + + describe('edit action', () => { + it('calls the find_or_create curation API, then navigates the user to the curation', async () => { + http.get.mockReturnValue(Promise.resolve({ id: 'cur-123456789' })); + wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first().simulate('click'); + await nextTick(); + + expect(http.get).toHaveBeenCalledWith( + '/api/app_search/engines/some-engine/curations/find_or_create', + { + query: { query: 'some search' }, + } + ); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-123456789'); + }); + + it('falls back to "" for the empty query', async () => { + http.get.mockReturnValue(Promise.resolve({ id: 'cur-987654321' })); + wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').last().simulate('click'); + await nextTick(); + + expect(http.get).toHaveBeenCalledWith( + '/api/app_search/engines/some-engine/curations/find_or_create', + { + query: { query: '""' }, + } + ); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-987654321'); + }); + + it('handles API errors', async () => { + http.get.mockReturnValue(Promise.reject()); + wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first().simulate('click'); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalled(); + }); + }); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx new file mode 100644 index 00000000000000..047d00ad98a0d5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { shallow } from 'enzyme'; + +import { CurationsRouter } from './'; + +describe('CurationsRouter', () => { + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(Switch)).toHaveLength(1); + expect(wrapper.find(Route)).toHaveLength(5); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx new file mode 100644 index 00000000000000..a7f99044cc1c37 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { APP_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { BreadcrumbTrail } from '../../../shared/kibana_chrome/generate_breadcrumbs'; +import { NotFound } from '../../../shared/not_found'; +import { + ENGINE_CURATIONS_PATH, + ENGINE_CURATIONS_NEW_PATH, + ENGINE_CURATION_PATH, + ENGINE_CURATION_ADD_RESULT_PATH, +} from '../../routes'; + +import { CURATIONS_TITLE } from './constants'; + +interface Props { + engineBreadcrumb: BreadcrumbTrail; +} +export const CurationsRouter: React.FC = ({ engineBreadcrumb }) => { + const CURATIONS_BREADCRUMB = [...engineBreadcrumb, CURATIONS_TITLE]; + + return ( + + + + TODO: Curations overview + + + + TODO: Curation creation view + + + + TODO: Curation view (+ show a NotFound view if ID is invalid) + + + + TODO: Curation Add Result view + + + + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/index.ts index f1eb95a0c878cb..075bc1368b3003 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/index.ts @@ -6,3 +6,4 @@ */ export { CURATIONS_TITLE } from './constants'; +export { CurationsRouter } from './curations_router'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx index 447e4d678bcdb6..a4ce724fdb0974 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx @@ -220,8 +220,8 @@ export const EngineNav: React.FC = () => { )} {canManageEngineCurations && ( {CURATIONS_TITLE} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx index 3740882dee3db2..e6b829a43dcc1c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx @@ -17,6 +17,7 @@ import { shallow } from 'enzyme'; import { Loading } from '../../../shared/loading'; import { AnalyticsRouter } from '../analytics'; +import { CurationsRouter } from '../curations'; import { EngineOverview } from '../engine_overview'; import { RelevanceTuning } from '../relevance_tuning'; @@ -97,7 +98,14 @@ describe('EngineRouter', () => { expect(wrapper.find(AnalyticsRouter)).toHaveLength(1); }); - it('renders an relevance tuning view', () => { + it('renders a curations view', () => { + setMockValues({ ...values, myRole: { canManageEngineCurations: true } }); + const wrapper = shallow(); + + expect(wrapper.find(CurationsRouter)).toHaveLength(1); + }); + + it('renders a relevance tuning view', () => { setMockValues({ ...values, myRole: { canManageEngineRelevanceTuning: true } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx index 2f1c3bc57d331e..305bdf74ae501b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx @@ -28,12 +28,13 @@ import { // META_ENGINE_SOURCE_ENGINES_PATH, ENGINE_RELEVANCE_TUNING_PATH, // ENGINE_SYNONYMS_PATH, - // ENGINE_CURATIONS_PATH, + ENGINE_CURATIONS_PATH, // ENGINE_RESULT_SETTINGS_PATH, // ENGINE_SEARCH_UI_PATH, // ENGINE_API_LOGS_PATH, } from '../../routes'; import { AnalyticsRouter } from '../analytics'; +import { CurationsRouter } from '../curations'; import { DocumentDetail, Documents } from '../documents'; import { OVERVIEW_TITLE } from '../engine_overview'; import { EngineOverview } from '../engine_overview'; @@ -46,13 +47,13 @@ export const EngineRouter: React.FC = () => { const { myRole: { canViewEngineAnalytics, - canManageEngineRelevanceTuning, // canViewEngineDocuments, // canViewEngineSchema, // canViewEngineCrawler, // canViewMetaEngineSourceEngines, + canManageEngineRelevanceTuning, // canManageEngineSynonyms, - // canManageEngineCurations, + canManageEngineCurations, // canManageEngineResultSettings, // canManageEngineSearchUi, // canViewEngineApiLogs, @@ -97,6 +98,11 @@ export const EngineRouter: React.FC = () => { + {canManageEngineCurations && ( + + + + )} {canManageEngineRelevanceTuning && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts index dee8858fada8b4..6fe9be083405e0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts @@ -44,9 +44,12 @@ export const META_ENGINE_SOURCE_ENGINES_PATH = `${ENGINE_PATH}/engines`; export const ENGINE_RELEVANCE_TUNING_PATH = `${ENGINE_PATH}/relevance_tuning`; export const ENGINE_SYNONYMS_PATH = `${ENGINE_PATH}/synonyms`; -export const ENGINE_CURATIONS_PATH = `${ENGINE_PATH}/curations`; -// TODO: Curations sub-pages export const ENGINE_RESULT_SETTINGS_PATH = `${ENGINE_PATH}/result-settings`; +export const ENGINE_CURATIONS_PATH = `${ENGINE_PATH}/curations`; +export const ENGINE_CURATIONS_NEW_PATH = `${ENGINE_CURATIONS_PATH}/new`; +export const ENGINE_CURATION_PATH = `${ENGINE_CURATIONS_PATH}/:curationId`; +export const ENGINE_CURATION_ADD_RESULT_PATH = `${ENGINE_CURATIONS_PATH}/:curationId/add_result`; + export const ENGINE_SEARCH_UI_PATH = `${ENGINE_PATH}/reference_application/new`; export const ENGINE_API_LOGS_PATH = `${ENGINE_PATH}/api-logs`; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts new file mode 100644 index 00000000000000..5b5d132591f4ef --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__'; + +import { registerCurationsRoutes } from './curations'; + +describe('curations routes', () => { + describe('GET /api/app_search/engines/{engineName}/curations/find_or_create', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/app_search/engines/{engineName}/curations/find_or_create', + }); + + registerCurationsRoutes({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/as/engines/:engineName/curations/find_or_create', + }); + }); + + describe('validates', () => { + it('required query param', () => { + const request = { query: { query: 'some query' } }; + mockRouter.shouldValidate(request); + }); + + it('missing query', () => { + const request = { query: {} }; + mockRouter.shouldThrow(request); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts new file mode 100644 index 00000000000000..a4addb3ad0d3ab --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../plugin'; + +export function registerCurationsRoutes({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/app_search/engines/{engineName}/curations/find_or_create', + validate: { + params: schema.object({ + engineName: schema.string(), + }), + query: schema.object({ + query: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/as/engines/:engineName/curations/find_or_create', + }) + ); +} diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts index 92fdcb689db1d2..90b86138a4a6d3 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts @@ -9,6 +9,7 @@ import { RouteDependencies } from '../../plugin'; import { registerAnalyticsRoutes } from './analytics'; import { registerCredentialsRoutes } from './credentials'; +import { registerCurationsRoutes } from './curations'; import { registerDocumentsRoutes, registerDocumentRoutes } from './documents'; import { registerEnginesRoutes } from './engines'; import { registerSearchSettingsRoutes } from './search_settings'; @@ -21,5 +22,6 @@ export const registerAppSearchRoutes = (dependencies: RouteDependencies) => { registerAnalyticsRoutes(dependencies); registerDocumentsRoutes(dependencies); registerDocumentRoutes(dependencies); + registerCurationsRoutes(dependencies); registerSearchSettingsRoutes(dependencies); }; From d5aea9378a4dc54347022fea107f60f52263d2ba Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 16 Feb 2021 13:02:15 -0500 Subject: [PATCH 04/46] Further optimize check privileges response validation (#90631) --- .../validate_es_response.test.ts.snap | 6 +-- .../authorization/check_privileges.test.ts | 12 ++--- .../authorization/validate_es_response.ts | 45 ++++++++++++------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/security/server/authorization/__snapshots__/validate_es_response.test.ts.snap b/x-pack/plugins/security/server/authorization/__snapshots__/validate_es_response.test.ts.snap index 76d284a21984e9..04190fbf5eacdd 100644 --- a/x-pack/plugins/security/server/authorization/__snapshots__/validate_es_response.test.ts.snap +++ b/x-pack/plugins/security/server/authorization/__snapshots__/validate_es_response.test.ts.snap @@ -1,12 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validateEsPrivilegeResponse fails validation when an action is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action3]: expected value of type [boolean] but got [string]"`; +exports[`validateEsPrivilegeResponse fails validation when an action is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: expected value of type [boolean] but got [string]"`; -exports[`validateEsPrivilegeResponse fails validation when an action is missing in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action2]: expected value of type [boolean] but got [undefined]"`; +exports[`validateEsPrivilegeResponse fails validation when an action is missing in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected actions"`; exports[`validateEsPrivilegeResponse fails validation when an expected resource property is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`; -exports[`validateEsPrivilegeResponse fails validation when an extra action is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action4]: definition for this key is missing"`; +exports[`validateEsPrivilegeResponse fails validation when an extra action is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected actions"`; exports[`validateEsPrivilegeResponse fails validation when an extra application is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.otherApplication]: definition for this key is missing"`; diff --git a/x-pack/plugins/security/server/authorization/check_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_privileges.test.ts index 93f5efed58fb8d..5bca46f22a5123 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges.test.ts @@ -316,7 +316,7 @@ describe('#atSpace', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:bar-type/get]: definition for this key is missing]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); @@ -338,7 +338,7 @@ describe('#atSpace', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:foo-type/get]: expected value of type [boolean] but got [undefined]]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); }); @@ -1092,7 +1092,7 @@ describe('#atSpaces', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [mock-action:version]: expected value of type [boolean] but got [undefined]]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); @@ -2266,7 +2266,7 @@ describe('#globally', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [mock-action:version]: expected value of type [boolean] but got [undefined]]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); @@ -2384,7 +2384,7 @@ describe('#globally', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:bar-type/get]: definition for this key is missing]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); @@ -2405,7 +2405,7 @@ describe('#globally', () => { }, }); expect(result).toMatchInlineSnapshot( - `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:foo-type/get]: expected value of type [boolean] but got [undefined]]` + `[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]` ); }); }); diff --git a/x-pack/plugins/security/server/authorization/validate_es_response.ts b/x-pack/plugins/security/server/authorization/validate_es_response.ts index 19afaaf035c15e..270ff26716e3f2 100644 --- a/x-pack/plugins/security/server/authorization/validate_es_response.ts +++ b/x-pack/plugins/security/server/authorization/validate_es_response.ts @@ -8,6 +8,11 @@ import { schema } from '@kbn/config-schema'; import { HasPrivilegesResponse } from './types'; +/** + * Validates an Elasticsearch "Has privileges" response against the expected application, actions, and resources. + * + * Note: the `actions` and `resources` parameters must be unique string arrays; any duplicates will cause validation to fail. + */ export function validateEsPrivilegeResponse( response: HasPrivilegesResponse, application: string, @@ -24,21 +29,29 @@ export function validateEsPrivilegeResponse( return response; } -function buildActionsValidationSchema(actions: string[]) { - return schema.object({ - ...actions.reduce>((acc, action) => { - return { - ...acc, - [action]: schema.boolean(), - }; - }, {}), - }); -} - function buildValidationSchema(application: string, actions: string[], resources: string[]) { - const actionValidationSchema = buildActionsValidationSchema(actions); + const actionValidationSchema = schema.boolean(); + const actionsValidationSchema = schema.object( + {}, + { + unknowns: 'allow', + validate: (value) => { + const actualActions = Object.keys(value).sort(); + if ( + actions.length !== actualActions.length || + ![...actions].sort().every((x, i) => x === actualActions[i]) + ) { + throw new Error('Payload did not match expected actions'); + } + + Object.values(value).forEach((actionResult) => { + actionValidationSchema.validate(actionResult); + }); + }, + } + ); - const resourceValidationSchema = schema.object( + const resourcesValidationSchema = schema.object( {}, { unknowns: 'allow', @@ -46,13 +59,13 @@ function buildValidationSchema(application: string, actions: string[], resources const actualResources = Object.keys(value).sort(); if ( resources.length !== actualResources.length || - !resources.sort().every((x, i) => x === actualResources[i]) + ![...resources].sort().every((x, i) => x === actualResources[i]) ) { throw new Error('Payload did not match expected resources'); } Object.values(value).forEach((actionResult) => { - actionValidationSchema.validate(actionResult); + actionsValidationSchema.validate(actionResult); }); }, } @@ -63,7 +76,7 @@ function buildValidationSchema(application: string, actions: string[], resources has_all_requested: schema.boolean(), cluster: schema.object({}, { unknowns: 'allow' }), application: schema.object({ - [application]: resourceValidationSchema, + [application]: resourcesValidationSchema, }), index: schema.object({}, { unknowns: 'allow' }), }); From 6f857dd7f3bc8c4ee5322b85cb558c639aa14b9b Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Tue, 16 Feb 2021 13:03:56 -0500 Subject: [PATCH 05/46] [Time to Visualize] Combine Discard & Cancel (#91267) * recombined discard and cancel button functionality --- .../application/listing/confirm_overlays.tsx | 54 +++++++++++++++ .../application/top_nav/dashboard_top_nav.tsx | 67 ++++++++++++------- .../application/top_nav/get_top_nav_config.ts | 19 ------ .../public/application/top_nav/top_nav_ids.ts | 1 - .../dashboard/public/dashboard_strings.ts | 12 ++++ test/accessibility/apps/dashboard.ts | 5 +- .../apps/dashboard/dashboard_unsaved_state.ts | 1 + test/functional/apps/dashboard/view_edit.ts | 32 ++++----- .../functional/page_objects/dashboard_page.ts | 18 ++++- 9 files changed, 139 insertions(+), 70 deletions(-) diff --git a/src/plugins/dashboard/public/application/listing/confirm_overlays.tsx b/src/plugins/dashboard/public/application/listing/confirm_overlays.tsx index 41b27b4fd69260..d302bb4216bc49 100644 --- a/src/plugins/dashboard/public/application/listing/confirm_overlays.tsx +++ b/src/plugins/dashboard/public/application/listing/confirm_overlays.tsx @@ -40,6 +40,60 @@ export const confirmDiscardUnsavedChanges = ( } }); +export type DiscardOrKeepSelection = 'cancel' | 'discard' | 'keep'; + +export const confirmDiscardOrKeepUnsavedChanges = ( + overlays: OverlayStart +): Promise => { + return new Promise((resolve) => { + const session = overlays.openModal( + toMountPoint( + <> + + {leaveConfirmStrings.getLeaveEditModeTitle()} + + + + {leaveConfirmStrings.getLeaveEditModeSubtitle()} + + + + session.close()} + > + {leaveConfirmStrings.getCancelButtonText()} + + { + session.close(); + resolve('keep'); + }} + > + {leaveConfirmStrings.getKeepChangesText()} + + { + session.close(); + resolve('discard'); + }} + > + {leaveConfirmStrings.getConfirmButtonText()} + + + + ), + { + 'data-test-subj': 'dashboardDiscardConfirmModal', + } + ); + }); +}; + export const confirmCreateWithUnsaved = ( overlays: OverlayStart, startBlankCallback: () => void, diff --git a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx index 786afc81c400cd..e68d371ebb2703 100644 --- a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx @@ -43,7 +43,7 @@ import { showOptionsPopover } from './show_options_popover'; import { TopNavIds } from './top_nav_ids'; import { ShowShareModal } from './show_share_modal'; import { PanelToolbar } from './panel_toolbar'; -import { confirmDiscardUnsavedChanges } from '../listing/confirm_overlays'; +import { confirmDiscardOrKeepUnsavedChanges } from '../listing/confirm_overlays'; import { OverlayRef } from '../../../../../core/public'; import { getNewDashboardTitle } from '../../dashboard_strings'; import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage'; @@ -152,34 +152,53 @@ export function DashboardTopNav({ } }, [state.addPanelOverlay]); - const onDiscardChanges = useCallback(() => { - function revertChangesAndExitEditMode() { - dashboardStateManager.resetState(); - dashboardStateManager.clearUnsavedPanels(); - - // We need to do a hard reset of the timepicker. appState will not reload like - // it does on 'open' because it's been saved to the url and the getAppState.previouslyStored() check on - // reload will cause it not to sync. - if (dashboardStateManager.getIsTimeSavedWithDashboard()) { - dashboardStateManager.syncTimefilterWithDashboardTime(timefilter); - dashboardStateManager.syncTimefilterWithDashboardRefreshInterval(timefilter); - } - dashboardStateManager.switchViewMode(ViewMode.VIEW); - } - confirmDiscardUnsavedChanges(core.overlays, revertChangesAndExitEditMode); - }, [core.overlays, dashboardStateManager, timefilter]); - const onChangeViewMode = useCallback( (newMode: ViewMode) => { clearAddPanel(); - if (savedDashboard?.id && allowByValueEmbeddables) { - const { getFullEditPath, title, id } = savedDashboard; - chrome.recentlyAccessed.add(getFullEditPath(newMode === ViewMode.EDIT), title, id); + const isPageRefresh = newMode === dashboardStateManager.getViewMode(); + const isLeavingEditMode = !isPageRefresh && newMode === ViewMode.VIEW; + const willLoseChanges = isLeavingEditMode && dashboardStateManager.getIsDirty(timefilter); + + function switchViewMode() { + dashboardStateManager.switchViewMode(newMode); + dashboardStateManager.restorePanels(); + + if (savedDashboard?.id && allowByValueEmbeddables) { + const { getFullEditPath, title, id } = savedDashboard; + chrome.recentlyAccessed.add(getFullEditPath(newMode === ViewMode.EDIT), title, id); + } + } + + if (!willLoseChanges) { + switchViewMode(); + return; } - dashboardStateManager.switchViewMode(newMode); - dashboardStateManager.restorePanels(); + + function discardChanges() { + dashboardStateManager.resetState(); + dashboardStateManager.clearUnsavedPanels(); + + // We need to do a hard reset of the timepicker. appState will not reload like + // it does on 'open' because it's been saved to the url and the getAppState.previouslyStored() check on + // reload will cause it not to sync. + if (dashboardStateManager.getIsTimeSavedWithDashboard()) { + dashboardStateManager.syncTimefilterWithDashboardTime(timefilter); + dashboardStateManager.syncTimefilterWithDashboardRefreshInterval(timefilter); + } + dashboardStateManager.switchViewMode(ViewMode.VIEW); + } + confirmDiscardOrKeepUnsavedChanges(core.overlays).then((selection) => { + if (selection === 'discard') { + discardChanges(); + } + if (selection !== 'cancel') { + switchViewMode(); + } + }); }, [ + timefilter, + core.overlays, clearAddPanel, savedDashboard, dashboardStateManager, @@ -381,7 +400,6 @@ export function DashboardTopNav({ }, [TopNavIds.EXIT_EDIT_MODE]: () => onChangeViewMode(ViewMode.VIEW), [TopNavIds.ENTER_EDIT_MODE]: () => onChangeViewMode(ViewMode.EDIT), - [TopNavIds.DISCARD_CHANGES]: onDiscardChanges, [TopNavIds.SAVE]: runSave, [TopNavIds.QUICK_SAVE]: runQuickSave, [TopNavIds.CLONE]: runClone, @@ -417,7 +435,6 @@ export function DashboardTopNav({ }, [ dashboardCapabilities, dashboardStateManager, - onDiscardChanges, onChangeViewMode, savedDashboard, runClone, diff --git a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts index abc128369017c5..26eea1b5f718de 100644 --- a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts +++ b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts @@ -41,14 +41,12 @@ export function getTopNavConfig( getOptionsConfig(actions[TopNavIds.OPTIONS]), getShareConfig(actions[TopNavIds.SHARE]), getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]), - getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]), getSaveConfig(actions[TopNavIds.SAVE], options.isNewDashboard), ] : [ getOptionsConfig(actions[TopNavIds.OPTIONS]), getShareConfig(actions[TopNavIds.SHARE]), getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]), - getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]), getSaveConfig(actions[TopNavIds.SAVE]), getQuickSave(actions[TopNavIds.QUICK_SAVE]), ]; @@ -154,23 +152,6 @@ function getViewConfig(action: NavAction) { }; } -/** - * @returns {kbnTopNavConfig} - */ -function getDiscardConfig(action: NavAction) { - return { - id: 'discard', - label: i18n.translate('dashboard.topNave.discardlButtonAriaLabel', { - defaultMessage: 'discard', - }), - description: i18n.translate('dashboard.topNave.discardConfigDescription', { - defaultMessage: 'Discard unsaved changes', - }), - testId: 'dashboardDiscardChanges', - run: action, - }; -} - /** * @returns {kbnTopNavConfig} */ diff --git a/src/plugins/dashboard/public/application/top_nav/top_nav_ids.ts b/src/plugins/dashboard/public/application/top_nav/top_nav_ids.ts index 92a0db6bd0ba2e..ee3d08e2330ae9 100644 --- a/src/plugins/dashboard/public/application/top_nav/top_nav_ids.ts +++ b/src/plugins/dashboard/public/application/top_nav/top_nav_ids.ts @@ -13,7 +13,6 @@ export const TopNavIds = { SAVE: 'save', EXIT_EDIT_MODE: 'exitEditMode', ENTER_EDIT_MODE: 'enterEditMode', - DISCARD_CHANGES: 'discard', CLONE: 'clone', FULL_SCREEN: 'fullScreenMode', }; diff --git a/src/plugins/dashboard/public/dashboard_strings.ts b/src/plugins/dashboard/public/dashboard_strings.ts index 96bd32088ec38b..8588fbc1bbdc7f 100644 --- a/src/plugins/dashboard/public/dashboard_strings.ts +++ b/src/plugins/dashboard/public/dashboard_strings.ts @@ -253,6 +253,18 @@ export const leaveConfirmStrings = { i18n.translate('dashboard.appLeaveConfirmModal.unsavedChangesSubtitle', { defaultMessage: 'Leave Dashboard with unsaved work?', }), + getKeepChangesText: () => + i18n.translate('dashboard.appLeaveConfirmModal.keepUnsavedChangesButtonLabel', { + defaultMessage: 'Keep unsaved changes', + }), + getLeaveEditModeTitle: () => + i18n.translate('dashboard.changeViewModeConfirmModal.leaveEditMode', { + defaultMessage: 'Leave edit mode with unsaved work?', + }), + getLeaveEditModeSubtitle: () => + i18n.translate('dashboard.changeViewModeConfirmModal.discardChangesOptionalDescription', { + defaultMessage: `If you discard your changes, there's no getting them back.`, + }), getDiscardTitle: () => i18n.translate('dashboard.changeViewModeConfirmModal.discardChangesTitle', { defaultMessage: 'Discard changes to dashboard?', diff --git a/test/accessibility/apps/dashboard.ts b/test/accessibility/apps/dashboard.ts index 0171a462b13680..08d577b3df08cd 100644 --- a/test/accessibility/apps/dashboard.ts +++ b/test/accessibility/apps/dashboard.ts @@ -110,12 +110,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('Exit out of edit mode', async () => { - await PageObjects.dashboard.clickDiscardChanges(); + await PageObjects.dashboard.clickDiscardChanges(false); await a11y.testAppSnapshot(); }); it('Discard changes', async () => { - await PageObjects.common.clickConfirmOnModal(); + await testSubjects.exists('dashboardDiscardConfirmDiscard'); + await testSubjects.click('dashboardDiscardConfirmDiscard'); await PageObjects.dashboard.getIsInViewMode(); await a11y.testAppSnapshot(); }); diff --git a/test/functional/apps/dashboard/dashboard_unsaved_state.ts b/test/functional/apps/dashboard/dashboard_unsaved_state.ts index 851d7ab7461ed0..eaf0d2f2a97df2 100644 --- a/test/functional/apps/dashboard/dashboard_unsaved_state.ts +++ b/test/functional/apps/dashboard/dashboard_unsaved_state.ts @@ -80,6 +80,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('retains unsaved panel count after returning to edit mode', async () => { await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.dashboard.switchToEditMode(); + await PageObjects.header.waitUntilLoadingHasFinished(); const currentPanelCount = await PageObjects.dashboard.getPanelCount(); expect(currentPanelCount).to.eql(unsavedPanelCount); }); diff --git a/test/functional/apps/dashboard/view_edit.ts b/test/functional/apps/dashboard/view_edit.ts index 5242e59efa0e99..6c7d60c9a15aa1 100644 --- a/test/functional/apps/dashboard/view_edit.ts +++ b/test/functional/apps/dashboard/view_edit.ts @@ -15,6 +15,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const dashboardAddPanel = getService('dashboardAddPanel'); + const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects(['dashboard', 'header', 'common', 'visualize', 'timePicker']); const dashboardName = 'dashboard with filter'; const filterBar = getService('filterBar'); @@ -74,9 +75,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await PageObjects.dashboard.clickDiscardChanges(); - // confirm lose changes - await PageObjects.common.clickConfirmOnModal(); - const newTime = await PageObjects.timePicker.getTimeConfig(); expect(newTime.start).to.equal(originalTime.start); @@ -90,9 +88,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.clickDiscardChanges(); - // confirm lose changes - await PageObjects.common.clickConfirmOnModal(); - const query = await queryBar.getQueryString(); expect(query).to.equal(originalQuery); }); @@ -113,9 +108,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.clickDiscardChanges(); - // confirm lose changes - await PageObjects.common.clickConfirmOnModal(); - hasFilter = await filterBar.hasFilter('animal', 'dog'); expect(hasFilter).to.be(true); }); @@ -133,12 +125,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { redirectToOrigin: true, }); - await PageObjects.dashboard.clickDiscardChanges(); + await PageObjects.dashboard.clickDiscardChanges(false); // for this sleep see https://github.com/elastic/kibana/issues/22299 await PageObjects.common.sleep(500); // confirm lose changes - await PageObjects.common.clickConfirmOnModal(); + await testSubjects.exists('dashboardDiscardConfirmDiscard'); + await testSubjects.click('dashboardDiscardConfirmDiscard'); const panelCount = await PageObjects.dashboard.getPanelCount(); expect(panelCount).to.eql(originalPanelCount); @@ -150,9 +143,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardAddPanel.addVisualization('new viz panel'); await PageObjects.dashboard.clickDiscardChanges(); - // confirm lose changes - await PageObjects.common.clickConfirmOnModal(); - const panelCount = await PageObjects.dashboard.getPanelCount(); expect(panelCount).to.eql(originalPanelCount); }); @@ -171,9 +161,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Sep 19, 2015 @ 06:31:44.000', 'Sep 19, 2015 @ 06:31:44.000' ); - await PageObjects.dashboard.clickDiscardChanges(); + await PageObjects.dashboard.clickDiscardChanges(false); - await PageObjects.common.clickCancelOnModal(); + await testSubjects.exists('dashboardDiscardConfirmCancel'); + await testSubjects.click('dashboardDiscardConfirmCancel'); await PageObjects.dashboard.saveDashboard(dashboardName, { storeTimeWithDashboard: true, }); @@ -200,9 +191,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); const newTime = await PageObjects.timePicker.getTimeConfig(); - await PageObjects.dashboard.clickDiscardChanges(); + await PageObjects.dashboard.clickDiscardChanges(false); - await PageObjects.common.clickCancelOnModal(); + await testSubjects.exists('dashboardDiscardConfirmCancel'); + await testSubjects.click('dashboardDiscardConfirmCancel'); await PageObjects.dashboard.saveDashboard(dashboardName, { storeTimeWithDashboard: true }); await PageObjects.dashboard.loadSavedDashboard(dashboardName); @@ -223,7 +215,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Oct 19, 2014 @ 06:31:44.000', 'Dec 19, 2014 @ 06:31:44.000' ); - await PageObjects.dashboard.clickCancelOutOfEditMode(); + await PageObjects.dashboard.clickCancelOutOfEditMode(false); await PageObjects.common.expectConfirmModalOpenState(false); }); @@ -235,7 +227,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const originalQuery = await queryBar.getQueryString(); await queryBar.setQuery(`${originalQuery}extra stuff`); - await PageObjects.dashboard.clickCancelOutOfEditMode(); + await PageObjects.dashboard.clickCancelOutOfEditMode(false); await PageObjects.common.expectConfirmModalOpenState(false); diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 4291d67a6bc082..9c571f0f0ef86b 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -246,14 +246,26 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide return await testSubjects.exists('dashboardEditMode'); } - public async clickCancelOutOfEditMode() { + public async clickCancelOutOfEditMode(accept = true) { log.debug('clickCancelOutOfEditMode'); await testSubjects.click('dashboardViewOnlyMode'); + if (accept) { + const confirmation = await testSubjects.exists('dashboardDiscardConfirmKeep'); + if (confirmation) { + await testSubjects.click('dashboardDiscardConfirmKeep'); + } + } } - public async clickDiscardChanges() { + public async clickDiscardChanges(accept = true) { log.debug('clickDiscardChanges'); - await testSubjects.click('dashboardDiscardChanges'); + await testSubjects.click('dashboardViewOnlyMode'); + if (accept) { + const confirmation = await testSubjects.exists('dashboardDiscardConfirmDiscard'); + if (confirmation) { + await testSubjects.click('dashboardDiscardConfirmDiscard'); + } + } } public async clickQuickSave() { From d4f3420b416b0e1378c81a1c85bb6c012dcf6841 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 16 Feb 2021 13:06:25 -0500 Subject: [PATCH 06/46] [Docs] Clarify KQL and Lucene docs (#91065) * [Docs] Clarify KQL and Lucene docs * Code review suggestions --- docs/discover/kuery.asciidoc | 64 +++++++++++++++++++++-------------- docs/discover/search.asciidoc | 59 +++++++++++++++++++++----------- 2 files changed, 78 insertions(+), 45 deletions(-) diff --git a/docs/discover/kuery.asciidoc b/docs/discover/kuery.asciidoc index 8c0012fb6c6bf5..a92fc182f388c3 100644 --- a/docs/discover/kuery.asciidoc +++ b/docs/discover/kuery.asciidoc @@ -1,55 +1,63 @@ [[kuery-query]] === Kibana Query Language -The Kibana Query Language (KQL) makes it easy to find -the fields and syntax for your {es} query. If you have the -https://www.elastic.co/subscriptions[Basic tier] or above, -simply place your cursor in the *Search* field. As you type, you’ll get suggestions for fields, -values, and operators. +The Kibana Query Language (KQL) is a simple syntax for filtering {es} data using +free text search or field-based search. KQL is only used for filtering data, and has +no role in sorting or aggregating the data. + +KQL is able to suggest field names, values, and operators as you type. +The performance of the suggestions is controlled by <>: [role="screenshot"] image::images/kql-autocomplete.png[Autocomplete in Search bar] -If you prefer to use Kibana’s legacy query language, based on the -<>, click *KQL* next to the *Search* field, and then turn off KQL. +KQL has a different set of features than the <>. KQL is able to query +nested fields and <>. KQL does not support regular expressions +or searching with fuzzy terms. To use the legacy Lucene syntax, click *KQL* next to the *Search* field, +and then turn off KQL. [discrete] === Terms query -A terms query matches documents that contain one or more *exact* terms in a field. +A terms query uses *exact search terms*. Spaces separate each search term, and only one term +is required to match the document. Use quotation marks to indicate a *phrase match*. -To match documents where the response field is `200`: +To query using *exact search terms*, enter the field name followed by `:` and +then the values separated by spaces: [source,yaml] ------------------- -response:200 +http.response.status_code:400 401 404 ------------------- -To match documents with the phrase "quick brown fox" in the `message` field. +For text fields, this will match any value regardless of order: [source,yaml] ------------------- -message:"quick brown fox" +http.response.body.content.text:quick brown fox ------------------- -Without the quotes, -the query matches documents regardless of the order in which -they appear. Documents with "quick brown fox" match, -and so does "quick fox brown". +To query for an *exact phrase*, use quotation marks around the values: + +[source,yaml] +------------------- +http.response.body.content.text:"quick brown fox" +------------------- -NOTE: Terms without fields are matched against the default field in your index settings. -If a default field is not -set, terms are matched against all fields. For example, a query -for `response:200` searches for the value 200 -in the response field, but a query for just `200` searches for 200 -across all fields in your index. +Field names are not required by KQL. When a field name is not provided, terms +will be matched by the default fields in your index settings. To search across fields: +[source,yaml] +------------------- +"quick brown fox" +------------------- [discrete] === Boolean queries KQL supports `or`, `and`, and `not`. By default, `and` has a higher precedence than `or`. -To override the default precedence, group operators in parentheses. +To override the default precedence, group operators in parentheses. These operators can +be upper or lower case. To match documents where response is `200`, extension is `php`, or both: @@ -143,7 +151,7 @@ but in some cases you might need to search on dates. Include the date range in q [discrete] === Exist queries -An exist query matches documents that contain a value for a field, in this case, +An exist query matches documents that contain any value for a field, in this case, response: [source,yaml] @@ -151,10 +159,16 @@ response: response:* ------------------- +Existence is defined by {es} and includes all values, including empty text. + [discrete] === Wildcard queries -To match documents where machine.os starts with `win`, such +Wildcards queries can be used to *search by a term prefix* or to *search multiple fields*. +The default settings of {kib} *prevent leading wildcards* for performance reasons, +but this can be allowed with an <>. + +To match documents where `machine.os` starts with `win`, such as "windows 7" and "windows 10": [source,yaml] diff --git a/docs/discover/search.asciidoc b/docs/discover/search.asciidoc index 45f0df5bd773fc..e8faccd50661a8 100644 --- a/docs/discover/search.asciidoc +++ b/docs/discover/search.asciidoc @@ -53,36 +53,55 @@ include::kuery.asciidoc[] [[lucene-query]] === Lucene query syntax -Kibana's legacy query language was based on the Lucene query syntax. For the time being this syntax -is still available under the options menu in the Query Bar and in Advanced Settings. The following -are some tips that can help get you started. +Lucene query syntax is available to {kib} users who opt out of the <>. +Full documentation for this syntax is available as part of {es} +{ref}/query-dsl-query-string-query.html#query-string-syntax[query string syntax]. -* To perform a free text search, simply enter a text string. For example, if +The main reason to use the Lucene query syntax in {kib} is for advanced +Lucene features, such as regular expressions or fuzzy term matching. However, +Lucene syntax is not able to search nested objects or scripted fields. + +To perform a free text search, simply enter a text string. For example, if you're searching web server logs, you could enter `safari` to search all -fields for the term `safari`. +fields: + +[source,yaml] +------------------- +safari +------------------- + +To search for a value in a specific field, prefix the value with the name +of the field: -* To search for a value in a specific field, prefix the value with the name -of the field. For example, you could enter `status:200` to find all of -the entries that contain the value `200` in the `status` field. +[source,yaml] +------------------- +status:200 +------------------- -* To search for a range of values, you can use the bracketed range syntax, +To search for a range of values, use the bracketed range syntax, `[START_VALUE TO END_VALUE]`. For example, to find entries that have 4xx status codes, you could enter `status:[400 TO 499]`. -* To specify more complex search criteria, you can use the Boolean operators -`AND`, `OR`, and `NOT`. For example, to find entries that have 4xx status -codes and have an extension of `php` or `html`, you could enter `status:[400 TO -499] AND (extension:php OR extension:html)`. +[source,yaml] +------------------- +status:[400 TO 499] +------------------- + +For an open range, use a wildcard: -IMPORTANT: When you use the Lucene Query Syntax in the *KQL* search bar, {kib} is unable to search on nested objects and perform aggregations across fields that contain nested objects. -Using `include_in_parent` or `copy_to` as a workaround can cause {kib} to fail. +[source,yaml] +------------------- +status:[400 TO *] +------------------- -For more detailed information about the Lucene query syntax, see the -{ref}/query-dsl-query-string-query.html#query-string-syntax[Query String Query] -docs. +To specify more complex search criteria, use the boolean operators +`AND`, `OR`, and `NOT`. For example, to find entries that have 4xx status +codes and have an extension of `php` or `html`: -NOTE: These examples use the Lucene query syntax. When lucene is selected as your -query language you can also submit queries using the {ref}/query-dsl.html[Elasticsearch Query DSL]. +[source,yaml] +------------------- +status:[400 TO 499] AND (extension:php OR extension:html) +------------------- [[save-open-search]] From 5686d85ac1468c75782e4fd9e232e9e6f7c9dbdb Mon Sep 17 00:00:00 2001 From: Kevin Logan <56395104+kevinlog@users.noreply.github.com> Date: Tue, 16 Feb 2021 13:41:34 -0500 Subject: [PATCH 07/46] [Security Solution] add unsupported type to Endpoint Policy response (#91295) * add unsupported type * update types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../security_solution/common/endpoint/generate_data.ts | 4 +++- .../plugins/security_solution/common/endpoint/types/index.ts | 1 + .../search_strategy/security_solution/hosts/common/index.ts | 1 + x-pack/plugins/security_solution/public/graphql/types.ts | 1 + .../management/pages/endpoint_hosts/view/host_constants.ts | 4 ++++ .../security_solution/server/graphql/hosts/schema.gql.ts | 1 + x-pack/plugins/security_solution/server/graphql/types.ts | 1 + 7 files changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts index ffeaf853828f13..8aec9768dd50d2 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -101,6 +101,7 @@ const POLICY_RESPONSE_STATUSES: HostPolicyResponseActionStatus[] = [ HostPolicyResponseActionStatus.success, HostPolicyResponseActionStatus.failure, HostPolicyResponseActionStatus.warning, + HostPolicyResponseActionStatus.unsupported, ]; const APPLIED_POLICIES: Array<{ @@ -1492,7 +1493,7 @@ export class EndpointDocGenerator { { name: 'workflow', message: 'Failed to apply a portion of the configuration (kernel)', - status: HostPolicyResponseActionStatus.success, + status: HostPolicyResponseActionStatus.unsupported, }, { name: 'download_model', @@ -1637,6 +1638,7 @@ export class EndpointDocGenerator { HostPolicyResponseActionStatus.failure, HostPolicyResponseActionStatus.success, HostPolicyResponseActionStatus.warning, + HostPolicyResponseActionStatus.unsupported, ]); } diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index d361c0d6282a34..94a09b385a08c8 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -933,6 +933,7 @@ export enum HostPolicyResponseActionStatus { success = 'success', failure = 'failure', warning = 'warning', + unsupported = 'unsupported', } /** diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts index 40e353263bcc8c..7e19944ea5856c 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts @@ -13,6 +13,7 @@ export enum HostPolicyResponseActionStatus { success = 'success', failure = 'failure', warning = 'warning', + unsupported = 'unsupported', } export enum HostsFields { diff --git a/x-pack/plugins/security_solution/public/graphql/types.ts b/x-pack/plugins/security_solution/public/graphql/types.ts index 4397573217312d..f70cd37b8da94e 100644 --- a/x-pack/plugins/security_solution/public/graphql/types.ts +++ b/x-pack/plugins/security_solution/public/graphql/types.ts @@ -273,6 +273,7 @@ export enum HostPolicyResponseActionStatus { success = 'success', failure = 'failure', warning = 'warning', + unsupported = 'unsupported', } export enum TimelineType { diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/host_constants.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/host_constants.ts index 37a26d88053521..4745cd9de249db 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/host_constants.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/host_constants.ts @@ -25,6 +25,7 @@ export const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze< success: 'success', warning: 'warning', failure: 'danger', + unsupported: 'subdued', }); export const POLICY_STATUS_TO_TEXT = Object.freeze< @@ -39,4 +40,7 @@ export const POLICY_STATUS_TO_TEXT = Object.freeze< failure: i18n.translate('xpack.securitySolution.policyStatusText.failure', { defaultMessage: 'Failure', }), + unsupported: i18n.translate('xpack.securitySolution.policyStatusText.unsupported', { + defaultMessage: 'Unsupported', + }), }); diff --git a/x-pack/plugins/security_solution/server/graphql/hosts/schema.gql.ts b/x-pack/plugins/security_solution/server/graphql/hosts/schema.gql.ts index f3d553936bac53..c3a5c4e3b23cf1 100644 --- a/x-pack/plugins/security_solution/server/graphql/hosts/schema.gql.ts +++ b/x-pack/plugins/security_solution/server/graphql/hosts/schema.gql.ts @@ -50,6 +50,7 @@ export const hostsSchema = gql` success failure warning + unsupported } type EndpointFields { diff --git a/x-pack/plugins/security_solution/server/graphql/types.ts b/x-pack/plugins/security_solution/server/graphql/types.ts index d1e646e73cf12c..0d6a0e63455b00 100644 --- a/x-pack/plugins/security_solution/server/graphql/types.ts +++ b/x-pack/plugins/security_solution/server/graphql/types.ts @@ -275,6 +275,7 @@ export enum HostPolicyResponseActionStatus { success = 'success', failure = 'failure', warning = 'warning', + unsupported = 'unsupported', } export enum TimelineType { From 9d8376d890ea30312430e717ea2c0453845aea9f Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Feb 2021 10:42:26 -0800 Subject: [PATCH 08/46] ship @kbn/ui-shared-deps metrics in separate step (#91504) Co-authored-by: spalger --- packages/kbn-ui-shared-deps/scripts/build.js | 32 ++----------------- packages/kbn-ui-shared-deps/webpack.config.js | 31 ++++++++++++++++++ test/scripts/jenkins_baseline.sh | 4 ++- test/scripts/jenkins_build_kibana.sh | 4 ++- test/scripts/jenkins_xpack_baseline.sh | 4 ++- test/scripts/jenkins_xpack_build_kibana.sh | 4 ++- 6 files changed, 45 insertions(+), 34 deletions(-) diff --git a/packages/kbn-ui-shared-deps/scripts/build.js b/packages/kbn-ui-shared-deps/scripts/build.js index 9e1e755b3077a3..0993f785902464 100644 --- a/packages/kbn-ui-shared-deps/scripts/build.js +++ b/packages/kbn-ui-shared-deps/scripts/build.js @@ -7,9 +7,8 @@ */ const Path = require('path'); -const Fs = require('fs'); -const { run, createFailError, CiStatsReporter } = require('@kbn/dev-utils'); +const { run, createFailError } = require('@kbn/dev-utils'); const webpack = require('webpack'); const Stats = require('webpack/lib/Stats'); const del = require('del'); @@ -34,34 +33,6 @@ run( const took = Math.round((stats.endTime - stats.startTime) / 1000); if (!stats.hasErrors() && !stats.hasWarnings()) { - if (!flags.dev) { - const reporter = CiStatsReporter.fromEnv(log); - - const metrics = [ - { - group: '@kbn/ui-shared-deps asset size', - id: 'kbn-ui-shared-deps.js', - value: Fs.statSync(Path.resolve(DIST_DIR, 'kbn-ui-shared-deps.js')).size, - }, - { - group: '@kbn/ui-shared-deps asset size', - id: 'kbn-ui-shared-deps.@elastic.js', - value: Fs.statSync(Path.resolve(DIST_DIR, 'kbn-ui-shared-deps.@elastic.js')).size, - }, - { - group: '@kbn/ui-shared-deps asset size', - id: 'css', - value: - Fs.statSync(Path.resolve(DIST_DIR, 'kbn-ui-shared-deps.css')).size + - Fs.statSync(Path.resolve(DIST_DIR, 'kbn-ui-shared-deps.v7.light.css')).size, - }, - ]; - - log.debug('metrics:', metrics); - - await reporter.metrics(metrics); - } - log.success(`webpack completed in about ${took} seconds`); return; } @@ -101,6 +72,7 @@ run( return; } + log.info('running webpack'); await onCompilationComplete( await new Promise((resolve, reject) => { compiler.run((error, stats) => { diff --git a/packages/kbn-ui-shared-deps/webpack.config.js b/packages/kbn-ui-shared-deps/webpack.config.js index 7ff5978e1f2ea2..cc761dae3bfe96 100644 --- a/packages/kbn-ui-shared-deps/webpack.config.js +++ b/packages/kbn-ui-shared-deps/webpack.config.js @@ -12,6 +12,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CompressionPlugin = require('compression-webpack-plugin'); const { REPO_ROOT } = require('@kbn/utils'); const webpack = require('webpack'); +const { RawSource } = require('webpack-sources'); const UiSharedDeps = require('./index'); @@ -145,6 +146,36 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({ test: /\.(js|css)$/, cache: false, }), + new (class MetricsPlugin { + apply(compiler) { + compiler.hooks.emit.tap('MetricsPlugin', (compilation) => { + const metrics = [ + { + group: '@kbn/ui-shared-deps asset size', + id: 'kbn-ui-shared-deps.js', + value: compilation.assets['kbn-ui-shared-deps.js'].size(), + }, + { + group: '@kbn/ui-shared-deps asset size', + id: 'kbn-ui-shared-deps.@elastic.js', + value: compilation.assets['kbn-ui-shared-deps.@elastic.js'].size(), + }, + { + group: '@kbn/ui-shared-deps asset size', + id: 'css', + value: + compilation.assets['kbn-ui-shared-deps.css'].size() + + compilation.assets['kbn-ui-shared-deps.v7.light.css'].size(), + }, + ]; + + compilation.emitAsset( + 'metrics.json', + new RawSource(JSON.stringify(metrics, null, 2)) + ); + }); + } + })(), ]), ], }); diff --git a/test/scripts/jenkins_baseline.sh b/test/scripts/jenkins_baseline.sh index 60926238576c77..58d86cddf65fa7 100755 --- a/test/scripts/jenkins_baseline.sh +++ b/test/scripts/jenkins_baseline.sh @@ -7,7 +7,9 @@ echo " -> building and extracting OSS Kibana distributable for use in functional node scripts/build --debug --oss echo " -> shipping metrics from build to ci-stats" -node scripts/ship_ci_stats --metrics target/optimizer_bundle_metrics.json +node scripts/ship_ci_stats \ + --metrics target/optimizer_bundle_metrics.json \ + --metrics packages/kbn-ui-shared-deps/target/metrics.json linuxBuild="$(find "$KIBANA_DIR/target" -name 'kibana-*-linux-x86_64.tar.gz')" installDir="$PARENT_DIR/install/kibana" diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh index 5819a3ce6765e1..fa0c9522ef5fb1 100755 --- a/test/scripts/jenkins_build_kibana.sh +++ b/test/scripts/jenkins_build_kibana.sh @@ -18,7 +18,9 @@ if [[ -z "$CODE_COVERAGE" ]] ; then node scripts/build --debug --oss echo " -> shipping metrics from build to ci-stats" - node scripts/ship_ci_stats --metrics target/optimizer_bundle_metrics.json + node scripts/ship_ci_stats \ + --metrics target/optimizer_bundle_metrics.json \ + --metrics packages/kbn-ui-shared-deps/target/metrics.json mkdir -p "$WORKSPACE/kibana-build-oss" cp -pR build/oss/kibana-*-SNAPSHOT-linux-x86_64/. $WORKSPACE/kibana-build-oss/ diff --git a/test/scripts/jenkins_xpack_baseline.sh b/test/scripts/jenkins_xpack_baseline.sh index aaacdd4ea3aaec..2755a6e0a705dc 100755 --- a/test/scripts/jenkins_xpack_baseline.sh +++ b/test/scripts/jenkins_xpack_baseline.sh @@ -8,7 +8,9 @@ cd "$KIBANA_DIR" node scripts/build --debug --no-oss echo " -> shipping metrics from build to ci-stats" -node scripts/ship_ci_stats --metrics target/optimizer_bundle_metrics.json +node scripts/ship_ci_stats \ + --metrics target/optimizer_bundle_metrics.json \ + --metrics packages/kbn-ui-shared-deps/target/metrics.json linuxBuild="$(find "$KIBANA_DIR/target" -name 'kibana-*-linux-x86_64.tar.gz')" installDir="$KIBANA_DIR/install/kibana" diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index 36865ce7c4967a..2887a51f262833 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -34,7 +34,9 @@ if [[ -z "$CODE_COVERAGE" ]] ; then node scripts/build --debug --no-oss echo " -> shipping metrics from build to ci-stats" - node scripts/ship_ci_stats --metrics target/optimizer_bundle_metrics.json + node scripts/ship_ci_stats \ + --metrics target/optimizer_bundle_metrics.json \ + --metrics packages/kbn-ui-shared-deps/target/metrics.json linuxBuild="$(find "$KIBANA_DIR/target" -name 'kibana-*-linux-x86_64.tar.gz')" installDir="$KIBANA_DIR/install/kibana" From 3e7ce0c53ee42b55435dedf411fc3314947f734d Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Tue, 16 Feb 2021 12:44:15 -0600 Subject: [PATCH 09/46] TS project references for monitoring plugin (#91498) Fixes #89293. --- tsconfig.refs.json | 1 + x-pack/plugins/monitoring/tsconfig.json | 31 +++++++++++++++++++++++++ x-pack/test/tsconfig.json | 3 ++- x-pack/tsconfig.json | 6 ++--- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/monitoring/tsconfig.json diff --git a/tsconfig.refs.json b/tsconfig.refs.json index 39f3057ec9b2a7..7806cf93756e57 100644 --- a/tsconfig.refs.json +++ b/tsconfig.refs.json @@ -87,6 +87,7 @@ { "path": "./x-pack/plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./x-pack/plugins/maps/tsconfig.json" }, { "path": "./x-pack/plugins/ml/tsconfig.json" }, + { "path": "./x-pack/plugins/monitoring/tsconfig.json" }, { "path": "./x-pack/plugins/observability/tsconfig.json" }, { "path": "./x-pack/plugins/osquery/tsconfig.json" }, { "path": "./x-pack/plugins/painless_lab/tsconfig.json" }, diff --git a/x-pack/plugins/monitoring/tsconfig.json b/x-pack/plugins/monitoring/tsconfig.json new file mode 100644 index 00000000000000..760ff188aacfc1 --- /dev/null +++ b/x-pack/plugins/monitoring/tsconfig.json @@ -0,0 +1,31 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": ["common/**/*", "public/**/*", "server/**/*"], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + { "path": "../../../src/plugins/data/tsconfig.json" }, + { "path": "../../../src/plugins/home/tsconfig.json" }, + { "path": "../../../src/plugins/kibana_legacy/tsconfig.json" }, + { "path": "../../../src/plugins/kibana_utils/tsconfig.json" }, + { "path": "../../../src/plugins/navigation/tsconfig.json" }, + { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, + { "path": "../actions/tsconfig.json" }, + { "path": "../alerts/tsconfig.json" }, + { "path": "../cloud/tsconfig.json" }, + { "path": "../encrypted_saved_objects/tsconfig.json" }, + { "path": "../features/tsconfig.json" }, + { "path": "../infra/tsconfig.json" }, + { "path": "../license_management/tsconfig.json" }, + { "path": "../licensing/tsconfig.json" }, + { "path": "../observability/tsconfig.json" }, + { "path": "../telemetry_collection_xpack/tsconfig.json" }, + { "path": "../triggers_actions_ui/tsconfig.json" } + ] +} diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 1c2e0aeecd2477..ff3fec1c5aaee7 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -69,6 +69,7 @@ { "path": "../plugins/license_management/tsconfig.json" }, { "path": "../plugins/licensing/tsconfig.json" }, { "path": "../plugins/ml/tsconfig.json" }, + { "path": "../plugins/monitoring/tsconfig.json" }, { "path": "../plugins/observability/tsconfig.json" }, { "path": "../plugins/osquery/tsconfig.json" }, { "path": "../plugins/painless_lab/tsconfig.json" }, @@ -88,7 +89,7 @@ { "path": "../plugins/rollup/tsconfig.json" }, { "path": "../plugins/remote_clusters/tsconfig.json" }, { "path": "../plugins/cross_cluster_replication/tsconfig.json" }, - { "path": "../plugins/index_lifecycle_management/tsconfig.json"}, + { "path": "../plugins/index_lifecycle_management/tsconfig.json" }, { "path": "../plugins/uptime/tsconfig.json" } ] } diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 813811d4a9ce45..b3e47136977e21 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -7,7 +7,6 @@ "plugins/case/**/*", "plugins/lists/**/*", "plugins/logstash/**/*", - "plugins/monitoring/**/*", "plugins/security_solution/**/*", "plugins/xpack_legacy/**/*", "plugins/drilldowns/url_drilldown/**/*" @@ -90,6 +89,7 @@ { "path": "./plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./plugins/maps/tsconfig.json" }, { "path": "./plugins/ml/tsconfig.json" }, + { "path": "./plugins/monitoring/tsconfig.json" }, { "path": "./plugins/observability/tsconfig.json" }, { "path": "./plugins/osquery/tsconfig.json" }, { "path": "./plugins/painless_lab/tsconfig.json" }, @@ -111,8 +111,8 @@ { "path": "./plugins/watcher/tsconfig.json" }, { "path": "./plugins/rollup/tsconfig.json" }, { "path": "./plugins/remote_clusters/tsconfig.json" }, - { "path": "./plugins/cross_cluster_replication/tsconfig.json"}, - { "path": "./plugins/index_lifecycle_management/tsconfig.json"}, + { "path": "./plugins/cross_cluster_replication/tsconfig.json" }, + { "path": "./plugins/index_lifecycle_management/tsconfig.json" }, { "path": "./plugins/uptime/tsconfig.json" } ] } From 0ecac0cabb1867183bd3466f167683f3914a9feb Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 16 Feb 2021 11:47:04 -0700 Subject: [PATCH 10/46] [Maps] fix reporting jobs fail when Elastic Maps Service (EMS) is unavailable (#90834) * [Maps] fix Reporting jobs fail when Elastic Maps Service (EMS) is unavailable * clean up test case names * make tests more explicit Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/selectors/map_selectors.test.ts | 79 ++++++++++++++++++- .../maps/public/selectors/map_selectors.ts | 7 +- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index c2f5fc02c5df20..89cd80f4daab50 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -26,10 +26,12 @@ jest.mock('../kibana_services', () => ({ })); import { DEFAULT_MAP_STORE_STATE } from '../reducers/store'; -import { getTimeFilters } from './map_selectors'; +import { areLayersLoaded, getTimeFilters } from './map_selectors'; +import { LayerDescriptor } from '../../common/descriptor_types'; +import { ILayer } from '../classes/layers/layer'; describe('getTimeFilters', () => { - it('should return timeFilters when contained in state', () => { + test('should return timeFilters when contained in state', () => { const state = { ...DEFAULT_MAP_STORE_STATE, map: { @@ -46,7 +48,7 @@ describe('getTimeFilters', () => { expect(getTimeFilters(state)).toEqual({ to: '2001-01-01', from: '2001-12-31' }); }); - it('should return kibana time filters when not contained in state', () => { + test('should return kibana time filters when not contained in state', () => { const state = { ...DEFAULT_MAP_STORE_STATE, map: { @@ -60,3 +62,74 @@ describe('getTimeFilters', () => { expect(getTimeFilters(state)).toEqual({ to: 'now', from: 'now-15m' }); }); }); + +describe('areLayersLoaded', () => { + function createLayerMock({ + hasErrors = false, + isDataLoaded = false, + isVisible = true, + showAtZoomLevel = true, + }: { + hasErrors?: boolean; + isDataLoaded?: boolean; + isVisible?: boolean; + showAtZoomLevel?: boolean; + }) { + return ({ + hasErrors: () => { + return hasErrors; + }, + isDataLoaded: () => { + return isDataLoaded; + }, + isVisible: () => { + return isVisible; + }, + showAtZoomLevel: () => { + return showAtZoomLevel; + }, + } as unknown) as ILayer; + } + + test('layers waiting for map to load should not be counted loaded', () => { + const layerList: ILayer[] = []; + const waitingForMapReadyLayerList: LayerDescriptor[] = [({} as unknown) as LayerDescriptor]; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); + }); + + test('layer should not be counted as loaded if it has not loaded', () => { + const layerList = [createLayerMock({ isDataLoaded: false })]; + const waitingForMapReadyLayerList: LayerDescriptor[] = []; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); + }); + + test('layer should be counted as loaded if its not visible', () => { + const layerList = [createLayerMock({ isVisible: false, isDataLoaded: false })]; + const waitingForMapReadyLayerList: LayerDescriptor[] = []; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + }); + + test('layer should be counted as loaded if its not shown at zoom level', () => { + const layerList = [createLayerMock({ showAtZoomLevel: false, isDataLoaded: false })]; + const waitingForMapReadyLayerList: LayerDescriptor[] = []; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + }); + + test('layer should be counted as loaded if it has a loading error', () => { + const layerList = [createLayerMock({ hasErrors: true, isDataLoaded: false })]; + const waitingForMapReadyLayerList: LayerDescriptor[] = []; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + }); + + test('layer should be counted as loaded if its loaded', () => { + const layerList = [createLayerMock({ isDataLoaded: true })]; + const waitingForMapReadyLayerList: LayerDescriptor[] = []; + const zoom = 4; + expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); + }); +}); diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index f53f39ad2fc0cc..b16ac704c3715b 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -428,7 +428,12 @@ export const areLayersLoaded = createSelector( for (let i = 0; i < layerList.length; i++) { const layer = layerList[i]; - if (layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.isDataLoaded()) { + if ( + layer.isVisible() && + layer.showAtZoomLevel(zoom) && + !layer.hasErrors() && + !layer.isDataLoaded() + ) { return false; } } From dc4e94e0bac5970b00f55ce96304c66320cb2997 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Tue, 16 Feb 2021 13:47:25 -0500 Subject: [PATCH 11/46] [Time to Visualize] Unsaved Changes Badge (#91073) * Added unsaved changes badge to dashboards. Removed (unsaved) from the dashboard title --- .../public/application/dashboard_app.tsx | 10 ++++- .../application/dashboard_state.test.ts | 2 + .../application/dashboard_state_manager.ts | 16 +++++++ .../hooks/use_dashboard_breadcrumbs.ts | 1 - .../hooks/use_dashboard_container.test.tsx | 14 ++++--- .../hooks/use_dashboard_container.ts | 30 +++++++++---- .../hooks/use_dashboard_state_manager.ts | 3 +- .../application/top_nav/dashboard_top_nav.tsx | 15 ++++++- .../dashboard/public/dashboard_strings.ts | 42 ++++++++----------- .../public/top_nav_menu/_index.scss | 9 ++++ .../public/top_nav_menu/top_nav_menu.tsx | 26 ++++++++++-- .../apps/dashboard/copy_panel_to.ts | 2 +- .../apps/dashboard/dashboard_unsaved_state.ts | 25 ++++++++++- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 15 files changed, 148 insertions(+), 49 deletions(-) diff --git a/src/plugins/dashboard/public/application/dashboard_app.tsx b/src/plugins/dashboard/public/application/dashboard_app.tsx index d060327563b25b..f659fa002e922b 100644 --- a/src/plugins/dashboard/public/application/dashboard_app.tsx +++ b/src/plugins/dashboard/public/application/dashboard_app.tsx @@ -67,7 +67,13 @@ export function DashboardApp({ savedDashboard, history ); - const dashboardContainer = useDashboardContainer(dashboardStateManager, history, false); + const [unsavedChanges, setUnsavedChanges] = useState(false); + const dashboardContainer = useDashboardContainer({ + timeFilter: data.query.timefilter.timefilter, + dashboardStateManager, + setUnsavedChanges, + history, + }); const searchSessionIdQuery$ = useMemo( () => createQueryParamObservable(history, DashboardConstants.SEARCH_SESSION_ID), [history] @@ -200,6 +206,7 @@ export function DashboardApp({ ); dashboardStateManager.registerChangeListener(() => { + setUnsavedChanges(dashboardStateManager?.hasUnsavedPanelState()); // we aren't checking dirty state because there are changes the container needs to know about // that won't make the dashboard "dirty" - like a view mode change. triggerRefresh$.next(); @@ -281,6 +288,7 @@ export function DashboardApp({ embedSettings, indexPatterns, savedDashboard, + unsavedChanges, dashboardContainer, dashboardStateManager, }} diff --git a/src/plugins/dashboard/public/application/dashboard_state.test.ts b/src/plugins/dashboard/public/application/dashboard_state.test.ts index 04112d10ae7e3b..c5bda98c31b700 100644 --- a/src/plugins/dashboard/public/application/dashboard_state.test.ts +++ b/src/plugins/dashboard/public/application/dashboard_state.test.ts @@ -17,6 +17,7 @@ import { createKbnUrlStateStorage } from '../services/kibana_utils'; import { InputTimeRange, TimefilterContract, TimeRange } from '../services/data'; import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; +import { coreMock } from '../../../../core/public/mocks'; describe('DashboardState', function () { let dashboardState: DashboardStateManager; @@ -45,6 +46,7 @@ describe('DashboardState', function () { kibanaVersion: '7.0.0', kbnUrlStateStorage: createKbnUrlStateStorage(), history: createBrowserHistory(), + toasts: coreMock.createStart().notifications.toasts, hasTaggingCapabilities: mockHasTaggingCapabilities, }); } diff --git a/src/plugins/dashboard/public/application/dashboard_state_manager.ts b/src/plugins/dashboard/public/application/dashboard_state_manager.ts index 8494900ea79c7e..e4b2afa8a46ea3 100644 --- a/src/plugins/dashboard/public/application/dashboard_state_manager.ts +++ b/src/plugins/dashboard/public/application/dashboard_state_manager.ts @@ -43,6 +43,8 @@ import { syncState, } from '../services/kibana_utils'; import { STATE_STORAGE_KEY } from '../url_generator'; +import { NotificationsStart } from '../services/core'; +import { getMigratedToastText } from '../dashboard_strings'; /** * Dashboard state manager handles connecting angular and redux state between the angular and react portions of the @@ -59,10 +61,12 @@ export class DashboardStateManager { query: Query; }; private stateDefaults: DashboardAppStateDefaults; + private toasts: NotificationsStart['toasts']; private hideWriteControls: boolean; private kibanaVersion: string; public isDirty: boolean; private changeListeners: Array<(status: { dirty: boolean }) => void>; + private hasShownMigrationToast = false; public get appState(): DashboardAppState { return this.stateContainer.get(); @@ -93,6 +97,7 @@ export class DashboardStateManager { * @param */ constructor({ + toasts, history, kibanaVersion, savedDashboard, @@ -108,11 +113,13 @@ export class DashboardStateManager { hideWriteControls: boolean; allowByValueEmbeddables: boolean; savedDashboard: DashboardSavedObject; + toasts: NotificationsStart['toasts']; usageCollection?: UsageCollectionSetup; kbnUrlStateStorage: IKbnUrlStateStorage; dashboardPanelStorage?: DashboardPanelStorage; hasTaggingCapabilities: SavedObjectTagDecoratorTypeGuard; }) { + this.toasts = toasts; this.kibanaVersion = kibanaVersion; this.savedDashboard = savedDashboard; this.hideWriteControls = hideWriteControls; @@ -283,6 +290,10 @@ export class DashboardStateManager { if (dirty) { this.stateContainer.transitions.set('panels', Object.values(convertedPanelStateMap)); if (dirtyBecauseOfInitialStateMigration) { + if (this.getIsEditMode() && !this.hasShownMigrationToast) { + this.toasts.addSuccess(getMigratedToastText()); + this.hasShownMigrationToast = true; + } this.saveState({ replace: true }); } @@ -693,6 +704,11 @@ export class DashboardStateManager { this.dashboardPanelStorage.clearPanels(this.savedDashboard?.id); } + public hasUnsavedPanelState(): boolean { + const panels = this.dashboardPanelStorage?.getPanels(this.savedDashboard?.id); + return panels !== undefined && panels.length > 0; + } + private getUnsavedPanelState(): { panels?: SavedDashboardPanel[] } { if (!this.allowByValueEmbeddables || this.getIsViewMode() || !this.dashboardPanelStorage) { return {}; diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_breadcrumbs.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_breadcrumbs.ts index 6eb1c0bf75b240..50465cc4ab58b2 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_breadcrumbs.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_breadcrumbs.ts @@ -45,7 +45,6 @@ export const useDashboardBreadcrumbs = ( text: getDashboardTitle( dashboardStateManager.getTitle(), dashboardStateManager.getViewMode(), - dashboardStateManager.getIsDirty(timefilter), dashboardStateManager.isNew() ), }, diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_container.test.tsx b/src/plugins/dashboard/public/application/hooks/use_dashboard_container.test.tsx index d14b4056a64c67..6a6dc58db78157 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_container.test.tsx @@ -20,6 +20,7 @@ import { DashboardCapabilities } from '../types'; import { EmbeddableFactory } from '../../../../embeddable/public'; import { HelloWorldEmbeddable } from '../../../../embeddable/public/tests/fixtures'; import { DashboardContainer } from '../embeddable'; +import { coreMock } from 'src/core/public/mocks'; const savedDashboard = getSavedDashboardMock(); @@ -32,12 +33,13 @@ const history = createBrowserHistory(); const createDashboardState = () => new DashboardStateManager({ savedDashboard, + kibanaVersion: '7.0.0', hideWriteControls: false, allowByValueEmbeddables: false, - kibanaVersion: '7.0.0', - kbnUrlStateStorage: createKbnUrlStateStorage(), history: createBrowserHistory(), + kbnUrlStateStorage: createKbnUrlStateStorage(), hasTaggingCapabilities: mockHasTaggingCapabilities, + toasts: coreMock.createStart().notifications.toasts, }); const defaultCapabilities: DashboardCapabilities = { @@ -83,9 +85,9 @@ const setupEmbeddableFactory = () => { test('container is destroyed on unmount', async () => { const { createEmbeddable, destroySpy, embeddable } = setupEmbeddableFactory(); - const state = createDashboardState(); + const dashboardStateManager = createDashboardState(); const { result, unmount, waitForNextUpdate } = renderHook( - () => useDashboardContainer(state, history, false), + () => useDashboardContainer({ dashboardStateManager, history }), { wrapper: ({ children }) => ( {children} @@ -113,7 +115,7 @@ test('old container is destroyed on new dashboardStateManager', async () => { const { result, waitForNextUpdate, rerender } = renderHook< DashboardStateManager, DashboardContainer | null - >((dashboardState) => useDashboardContainer(dashboardState, history, false), { + >((dashboardStateManager) => useDashboardContainer({ dashboardStateManager, history }), { wrapper: ({ children }) => ( {children} ), @@ -148,7 +150,7 @@ test('destroyed if rerendered before resolved', async () => { const { result, waitForNextUpdate, rerender } = renderHook< DashboardStateManager, DashboardContainer | null - >((dashboardState) => useDashboardContainer(dashboardState, history, false), { + >((dashboardStateManager) => useDashboardContainer({ dashboardStateManager, history }), { wrapper: ({ children }) => ( {children} ), diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_container.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_container.ts index d12fea07bdd418..f4fe55f8774004 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_container.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_container.ts @@ -24,12 +24,21 @@ import { getDashboardContainerInput, getSearchSessionIdFromURL } from '../dashbo import { DashboardConstants, DashboardContainer, DashboardContainerInput } from '../..'; import { DashboardAppServices } from '../types'; import { DASHBOARD_CONTAINER_TYPE } from '..'; - -export const useDashboardContainer = ( - dashboardStateManager: DashboardStateManager | null, - history: History, - isEmbeddedExternally: boolean -) => { +import { TimefilterContract } from '../../services/data'; + +export const useDashboardContainer = ({ + history, + timeFilter, + setUnsavedChanges, + dashboardStateManager, + isEmbeddedExternally, +}: { + history: History; + isEmbeddedExternally?: boolean; + timeFilter?: TimefilterContract; + setUnsavedChanges?: (dirty: boolean) => void; + dashboardStateManager: DashboardStateManager | null; +}) => { const { dashboardCapabilities, data, @@ -72,15 +81,20 @@ export const useDashboardContainer = ( .getStateTransfer() .getIncomingEmbeddablePackage(DashboardConstants.DASHBOARDS_ID, true); + // when dashboard state manager initially loads, determine whether or not there are unsaved changes + setUnsavedChanges?.( + Boolean(incomingEmbeddable) || dashboardStateManager.hasUnsavedPanelState() + ); + let canceled = false; let pendingContainer: DashboardContainer | ErrorEmbeddable | null | undefined; (async function createContainer() { pendingContainer = await dashboardFactory.create( getDashboardContainerInput({ + isEmbeddedExternally: Boolean(isEmbeddedExternally), dashboardCapabilities, dashboardStateManager, incomingEmbeddable, - isEmbeddedExternally, query, searchSessionId: searchSessionIdFromURL ?? searchSession.start(), }) @@ -141,8 +155,10 @@ export const useDashboardContainer = ( dashboardCapabilities, dashboardStateManager, isEmbeddedExternally, + setUnsavedChanges, searchSession, scopedHistory, + timeFilter, embeddable, history, query, diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_state_manager.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_state_manager.ts index ed14223bb0a830..effd598cc3ee87 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_state_manager.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_state_manager.ts @@ -87,6 +87,7 @@ export const useDashboardStateManager = ( }); const stateManager = new DashboardStateManager({ + toasts: core.notifications.toasts, hasTaggingCapabilities, dashboardPanelStorage, hideWriteControls, @@ -160,7 +161,6 @@ export const useDashboardStateManager = ( const dashboardTitle = getDashboardTitle( stateManager.getTitle(), stateManager.getViewMode(), - stateManager.getIsDirty(timefilter), stateManager.isNew() ); @@ -213,6 +213,7 @@ export const useDashboardStateManager = ( uiSettings, usageCollection, allowByValueEmbeddables, + core.notifications.toasts, dashboardCapabilities.storeSearchSession, ]); diff --git a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx index e68d371ebb2703..11fb7f0cb56ff4 100644 --- a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx @@ -45,7 +45,7 @@ import { ShowShareModal } from './show_share_modal'; import { PanelToolbar } from './panel_toolbar'; import { confirmDiscardOrKeepUnsavedChanges } from '../listing/confirm_overlays'; import { OverlayRef } from '../../../../../core/public'; -import { getNewDashboardTitle } from '../../dashboard_strings'; +import { getNewDashboardTitle, unsavedChangesBadge } from '../../dashboard_strings'; import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage'; import { DashboardContainer } from '..'; @@ -64,6 +64,7 @@ export interface DashboardTopNavProps { timefilter: TimefilterContract; indexPatterns: IndexPattern[]; redirectTo: DashboardRedirect; + unsavedChanges?: boolean; lastDashboardId?: string; viewMode: ViewMode; } @@ -72,6 +73,7 @@ export function DashboardTopNav({ dashboardStateManager, dashboardContainer, lastDashboardId, + unsavedChanges, savedDashboard, onQuerySubmit, embedSettings, @@ -467,7 +469,18 @@ export function DashboardTopNav({ isDirty: dashboardStateManager.isDirty, }); + const badges = unsavedChanges + ? [ + { + 'data-test-subj': 'dashboardUnsavedChangesBadge', + badgeText: unsavedChangesBadge.getUnsavedChangedBadgeText(), + color: 'secondary', + }, + ] + : undefined; + return { + badges, appName: 'dashboard', config: showTopNavMenu ? topNav : undefined, className: isFullScreenMode ? 'kbnTopNavMenu-isFullScreen' : undefined, diff --git a/src/plugins/dashboard/public/dashboard_strings.ts b/src/plugins/dashboard/public/dashboard_strings.ts index 8588fbc1bbdc7f..dad347b176c7ef 100644 --- a/src/plugins/dashboard/public/dashboard_strings.ts +++ b/src/plugins/dashboard/public/dashboard_strings.ts @@ -12,36 +12,30 @@ import { ViewMode } from './services/embeddable'; /** * @param title {string} the current title of the dashboard * @param viewMode {DashboardViewMode} the current mode. If in editing state, prepends 'Editing ' to the title. - * @param isDirty {boolean} if the dashboard is in a dirty state. If in dirty state, adds (unsaved) to the - * end of the title. * @returns {string} A title to display to the user based on the above parameters. */ -export function getDashboardTitle( - title: string, - viewMode: ViewMode, - isDirty: boolean, - isNew: boolean -): string { +export function getDashboardTitle(title: string, viewMode: ViewMode, isNew: boolean): string { const isEditMode = viewMode === ViewMode.EDIT; - let displayTitle: string; const dashboardTitle = isNew ? getNewDashboardTitle() : title; + return isEditMode + ? i18n.translate('dashboard.strings.dashboardEditTitle', { + defaultMessage: 'Editing {title}', + values: { title: dashboardTitle }, + }) + : dashboardTitle; +} - if (isEditMode && isDirty) { - displayTitle = i18n.translate('dashboard.strings.dashboardUnsavedEditTitle', { - defaultMessage: 'Editing {title} (unsaved)', - values: { title: dashboardTitle }, - }); - } else if (isEditMode) { - displayTitle = i18n.translate('dashboard.strings.dashboardEditTitle', { - defaultMessage: 'Editing {title}', - values: { title: dashboardTitle }, - }); - } else { - displayTitle = dashboardTitle; - } +export const unsavedChangesBadge = { + getUnsavedChangedBadgeText: () => + i18n.translate('dashboard.unsavedChangesBadge', { + defaultMessage: 'Unsaved changes', + }), +}; - return displayTitle; -} +export const getMigratedToastText = () => + i18n.translate('dashboard.migratedChanges', { + defaultMessage: 'Some panels have been successfully updated to the latest version.', + }); /* Plugin diff --git a/src/plugins/navigation/public/top_nav_menu/_index.scss b/src/plugins/navigation/public/top_nav_menu/_index.scss index 230be399febda3..bc27cf061eb68a 100644 --- a/src/plugins/navigation/public/top_nav_menu/_index.scss +++ b/src/plugins/navigation/public/top_nav_menu/_index.scss @@ -1,3 +1,12 @@ .kbnTopNavMenu { margin-right: $euiSizeXS; } + +.kbnTopNavMenu__badgeWrapper { + display: flex; + align-items: baseline; +} + +.kbnTopNavMenu__badgeGroup { + margin-right: $euiSizeM; +} diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index 70bc3b10b30adc..22edf9c454466c 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -7,7 +7,7 @@ */ import React, { ReactElement } from 'react'; -import { EuiHeaderLinks } from '@elastic/eui'; +import { EuiBadge, EuiBadgeGroup, EuiBadgeProps, EuiHeaderLinks } from '@elastic/eui'; import classNames from 'classnames'; import { MountPoint } from '../../../../core/public'; @@ -23,6 +23,7 @@ import { TopNavMenuItem } from './top_nav_menu_item'; export type TopNavMenuProps = StatefulSearchBarProps & Omit & { config?: TopNavMenuData[]; + badges?: Array; showSearchBar?: boolean; showQueryBar?: boolean; showQueryInput?: boolean; @@ -61,12 +62,28 @@ export type TopNavMenuProps = StatefulSearchBarProps & **/ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { - const { config, showSearchBar, ...searchBarProps } = props; + const { config, badges, showSearchBar, ...searchBarProps } = props; if ((!config || config.length === 0) && (!showSearchBar || !props.data)) { return null; } + function renderBadges(): ReactElement | null { + if (!badges || badges.length === 0) return null; + return ( + + {badges.map((badge: EuiBadgeProps & { badgeText: string }, i: number) => { + const { badgeText, ...badgeProps } = badge; + return ( + + {badgeText} + + ); + })} + + ); + } + function renderItems(): ReactElement[] | null { if (!config || config.length === 0) return null; return config.map((menuItem: TopNavMenuData, i: number) => { @@ -98,7 +115,10 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { return ( <> - {renderMenu(menuClassName)} + + {renderBadges()} + {renderMenu(menuClassName)} + {renderSearchBar()} diff --git a/test/functional/apps/dashboard/copy_panel_to.ts b/test/functional/apps/dashboard/copy_panel_to.ts index bb02bfee49f006..9abdc2ceffc013 100644 --- a/test/functional/apps/dashboard/copy_panel_to.ts +++ b/test/functional/apps/dashboard/copy_panel_to.ts @@ -115,7 +115,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('confirmCopyToButton'); await PageObjects.dashboard.waitForRenderComplete(); - await PageObjects.dashboard.expectOnDashboard(`Editing New Dashboard (unsaved)`); + await PageObjects.dashboard.expectOnDashboard(`Editing New Dashboard`); }); it('it always appends new panels instead of overwriting', async () => { diff --git a/test/functional/apps/dashboard/dashboard_unsaved_state.ts b/test/functional/apps/dashboard/dashboard_unsaved_state.ts index eaf0d2f2a97df2..e6cc91880010ae 100644 --- a/test/functional/apps/dashboard/dashboard_unsaved_state.ts +++ b/test/functional/apps/dashboard/dashboard_unsaved_state.ts @@ -13,6 +13,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['dashboard', 'header', 'visualize', 'settings', 'common']); const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); const kibanaServer = getService('kibanaServer'); const dashboardAddPanel = getService('dashboardAddPanel'); @@ -29,10 +30,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.preserveCrossAppState(); await PageObjects.dashboard.loadSavedDashboard('few panels'); - await PageObjects.dashboard.switchToEditMode(); - + await PageObjects.header.waitUntilLoadingHasFinished(); originalPanelCount = await PageObjects.dashboard.getPanelCount(); + }); + it('does not show unsaved changes badge when there are no unsaved changes', async () => { + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); + + it('shows the unsaved changes badge after adding panels', async () => { + await PageObjects.dashboard.switchToEditMode(); // add an area chart by value await dashboardAddPanel.clickCreateNewLink(); await PageObjects.visualize.clickAggBasedVisualizations(); @@ -42,6 +49,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // add a metric by reference await dashboardAddPanel.addVisualization('Rendering-Test: metric'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); }); it('has correct number of panels', async () => { @@ -73,10 +83,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('resets to original panel count upon entering view mode', async () => { await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.dashboard.clickCancelOutOfEditMode(); + await PageObjects.header.waitUntilLoadingHasFinished(); const currentPanelCount = await PageObjects.dashboard.getPanelCount(); expect(currentPanelCount).to.eql(originalPanelCount); }); + it('shows unsaved changes badge in view mode if changes have not been discarded', async () => { + await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); + }); + it('retains unsaved panel count after returning to edit mode', async () => { await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.dashboard.switchToEditMode(); @@ -84,5 +99,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const currentPanelCount = await PageObjects.dashboard.getPanelCount(); expect(currentPanelCount).to.eql(unsavedPanelCount); }); + + it('does not show unsaved changes badge after saving', async () => { + await PageObjects.dashboard.saveDashboard('Unsaved State Test'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); }); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9e5e0ad057ef56..697cc18ad41d12 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -646,7 +646,6 @@ "dashboard.savedDashboard.newDashboardTitle": "新規ダッシュボード", "dashboard.stateManager.timeNotSavedWithDashboardErrorMessage": "このダッシュボードに時刻が保存されていないため、同期できません。", "dashboard.strings.dashboardEditTitle": "{title}を編集中", - "dashboard.strings.dashboardUnsavedEditTitle": "{title}を編集中(未保存)", "dashboard.topNav.cloneModal.cancelButtonLabel": "キャンセル", "dashboard.topNav.cloneModal.cloneDashboardModalHeaderTitle": "ダッシュボードのクローンを作成", "dashboard.topNav.cloneModal.confirmButtonLabel": "クローンの確認", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d230d4847df3d9..7c622613173349 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -646,7 +646,6 @@ "dashboard.savedDashboard.newDashboardTitle": "新建仪表板", "dashboard.stateManager.timeNotSavedWithDashboardErrorMessage": "时间未随此仪表板保存,因此无法同步。", "dashboard.strings.dashboardEditTitle": "正在编辑 {title}", - "dashboard.strings.dashboardUnsavedEditTitle": "正在编辑 {title}(未保存)", "dashboard.topNav.cloneModal.cancelButtonLabel": "取消", "dashboard.topNav.cloneModal.cloneDashboardModalHeaderTitle": "克隆仪表板", "dashboard.topNav.cloneModal.confirmButtonLabel": "确认克隆", From ea9f1e3dfb3fdd2e49b547fd1bcf2f0df6062b57 Mon Sep 17 00:00:00 2001 From: Kevin Qualters <56408403+kqualters-elastic@users.noreply.github.com> Date: Tue, 16 Feb 2021 13:52:43 -0500 Subject: [PATCH 12/46] [Security Solution] Format large numbers in timeline kpis and display value in a tooltip (#91263) * Format large numbers in timeline kpis and display actual value in a tooltip * Use more descriptive timelineId for additional test id Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/types/timeline/index.ts | 2 +- .../events_viewer/events_viewer.test.tsx | 2 +- .../components/flyout/header/index.test.tsx | 40 ++++++- .../components/flyout/header/kpis.tsx | 108 ++++++++++++------ 4 files changed, 110 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/security_solution/common/types/timeline/index.ts b/x-pack/plugins/security_solution/common/types/timeline/index.ts index cee8ccdea3e9e1..58e3b9824d8fdb 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/index.ts @@ -281,7 +281,7 @@ export enum TimelineId { active = 'timeline-1', casePage = 'timeline-case', test = 'test', // Reserved for testing purposes - test2 = 'test2', + alternateTest = 'alternateTest', } export const TimelineIdLiteralRt = runtimeTypes.union([ diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx index a37528fcb24d7c..3ecc17589fe084 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx @@ -201,7 +201,7 @@ describe('EventsViewer', () => { testProps = { ...testProps, // Update with a new id, to force columns back to default. - id: TimelineId.test2, + id: TimelineId.alternateTest, }; const wrapper = mount( diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx index 35dcd88b77e04e..6713be176586cc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { useKibana } from '../../../../common/lib/kibana'; import { TestProviders, mockIndexNames, mockIndexPattern } from '../../../../common/mock'; +import { TimelineId } from '../../../../../common/types/timeline'; import { useTimelineKpis } from '../../../containers/kpis'; import { FlyoutHeader } from '.'; import { useSourcererScope } from '../../../../common/containers/sourcerer'; @@ -33,6 +34,14 @@ const mockUseTimelineKpiResponse = { hostCount: 1, destinationIpCount: 1, }; + +const mockUseTimelineLargeKpiResponse = { + processCount: 1000, + userCount: 1000000, + sourceIpCount: 1000000000, + hostCount: 999, + destinationIpCount: 1, +}; const defaultMocks = { browserFields: mockBrowserFields, docValueFields: mockDocValueFields, @@ -65,7 +74,7 @@ describe('Timeline KPIs', () => { it('renders the component, labels and values succesfully', async () => { const wrapper = mount( - + ); expect(wrapper.find('[data-test-subj="siem-timeline-kpis"]').exists()).toEqual(true); @@ -87,7 +96,7 @@ describe('Timeline KPIs', () => { it('renders a loading indicator for values', async () => { const wrapper = mount( - + ); expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( @@ -103,7 +112,7 @@ describe('Timeline KPIs', () => { it('renders labels and the default empty string', async () => { const wrapper = mount( - + ); @@ -115,4 +124,29 @@ describe('Timeline KPIs', () => { ); }); }); + + describe('when the response contains numbers larger than one thousand', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineLargeKpiResponse]); + }); + it('formats the numbers correctly', async () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining('1k') + ); + expect(wrapper.find('[data-test-subj="siem-timeline-user-kpi"]').first().text()).toEqual( + expect.stringContaining('1m') + ); + expect(wrapper.find('[data-test-subj="siem-timeline-source-ip-kpi"]').first().text()).toEqual( + expect.stringContaining('1b') + ); + expect(wrapper.find('[data-test-subj="siem-timeline-host-kpi"]').first().text()).toEqual( + expect.stringContaining('999') + ); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx index 3b0a86432aa969..e487fe70fdc94c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx @@ -5,61 +5,95 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; -import { EuiStat, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { EuiStat, EuiFlexItem, EuiFlexGroup, EuiToolTip } from '@elastic/eui'; +import numeral from '@elastic/numeral'; +import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; +import { useUiSetting$ } from '../../../../common/lib/kibana'; import { TimelineKpiStrategyResponse } from '../../../../../common/search_strategy'; import { getEmptyValue } from '../../../../common/components/empty_value'; import * as i18n from './translations'; export const TimelineKPIs = React.memo( ({ kpis, isLoading }: { kpis: TimelineKpiStrategyResponse | null; isLoading: boolean }) => { + const kpiFormat = '0,0.[000]a'; + const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); + const formattedKpis = useMemo(() => { + return { + process: kpis === null ? getEmptyValue() : numeral(kpis.processCount).format(kpiFormat), + user: kpis === null ? getEmptyValue() : numeral(kpis.userCount).format(kpiFormat), + host: kpis === null ? getEmptyValue() : numeral(kpis.hostCount).format(kpiFormat), + sourceIp: kpis === null ? getEmptyValue() : numeral(kpis.sourceIpCount).format(kpiFormat), + destinationIp: + kpis === null ? getEmptyValue() : numeral(kpis.destinationIpCount).format(kpiFormat), + }; + }, [kpis]); + const formattedKpiToolTips = useMemo(() => { + return { + process: numeral(kpis?.processCount).format(defaultNumberFormat), + user: numeral(kpis?.userCount).format(defaultNumberFormat), + host: numeral(kpis?.hostCount).format(defaultNumberFormat), + sourceIp: numeral(kpis?.sourceIpCount).format(defaultNumberFormat), + destinationIp: numeral(kpis?.destinationIpCount).format(defaultNumberFormat), + }; + }, [kpis, defaultNumberFormat]); return ( - + + + - + + + - + + + - + + + - + + + ); From a99ccc27d7a9d2ad7be162c21f545e8eebf59c69 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 16 Feb 2021 13:54:54 -0500 Subject: [PATCH 13/46] [Fleet] Setup fleet server indices in Kibana without packages (#90658) --- .../plugins/fleet/common/constants/index.ts | 2 + .../server/collectors/agent_collectors.ts | 3 +- x-pack/plugins/fleet/server/plugin.ts | 17 +- .../fleet/server/services/app_context.ts | 4 + .../fleet_server/elastic_index.test.ts | 156 +++++++++++++ .../services/fleet_server/elastic_index.ts | 117 ++++++++++ .../elasticsearch/fleet_actions.json | 30 +++ .../elasticsearch/fleet_agents.json | 220 ++++++++++++++++++ .../fleet_enrollment_api_keys.json | 32 +++ .../elasticsearch/fleet_policies.json | 27 +++ .../elasticsearch/fleet_policies_leader.json | 21 ++ .../elasticsearch/fleet_servers.json | 47 ++++ .../server/services/fleet_server/index.ts | 57 +++++ .../saved_object_migrations.ts} | 36 +-- x-pack/plugins/fleet/server/services/setup.ts | 31 +-- x-pack/plugins/fleet/tsconfig.json | 3 +- 16 files changed, 729 insertions(+), 74 deletions(-) create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elastic_index.test.ts create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_agents.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_enrollment_api_keys.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies_leader.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_servers.json create mode 100644 x-pack/plugins/fleet/server/services/fleet_server/index.ts rename x-pack/plugins/fleet/server/services/{fleet_server_migration.ts => fleet_server/saved_object_migrations.ts} (84%) diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index dcddbe3539abd1..d95bc9cf736a6b 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -22,6 +22,8 @@ export * from './settings'; // setting in the future? export const SO_SEARCH_LIMIT = 10000; +export const FLEET_SERVER_INDICES_VERSION = 1; + export const FLEET_SERVER_INDICES = [ '.fleet-actions', '.fleet-agents', diff --git a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts index 8aa66c4ae5f4ac..154e78feae2832 100644 --- a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts @@ -7,7 +7,8 @@ import { ElasticsearchClient, SavedObjectsClient } from 'kibana/server'; import * as AgentService from '../services/agents'; -import { isFleetServerSetup } from '../services/fleet_server_migration'; +import { isFleetServerSetup } from '../services/fleet_server'; + export interface AgentUsage { total: number; online: number; diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index d89db7f1ac3415..d4cd39b274f052 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -83,7 +83,7 @@ import { agentCheckinState } from './services/agents/checkin/state'; import { registerFleetUsageCollector } from './collectors/register'; import { getInstallation } from './services/epm/packages'; import { makeRouterEnforcingSuperuser } from './routes/security'; -import { isFleetServerSetup } from './services/fleet_server_migration'; +import { startFleetServerSetup } from './services/fleet_server'; export interface FleetSetupDeps { licensing: LicensingPluginSetup; @@ -297,18 +297,9 @@ export class FleetPlugin licenseService.start(this.licensing$); agentCheckinState.start(); - const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled; - if (fleetServerEnabled) { - // We need licence to be initialized before using the SO service. - await this.licensing$.pipe(first()).toPromise(); - - const fleetSetup = await isFleetServerSetup(); - - if (!fleetSetup) { - this.logger?.warn( - 'Extra setup is needed to be able to use central management for agent, please visit the Fleet app in Kibana.' - ); - } + if (appContextService.getConfig()?.agents?.fleetServerEnabled) { + // Break the promise chain, the error handling is done in startFleetServerSetup + startFleetServerSetup(); } return { diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index cc4be6b31734a3..1ada940dd793c9 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -80,6 +80,10 @@ class AppContextService { return this.security; } + public hasSecurity() { + return !!this.security; + } + public getCloud() { return this.cloud; } diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.test.ts b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.test.ts new file mode 100644 index 00000000000000..96e642ba9884e8 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.test.ts @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { elasticsearchServiceMock } from 'src/core/server/mocks'; +import hash from 'object-hash'; +import { setupFleetServerIndexes } from './elastic_index'; +import ESFleetAgentIndex from './elasticsearch/fleet_agents.json'; +import ESFleetPoliciesIndex from './elasticsearch/fleet_policies.json'; +import ESFleetPoliciesLeaderIndex from './elasticsearch/fleet_policies_leader.json'; +import ESFleetServersIndex from './elasticsearch/fleet_servers.json'; +import ESFleetEnrollmentApiKeysIndex from './elasticsearch/fleet_enrollment_api_keys.json'; +import EsFleetActionsIndex from './elasticsearch/fleet_actions.json'; + +const FLEET_INDEXES_MIGRATION_HASH = { + '.fleet-actions': hash(EsFleetActionsIndex), + '.fleet-agents': hash(ESFleetAgentIndex), + '.fleet-enrollment-apy-keys': hash(ESFleetEnrollmentApiKeysIndex), + '.fleet-policies': hash(ESFleetPoliciesIndex), + '.fleet-policies-leader': hash(ESFleetPoliciesLeaderIndex), + '.fleet-servers': hash(ESFleetServersIndex), +}; + +describe('setupFleetServerIndexes ', () => { + it('should create all the indices and aliases if nothings exists', async () => { + const esMock = elasticsearchServiceMock.createInternalClient(); + await setupFleetServerIndexes(esMock); + + const indexesCreated = esMock.indices.create.mock.calls.map((call) => call[0].index).sort(); + expect(indexesCreated).toEqual([ + '.fleet-actions_1', + '.fleet-agents_1', + '.fleet-enrollment-api-keys_1', + '.fleet-policies-leader_1', + '.fleet-policies_1', + '.fleet-servers_1', + ]); + const aliasesCreated = esMock.indices.updateAliases.mock.calls + .map((call) => (call[0].body as any)?.actions[0].add.alias) + .sort(); + + expect(aliasesCreated).toEqual([ + '.fleet-actions', + '.fleet-agents', + '.fleet-enrollment-api-keys', + '.fleet-policies', + '.fleet-policies-leader', + '.fleet-servers', + ]); + }); + + it('should not create any indices and create aliases if indices exists but not the aliases', async () => { + const esMock = elasticsearchServiceMock.createInternalClient(); + // @ts-expect-error + esMock.indices.exists.mockResolvedValue({ body: true }); + // @ts-expect-error + esMock.indices.getMapping.mockImplementation((params: { index: string }) => { + return { + body: { + [params.index]: { + mappings: { + _meta: { + // @ts-expect-error + migrationHash: FLEET_INDEXES_MIGRATION_HASH[params.index.replace(/_1$/, '')], + }, + }, + }, + }, + }; + }); + + await setupFleetServerIndexes(esMock); + + expect(esMock.indices.create).not.toBeCalled(); + const aliasesCreated = esMock.indices.updateAliases.mock.calls + .map((call) => (call[0].body as any)?.actions[0].add.alias) + .sort(); + + expect(aliasesCreated).toEqual([ + '.fleet-actions', + '.fleet-agents', + '.fleet-enrollment-api-keys', + '.fleet-policies', + '.fleet-policies-leader', + '.fleet-servers', + ]); + }); + + it('should put new indices mapping if the mapping has been updated ', async () => { + const esMock = elasticsearchServiceMock.createInternalClient(); + // @ts-expect-error + esMock.indices.exists.mockResolvedValue({ body: true }); + // @ts-expect-error + esMock.indices.getMapping.mockImplementation((params: { index: string }) => { + return { + body: { + [params.index]: { + mappings: { + _meta: { + migrationHash: 'NOT_VALID_HASH', + }, + }, + }, + }, + }; + }); + + await setupFleetServerIndexes(esMock); + + expect(esMock.indices.create).not.toBeCalled(); + const indexesMappingUpdated = esMock.indices.putMapping.mock.calls + .map((call) => call[0].index) + .sort(); + + expect(indexesMappingUpdated).toEqual([ + '.fleet-actions_1', + '.fleet-agents_1', + '.fleet-enrollment-api-keys_1', + '.fleet-policies-leader_1', + '.fleet-policies_1', + '.fleet-servers_1', + ]); + }); + + it('should not create any indices or aliases if indices and aliases already exists', async () => { + const esMock = elasticsearchServiceMock.createInternalClient(); + + // @ts-expect-error + esMock.indices.exists.mockResolvedValue({ body: true }); + // @ts-expect-error + esMock.indices.getMapping.mockImplementation((params: { index: string }) => { + return { + body: { + [params.index]: { + mappings: { + _meta: { + // @ts-expect-error + migrationHash: FLEET_INDEXES_MIGRATION_HASH[params.index.replace(/_1$/, '')], + }, + }, + }, + }, + }; + }); + // @ts-expect-error + esMock.indices.existsAlias.mockResolvedValue({ body: true }); + + await setupFleetServerIndexes(esMock); + + expect(esMock.indices.create).not.toBeCalled(); + expect(esMock.indices.updateAliases).not.toBeCalled(); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts new file mode 100644 index 00000000000000..15672be756fe2d --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from 'kibana/server'; +import hash from 'object-hash'; + +import { FLEET_SERVER_INDICES, FLEET_SERVER_INDICES_VERSION } from '../../../common'; +import { appContextService } from '../app_context'; +import ESFleetAgentIndex from './elasticsearch/fleet_agents.json'; +import ESFleetPoliciesIndex from './elasticsearch/fleet_policies.json'; +import ESFleetPoliciesLeaderIndex from './elasticsearch/fleet_policies_leader.json'; +import ESFleetServersIndex from './elasticsearch/fleet_servers.json'; +import ESFleetEnrollmentApiKeysIndex from './elasticsearch/fleet_enrollment_api_keys.json'; +import EsFleetActionsIndex from './elasticsearch/fleet_actions.json'; + +const FLEET_INDEXES: Array<[typeof FLEET_SERVER_INDICES[number], any]> = [ + ['.fleet-actions', EsFleetActionsIndex], + ['.fleet-agents', ESFleetAgentIndex], + ['.fleet-enrollment-api-keys', ESFleetEnrollmentApiKeysIndex], + ['.fleet-policies', ESFleetPoliciesIndex], + ['.fleet-policies-leader', ESFleetPoliciesLeaderIndex], + ['.fleet-servers', ESFleetServersIndex], +]; + +export async function setupFleetServerIndexes( + esClient = appContextService.getInternalUserESClient() +) { + await Promise.all( + FLEET_INDEXES.map(async ([indexAlias, indexData]) => { + const index = `${indexAlias}_${FLEET_SERVER_INDICES_VERSION}`; + await createOrUpdateIndex(esClient, index, indexData); + await createAliasIfDoNotExists(esClient, indexAlias, index); + }) + ); +} + +export async function createAliasIfDoNotExists( + esClient: ElasticsearchClient, + alias: string, + index: string +) { + const { body: exists } = await esClient.indices.existsAlias({ + name: alias, + }); + + if (exists === true) { + return; + } + await esClient.indices.updateAliases({ + body: { + actions: [ + { + add: { index, alias }, + }, + ], + }, + }); +} + +async function createOrUpdateIndex( + esClient: ElasticsearchClient, + indexName: string, + indexData: any +) { + const resExists = await esClient.indices.exists({ + index: indexName, + }); + + // Support non destructive migration only (adding new field) + if (resExists.body === true) { + return updateIndex(esClient, indexName, indexData); + } + + return createIndex(esClient, indexName, indexData); +} + +async function updateIndex(esClient: ElasticsearchClient, indexName: string, indexData: any) { + const res = await esClient.indices.getMapping({ + index: indexName, + }); + + const migrationHash = hash(indexData); + if (res.body[indexName].mappings?._meta?.migrationHash !== migrationHash) { + await esClient.indices.putMapping({ + index: indexName, + body: Object.assign({ + ...indexData.mappings, + _meta: { ...(indexData.mappings._meta || {}), migrationHash }, + }), + }); + } +} + +async function createIndex(esClient: ElasticsearchClient, indexName: string, indexData: any) { + try { + const migrationHash = hash(indexData); + await esClient.indices.create({ + index: indexName, + body: { + ...indexData, + mappings: Object.assign({ + ...indexData.mappings, + _meta: { ...(indexData.mappings._meta || {}), migrationHash }, + }), + }, + }); + } catch (err) { + // Swallow already exists errors as concurent Kibana can try to create that indice + if (err?.body?.error?.type !== 'resource_already_exists_exception') { + throw err; + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json new file mode 100644 index 00000000000000..3008ee74ab50c8 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json @@ -0,0 +1,30 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "action_id": { + "type": "keyword" + }, + "agents": { + "type": "keyword" + }, + "data": { + "enabled": false, + "type": "object" + }, + "expiration": { + "type": "date" + }, + "input_type": { + "type": "keyword" + }, + "@timestamp": { + "type": "date" + }, + "type": { + "type": "keyword" + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_agents.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_agents.json new file mode 100644 index 00000000000000..9937e9ad66e56f --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_agents.json @@ -0,0 +1,220 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "access_api_key_id": { + "type": "keyword" + }, + "action_seq_no": { + "type": "integer" + }, + "active": { + "type": "boolean" + }, + "agent": { + "properties": { + "id": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "default_api_key": { + "type": "keyword" + }, + "default_api_key_id": { + "type": "keyword" + }, + "enrolled_at": { + "type": "date" + }, + "last_checkin": { + "type": "date" + }, + "last_checkin_status": { + "type": "keyword" + }, + "last_updated": { + "type": "date" + }, + "local_metadata": { + "properties": { + "elastic": { + "properties": { + "agent": { + "properties": { + "build": { + "properties": { + "original": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "keyword" + }, + "log_level": { + "type": "keyword" + }, + "snapshot": { + "type": "boolean" + }, + "upgradeable": { + "type": "boolean" + }, + "version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 16 + } + } + } + } + } + } + }, + "host": { + "properties": { + "architecture": { + "type": "keyword" + }, + "hostname": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "keyword" + }, + "ip": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 64 + } + } + }, + "mac": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 17 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "os": { + "properties": { + "family": { + "type": "keyword" + }, + "full": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 128 + } + } + }, + "kernel": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 128 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "platform": { + "type": "keyword" + }, + "version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 32 + } + } + } + } + } + } + }, + "packages": { + "type": "keyword" + }, + "policy_coordinator_idx": { + "type": "integer" + }, + "policy_id": { + "type": "keyword" + }, + "policy_revision_idx": { + "type": "integer" + }, + "shared_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "unenrolled_at": { + "type": "date" + }, + "unenrollment_started_at": { + "type": "date" + }, + "updated_at": { + "type": "date" + }, + "upgrade_started_at": { + "type": "date" + }, + "upgraded_at": { + "type": "date" + }, + "user_provided_metadata": { + "type": "object", + "enabled": false + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_enrollment_api_keys.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_enrollment_api_keys.json new file mode 100644 index 00000000000000..fc3898aff55c66 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_enrollment_api_keys.json @@ -0,0 +1,32 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "active": { + "type": "boolean" + }, + "api_key": { + "type": "keyword" + }, + "api_key_id": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "expire_at": { + "type": "date" + }, + "name": { + "type": "keyword" + }, + "policy_id": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies.json new file mode 100644 index 00000000000000..50078aaa5ea988 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies.json @@ -0,0 +1,27 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "coordinator_idx": { + "type": "integer" + }, + "data": { + "enabled": false, + "type": "object" + }, + "default_fleet_server": { + "type": "boolean" + }, + "policy_id": { + "type": "keyword" + }, + "revision_idx": { + "type": "integer" + }, + "@timestamp": { + "type": "date" + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies_leader.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies_leader.json new file mode 100644 index 00000000000000..ad3dfe64df57c3 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_policies_leader.json @@ -0,0 +1,21 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "server": { + "properties": { + "id": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "@timestamp": { + "type": "date" + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_servers.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_servers.json new file mode 100644 index 00000000000000..9ee68735d5b6fc --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_servers.json @@ -0,0 +1,47 @@ +{ + "settings": {}, + "mappings": { + "dynamic": false, + "properties": { + "agent": { + "properties": { + "id": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "host": { + "properties": { + "architecture": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "ip": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "server": { + "properties": { + "id": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "@timestamp": { + "type": "date" + } + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/index.ts b/x-pack/plugins/fleet/server/services/fleet_server/index.ts new file mode 100644 index 00000000000000..0b54dc0d168b4f --- /dev/null +++ b/x-pack/plugins/fleet/server/services/fleet_server/index.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { first } from 'rxjs/operators'; +import { appContextService } from '../app_context'; +import { licenseService } from '../license'; +import { setupFleetServerIndexes } from './elastic_index'; +import { runFleetServerMigration } from './saved_object_migrations'; + +let _isFleetServerSetup = false; +let _isPending = false; +let _status: Promise | undefined; +let _onResolve: (arg?: any) => void; + +export function isFleetServerSetup() { + return _isFleetServerSetup; +} + +export function awaitIfFleetServerSetupPending() { + if (!_isPending) { + return; + } + + return _status; +} + +export async function startFleetServerSetup() { + _isPending = true; + _status = new Promise((resolve) => { + _onResolve = resolve; + }); + const logger = appContextService.getLogger(); + if (!appContextService.hasSecurity()) { + // Fleet will not work if security is not enabled + logger?.warn('Fleet requires the security plugin to be enabled.'); + return; + } + + try { + // We need licence to be initialized before using the SO service. + await licenseService.getLicenseInformation$()?.pipe(first())?.toPromise(); + await setupFleetServerIndexes(); + await runFleetServerMigration(); + _isFleetServerSetup = true; + } catch (err) { + logger?.error('Setup for central management of agents failed.'); + logger?.error(err); + } + _isPending = false; + if (_onResolve) { + _onResolve(); + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server_migration.ts b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts similarity index 84% rename from x-pack/plugins/fleet/server/services/fleet_server_migration.ts rename to x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts index 170bec54983c0e..84e6b06e59844f 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server_migration.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts @@ -17,38 +17,12 @@ import { AgentSOAttributes, FleetServerAgent, SO_SEARCH_LIMIT, - FLEET_SERVER_PACKAGE, - FLEET_SERVER_INDICES, -} from '../../common'; -import { listEnrollmentApiKeys, getEnrollmentAPIKey } from './api_keys/enrollment_api_key_so'; -import { appContextService } from './app_context'; -import { getInstallation } from './epm/packages'; - -import { isAgentsSetup } from './agents'; -import { agentPolicyService } from './agent_policy'; - -export async function isFleetServerSetup() { - const pkgInstall = await getInstallation({ - savedObjectsClient: getInternalUserSOClient(), - pkgName: FLEET_SERVER_PACKAGE, - }); - - if (!pkgInstall) { - return false; - } +} from '../../../common'; +import { listEnrollmentApiKeys, getEnrollmentAPIKey } from '../api_keys/enrollment_api_key_so'; +import { appContextService } from '../app_context'; - const esClient = appContextService.getInternalUserESClient(); - const exists = await Promise.all( - FLEET_SERVER_INDICES.map(async (index) => { - const res = await esClient.indices.exists({ - index, - }); - return res.statusCode !== 404; - }) - ); - - return exists.every((exist) => exist === true); -} +import { isAgentsSetup } from '../agents'; +import { agentPolicyService } from '../agent_policy'; export async function runFleetServerMigration() { // If Agents are not setup skip as there is nothing to migrate diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 94c3c606f9f8f0..2a3166e9dc7296 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -23,7 +23,6 @@ import { Output, DEFAULT_AGENT_POLICIES_PACKAGES, FLEET_SERVER_PACKAGE, - FLEET_SERVER_INDICES, } from '../../common'; import { SO_SEARCH_LIMIT } from '../constants'; import { getPackageInfo } from './epm/packages'; @@ -34,7 +33,7 @@ import { awaitIfPending } from './setup_utils'; import { createDefaultSettings } from './settings'; import { ensureAgentActionPolicyChangeExists } from './agents'; import { appContextService } from './app_context'; -import { runFleetServerMigration } from './fleet_server_migration'; +import { awaitIfFleetServerSetupPending } from './fleet_server'; const FLEET_ENROLL_USERNAME = 'fleet_enroll'; const FLEET_ENROLL_ROLE = 'fleet_enroll'; @@ -88,24 +87,15 @@ async function createSetupSideEffects( // By moving this outside of the Promise.all, the upgrade will occur first, and then we'll attempt to reinstall any // packages that are stuck in the installing state. await ensurePackagesCompletedInstall(soClient, callCluster); + if (isFleetServerEnabled) { - await ensureInstalledPackage({ - savedObjectsClient: soClient, - pkgName: FLEET_SERVER_PACKAGE, - callCluster, - }); - await ensureFleetServerIndicesCreated(esClient); - await runFleetServerMigration(); - } + await awaitIfFleetServerSetupPending(); - if (appContextService.getConfig()?.agents?.fleetServerEnabled) { const fleetServerPackage = await ensureInstalledPackage({ savedObjectsClient: soClient, pkgName: FLEET_SERVER_PACKAGE, callCluster, }); - await ensureFleetServerIndicesCreated(esClient); - await runFleetServerMigration(); if (defaultFleetServerPolicyCreated) { await addPackageToAgentPolicy( @@ -187,21 +177,6 @@ async function updateFleetRoleIfExists(callCluster: CallESAsCurrentUser) { return putFleetRole(callCluster); } -async function ensureFleetServerIndicesCreated(esClient: ElasticsearchClient) { - await Promise.all( - FLEET_SERVER_INDICES.map(async (index) => { - const res = await esClient.indices.exists({ - index, - }); - if (res.statusCode === 404) { - await esClient.indices.create({ - index, - }); - } - }) - ); -} - async function putFleetRole(callCluster: CallESAsCurrentUser) { return callCluster('transport.request', { method: 'PUT', diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 152fb2e132f626..e6dc206912c4bd 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -5,13 +5,14 @@ "outDir": "./target/types", "emitDeclarationOnly": true, "declaration": true, - "declarationMap": true + "declarationMap": true, }, "include": [ // add all the folders containg files to be compiled "common/**/*", "public/**/*", "server/**/*", + "server/**/*.json", "scripts/**/*", "package.json", "../../typings/**/*" From db6cd8665c8992b0647624a07fdd4b29cdc6c24b Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 16 Feb 2021 13:21:16 -0600 Subject: [PATCH 14/46] [CI] Detect architecture when determining node download url (#91497) Currently CI is setup to always download the x64 Node.js architecture. When runing builds on ARM machines we'll want to make sure the architecture matches the machine. --- src/dev/ci_setup/setup_env.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dev/ci_setup/setup_env.sh b/src/dev/ci_setup/setup_env.sh index 2deafaaf35a94d..b9898960135fcd 100644 --- a/src/dev/ci_setup/setup_env.sh +++ b/src/dev/ci_setup/setup_env.sh @@ -56,7 +56,13 @@ export WORKSPACE="${WORKSPACE:-$PARENT_DIR}" nodeVersion="$(cat "$dir/.node-version")" nodeDir="$cacheDir/node/$nodeVersion" nodeBin="$nodeDir/bin" -classifier="x64.tar.gz" +hostArch="$(command uname -m)" +case "${hostArch}" in + x86_64 | amd64) nodeArch="x64" ;; + aarch64) nodeArch="arm64" ;; + *) nodeArch="${hostArch}" ;; +esac +classifier="$nodeArch.tar.gz" UNAME=$(uname) OS="linux" From 312351c52c1acc7707813e6b8547df4f379b0cba Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Tue, 16 Feb 2021 20:27:25 +0100 Subject: [PATCH 15/46] Unify Kibana & Elasticsearch logging config keys (#90764) * align logging config with ES. rename kind to type. * rename file "path" to "fileName" * rename logger "context" to "name" * update audit log docs and tests * update docs * fix integration tests * update deprecations for audit appender * add tests for audit logging deprecations * fix eslint problem Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...re-server.loggingservicesetup.configure.md | 2 +- docs/settings/security-settings.asciidoc | 22 ++-- ...gacy_object_to_config_adapter.test.ts.snap | 4 +- .../legacy/legacy_object_to_config_adapter.ts | 2 +- .../core_usage_data_service.ts | 2 +- .../http/integration_tests/logging.test.ts | 12 +- .../legacy/integration_tests/logging.test.ts | 6 +- .../logging/appenders/legacy_appender.test.ts | 6 +- .../logging/appenders/legacy_appender.ts | 4 +- src/core/server/logging/README.md | 120 +++++++++--------- .../__snapshots__/logging_system.test.ts.snap | 2 +- .../logging/appenders/appenders.test.mocks.ts | 2 +- .../logging/appenders/appenders.test.ts | 50 ++++---- .../server/logging/appenders/appenders.ts | 4 +- .../console/console_appender.test.ts | 12 +- .../appenders/console/console_appender.ts | 4 +- .../file/file_appender.test.mocks.ts | 2 +- .../appenders/file/file_appender.test.ts | 18 +-- .../logging/appenders/file/file_appender.ts | 8 +- .../appenders/rolling_file/policies/index.ts | 4 +- .../size_limit/size_limit_policy.test.ts | 2 +- .../policies/size_limit/size_limit_policy.ts | 4 +- .../time_interval_policy.test.ts | 2 +- .../time_interval/time_interval_policy.ts | 4 +- .../rolling_file_appender.test.ts | 12 +- .../rolling_file/rolling_file_appender.ts | 10 +- .../rolling_file/strategies/index.ts | 2 +- .../numeric/numeric_strategy.test.ts | 4 +- .../strategies/numeric/numeric_strategy.ts | 14 +- .../logging/integration_tests/logging.test.ts | 34 ++--- .../rolling_file_appender.test.ts | 32 ++--- .../logging/layouts/json_layout.test.ts | 2 +- .../server/logging/layouts/json_layout.ts | 4 +- .../server/logging/layouts/layouts.test.ts | 18 +-- src/core/server/logging/layouts/layouts.ts | 2 +- .../logging/layouts/pattern_layout.test.ts | 12 +- .../server/logging/layouts/pattern_layout.ts | 4 +- .../server/logging/logging_config.test.ts | 84 ++++++------ src/core/server/logging/logging_config.ts | 23 ++-- .../server/logging/logging_service.test.ts | 10 +- src/core/server/logging/logging_service.ts | 2 +- .../server/logging/logging_system.test.ts | 62 ++++----- src/core/server/logging/logging_system.ts | 6 +- .../integration_tests/migration.test.ts | 8 +- .../migration_7.7.2_xpack_100k.test.ts | 8 +- .../server/audit/audit_service.test.ts | 26 ++-- .../security/server/audit/audit_service.ts | 6 +- x-pack/plugins/security/server/config.test.ts | 16 +-- .../server/config_deprecations.test.ts | 111 ++++++++++++++++ .../security/server/config_deprecations.ts | 7 + .../security_api_integration/audit.config.ts | 6 +- 51 files changed, 468 insertions(+), 355 deletions(-) diff --git a/docs/development/core/server/kibana-plugin-core-server.loggingservicesetup.configure.md b/docs/development/core/server/kibana-plugin-core-server.loggingservicesetup.configure.md index 04a3cf9aff6448..52ab5f1098457c 100644 --- a/docs/development/core/server/kibana-plugin-core-server.loggingservicesetup.configure.md +++ b/docs/development/core/server/kibana-plugin-core-server.loggingservicesetup.configure.md @@ -34,7 +34,7 @@ Customize the configuration for the plugins.data.search context. core.logging.configure( of({ appenders: new Map(), - loggers: [{ context: 'search', appenders: ['default'] }] + loggers: [{ name: 'search', appenders: ['default'] }] }) ) diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index afcb7bc21b66b6..7ffb6b66f5a2b4 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -356,26 +356,26 @@ To enable the <>, specify wh [source,yaml] ---------------------------------------- xpack.security.audit.appender: - kind: rolling-file - path: ./audit.log + type: rolling-file + fileName: ./audit.log policy: - kind: time-interval + type: time-interval interval: 24h <1> strategy: - kind: numeric + type: numeric max: 10 <2> layout: - kind: json + type: json ---------------------------------------- <1> Rotates log files every 24 hours. <2> Keeps maximum of 10 log files before deleting older ones. -| `xpack.security.audit.appender.kind` +| `xpack.security.audit.appender.type` | Required. Specifies where audit logs should be written to. Allowed values are `console`, `file`, or `rolling-file`. Refer to <> and <> for appender specific settings. -| `xpack.security.audit.appender.layout.kind` +| `xpack.security.audit.appender.layout.type` | Required. Specifies how audit logs should be formatted. Allowed values are `json` or `pattern`. Refer to <> for layout specific settings. @@ -396,7 +396,7 @@ The `file` appender writes to a file and can be configured using the following s [cols="2*<"] |====== -| `xpack.security.audit.appender.path` +| `xpack.security.audit.appender.fileName` | Required. Full file path the log file should be written to. |====== @@ -408,14 +408,14 @@ The `rolling-file` appender writes to a file and rotates it using a rolling stra [cols="2*<"] |====== -| `xpack.security.audit.appender.path` +| `xpack.security.audit.appender.fileName` | Required. Full file path the log file should be written to. -| `xpack.security.audit.appender.policy.kind` +| `xpack.security.audit.appender.policy.type` | Specifies when a rollover should occur. Allowed values are `size-limit` and `time-interval`. *Default:* `time-interval`. Refer to <> and <> for policy specific settings. -| `xpack.security.audit.appender.strategy.kind` +| `xpack.security.audit.appender.strategy.type` | Specifies how the rollover should occur. Only allowed value is currently `numeric`. *Default:* `numeric` Refer to <> for strategy specific settings. diff --git a/packages/kbn-config/src/legacy/__snapshots__/legacy_object_to_config_adapter.test.ts.snap b/packages/kbn-config/src/legacy/__snapshots__/legacy_object_to_config_adapter.test.ts.snap index 6351a227ff90b8..2801e0a0688cc6 100644 --- a/packages/kbn-config/src/legacy/__snapshots__/legacy_object_to_config_adapter.test.ts.snap +++ b/packages/kbn-config/src/legacy/__snapshots__/legacy_object_to_config_adapter.test.ts.snap @@ -68,10 +68,10 @@ exports[`#get correctly handles silent logging config. 1`] = ` Object { "appenders": Object { "default": Object { - "kind": "legacy-appender", "legacyLoggingConfig": Object { "silent": true, }, + "type": "legacy-appender", }, }, "loggers": undefined, @@ -85,12 +85,12 @@ exports[`#get correctly handles verbose file logging config with json format. 1` Object { "appenders": Object { "default": Object { - "kind": "legacy-appender", "legacyLoggingConfig": Object { "dest": "/some/path.log", "json": true, "verbose": true, }, + "type": "legacy-appender", }, }, "loggers": undefined, diff --git a/packages/kbn-config/src/legacy/legacy_object_to_config_adapter.ts b/packages/kbn-config/src/legacy/legacy_object_to_config_adapter.ts index 4d877a26b76418..8ec26ff1f8e71c 100644 --- a/packages/kbn-config/src/legacy/legacy_object_to_config_adapter.ts +++ b/packages/kbn-config/src/legacy/legacy_object_to_config_adapter.ts @@ -44,7 +44,7 @@ export class LegacyObjectToConfigAdapter extends ObjectToConfigAdapter { const loggingConfig = { appenders: { ...appenders, - default: { kind: 'legacy-appender', legacyLoggingConfig }, + default: { type: 'legacy-appender', legacyLoggingConfig }, }, root: { level: 'info', ...root }, loggers, diff --git a/src/core/server/core_usage_data/core_usage_data_service.ts b/src/core/server/core_usage_data/core_usage_data_service.ts index bd5f23b1c09bc7..e57d8d90a02dcc 100644 --- a/src/core/server/core_usage_data/core_usage_data_service.ts +++ b/src/core/server/core_usage_data/core_usage_data_service.ts @@ -226,7 +226,7 @@ export class CoreUsageDataService implements CoreService acc.add(a.kind), new Set()) + .reduce((acc, a) => acc.add(a.type), new Set()) .values() ), loggersConfiguredCount: this.loggingConfig?.loggers.length ?? 0, diff --git a/src/core/server/http/integration_tests/logging.test.ts b/src/core/server/http/integration_tests/logging.test.ts index ba265c1ff61bc2..fcf2cd2ba3372d 100644 --- a/src/core/server/http/integration_tests/logging.test.ts +++ b/src/core/server/http/integration_tests/logging.test.ts @@ -50,16 +50,16 @@ describe('request logging', () => { silent: true, appenders: { 'test-console': { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', pattern: '%level|%logger|%message|%meta', }, }, }, loggers: [ { - context: 'http.server.response', + name: 'http.server.response', appenders: ['test-console'], level: 'debug', }, @@ -96,16 +96,16 @@ describe('request logging', () => { silent: true, appenders: { 'test-console': { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', pattern: '%level|%logger|%message|%meta', }, }, }, loggers: [ { - context: 'http.server.response', + name: 'http.server.response', appenders: ['test-console'], level: 'debug', }, diff --git a/src/core/server/legacy/integration_tests/logging.test.ts b/src/core/server/legacy/integration_tests/logging.test.ts index 321eb81708f1e7..88c45962ce4a68 100644 --- a/src/core/server/legacy/integration_tests/logging.test.ts +++ b/src/core/server/legacy/integration_tests/logging.test.ts @@ -29,16 +29,16 @@ function createRoot(legacyLoggingConfig: LegacyLoggingConfig = {}) { // platform config appenders: { 'test-console': { - kind: 'console', + type: 'console', layout: { highlight: false, - kind: 'pattern', + type: 'pattern', }, }, }, loggers: [ { - context: 'test-file', + name: 'test-file', appenders: ['test-console'], level: 'info', }, diff --git a/src/core/server/legacy/logging/appenders/legacy_appender.test.ts b/src/core/server/legacy/logging/appenders/legacy_appender.test.ts index 1b76b6748a5bb6..9213403d72d07a 100644 --- a/src/core/server/legacy/logging/appenders/legacy_appender.test.ts +++ b/src/core/server/legacy/logging/appenders/legacy_appender.test.ts @@ -16,13 +16,13 @@ afterEach(() => (LegacyLoggingServer as any).mockClear()); test('`configSchema` creates correct schema.', () => { const appenderSchema = LegacyAppender.configSchema; - const validConfig = { kind: 'legacy-appender', legacyLoggingConfig: { verbose: true } }; + const validConfig = { type: 'legacy-appender', legacyLoggingConfig: { verbose: true } }; expect(appenderSchema.validate(validConfig)).toEqual({ - kind: 'legacy-appender', + type: 'legacy-appender', legacyLoggingConfig: { verbose: true }, }); - const wrongConfig = { kind: 'not-legacy-appender' }; + const wrongConfig = { type: 'not-legacy-appender' }; expect(() => appenderSchema.validate(wrongConfig)).toThrow(); }); diff --git a/src/core/server/legacy/logging/appenders/legacy_appender.ts b/src/core/server/legacy/logging/appenders/legacy_appender.ts index 83e43999eeebf1..a89441a5671b55 100644 --- a/src/core/server/legacy/logging/appenders/legacy_appender.ts +++ b/src/core/server/legacy/logging/appenders/legacy_appender.ts @@ -12,7 +12,7 @@ import { DisposableAppender, LogRecord } from '@kbn/logging'; import { LegacyVars } from '../../types'; export interface LegacyAppenderConfig { - kind: 'legacy-appender'; + type: 'legacy-appender'; legacyLoggingConfig?: any; } @@ -22,7 +22,7 @@ export interface LegacyAppenderConfig { */ export class LegacyAppender implements DisposableAppender { public static configSchema = schema.object({ - kind: schema.literal('legacy-appender'), + type: schema.literal('legacy-appender'), legacyLoggingConfig: schema.any(), }); diff --git a/src/core/server/logging/README.md b/src/core/server/logging/README.md index 9e3da1f3e0d715..385d1fd91a5d75 100644 --- a/src/core/server/logging/README.md +++ b/src/core/server/logging/README.md @@ -24,7 +24,7 @@ Kibana logging system has three main components: _loggers_, _appenders_ and _lay messages according to message type and level, and to control how these messages are formatted and where the final logs will be displayed or stored. -__Loggers__ define what logging settings should be applied at the particular context. +__Loggers__ define what logging settings should be applied at the particular context name. __Appenders__ define where log messages are displayed (eg. stdout or console) and stored (eg. file on the disk). @@ -33,17 +33,17 @@ __Layouts__ define how log messages are formatted and what type of information t ## Logger hierarchy -Every logger has its unique name or context that follows hierarchical naming rule. The logger is considered to be an +Every logger has its unique context name that follows hierarchical naming rule. The logger is considered to be an ancestor of another logger if its name followed by a `.` is a prefix of the descendant logger name. For example logger -with `a.b` context is an ancestor of logger with `a.b.c` context. All top-level loggers are descendants of special -logger with `root` context that resides at the top of the logger hierarchy. This logger always exists and +with `a.b` context name is an ancestor of logger with `a.b.c` context name. All top-level loggers are descendants of special +logger with `root` context name that resides at the top of the logger hierarchy. This logger always exists and fully configured. -Developer can configure _log level_ and _appenders_ that should be used within particular context. If logger configuration +Developer can configure _log level_ and _appenders_ that should be used within particular context name. If logger configuration specifies only _log level_ then _appenders_ configuration will be inherited from the ancestor logger. __Note:__ in the current implementation log messages are only forwarded to appenders configured for a particular logger -context or to appenders of the closest ancestor if current logger doesn't have any appenders configured. That means that +context name or to appenders of the closest ancestor if current logger doesn't have any appenders configured. That means that we __don't support__ so called _appender additivity_ when log messages are forwarded to _every_ distinct appender within ancestor chain including `root`. @@ -55,7 +55,7 @@ A log record is being logged by the logger if its level is higher than or equal the log record is ignored. The _all_ and _off_ levels can be used only in configuration and are just handy shortcuts that allow developer to log every -log record or disable logging entirely for the specific context. +log record or disable logging entirely for the specific context name. ## Layouts @@ -129,7 +129,7 @@ Example of `%date` output: Outputs the process ID. ### JSON layout -With `json` layout log messages will be formatted as JSON strings that include timestamp, log level, context, message +With `json` layout log messages will be formatted as JSON strings that include timestamp, log level, context name, message text and any other metadata that may be associated with the log message itself. ## Appenders @@ -153,15 +153,15 @@ This policy will rotate the file when it reaches a predetermined size. logging: appenders: rolling-file: - kind: rolling-file - path: /var/logs/kibana.log + type: rolling-file + fileName: /var/logs/kibana.log policy: - kind: size-limit + type: size-limit size: 50mb strategy: //... layout: - kind: pattern + type: pattern ``` The options are: @@ -180,16 +180,16 @@ This policy will rotate the file every given interval of time. logging: appenders: rolling-file: - kind: rolling-file - path: /var/logs/kibana.log + type: rolling-file + fileName: /var/logs/kibana.log policy: - kind: time-interval + type: time-interval interval: 10s modulate: true strategy: //... layout: - kind: pattern + type: pattern ``` The options are: @@ -225,16 +225,16 @@ and will retains a fixed amount of rolled files. logging: appenders: rolling-file: - kind: rolling-file - path: /var/logs/kibana.log + type: rolling-file + fileName: /var/logs/kibana.log policy: // ... strategy: - kind: numeric + type: numeric pattern: '-%i' max: 2 layout: - kind: pattern + type: pattern ``` For example, with this configuration: @@ -253,7 +253,7 @@ The options are: The suffix to append to the file path when rolling. Must include `%i`, as this is the value that will be converted to the file index. -for example, with `path: /var/logs/kibana.log` and `pattern: '-%i'`, the created rolling files +for example, with `fileName: /var/logs/kibana.log` and `pattern: '-%i'`, the created rolling files will be `/var/logs/kibana-1.log`, `/var/logs/kibana-2.log`, and so on. The default value is `-%i` @@ -278,49 +278,49 @@ Here is the configuration example that can be used to configure _loggers_, _appe logging: appenders: console: - kind: console + type: console layout: - kind: pattern + type: pattern highlight: true file: - kind: file - path: /var/log/kibana.log + type: file + fileName: /var/log/kibana.log layout: - kind: pattern + type: pattern custom: - kind: console + type: console layout: - kind: pattern + type: pattern pattern: "[%date][%level] %message" json-file-appender: - kind: file - path: /var/log/kibana-json.log + type: file + fileName: /var/log/kibana-json.log root: appenders: [console, file] level: error loggers: - - context: plugins + - name: plugins appenders: [custom] level: warn - - context: plugins.myPlugin + - name: plugins.myPlugin level: info - - context: server + - name: server level: fatal - - context: optimize + - name: optimize appenders: [console] - - context: telemetry + - name: telemetry level: all appenders: [json-file-appender] - - context: metrics.ops + - name: metrics.ops level: debug appenders: [console] ``` Here is what we get with the config above: -| Context | Appenders | Level | +| Context name | Appenders | Level | | ---------------- |:------------------------:| -----:| | root | console, file | error | | plugins | custom | warn | @@ -331,7 +331,7 @@ Here is what we get with the config above: | metrics.ops | console | debug | -The `root` logger has a dedicated configuration node since this context is special and should always exist. By +The `root` logger has a dedicated configuration node since this context name is special and should always exist. By default `root` is configured with `info` level and `default` appender that is also always available. This is the configuration that all custom loggers will use unless they're re-configured explicitly. @@ -391,7 +391,7 @@ The message contains some high-level information, and the corresponding log meta ## Usage -Usage is very straightforward, one should just get a logger for a specific context and use it to log messages with +Usage is very straightforward, one should just get a logger for a specific context name and use it to log messages with different log level. ```typescript @@ -409,7 +409,7 @@ loggerWithNestedContext.trace('Message with `trace` log level.'); loggerWithNestedContext.debug('Message with `debug` log level.'); ``` -And assuming logger for `server` context with `console` appender and `trace` level was used, console output will look like this: +And assuming logger for `server` name with `console` appender and `trace` level was used, console output will look like this: ```bash [2017-07-25T11:54:41.639-07:00][TRACE][server] Message with `trace` log level. [2017-07-25T11:54:41.639-07:00][DEBUG][server] Message with `debug` log level. @@ -422,7 +422,7 @@ And assuming logger for `server` context with `console` appender and `trace` lev [2017-07-25T11:54:41.639-07:00][DEBUG][server.http] Message with `debug` log level. ``` -The log will be less verbose with `warn` level for the `server` context: +The log will be less verbose with `warn` level for the `server` context name: ```bash [2017-07-25T11:54:41.639-07:00][WARN ][server] Message with `warn` log level. [2017-07-25T11:54:41.639-07:00][ERROR][server] Message with `error` log level. @@ -433,7 +433,7 @@ The log will be less verbose with `warn` level for the `server` context: Compatibility with the legacy logging system is assured until the end of the `v7` version. All log messages handled by `root` context are forwarded to the legacy logging service. If you re-write root appenders, make sure that it contains `default` appender to provide backward compatibility. -**Note**: If you define an appender for a context, the log messages aren't handled by the +**Note**: If you define an appender for a context name, the log messages aren't handled by the `root` context anymore and not forwarded to the legacy logging service. #### logging.dest @@ -442,21 +442,21 @@ define a custom one. ```yaml logging: loggers: - - context: plugins.myPlugin + - name: plugins.myPlugin appenders: [console] ``` -Logs in a *file* if given file path. You should define a custom appender with `kind: file` +Logs in a *file* if given file path. You should define a custom appender with `type: file` ```yaml logging: appenders: file: - kind: file - path: /var/log/kibana.log + type: file + fileName: /var/log/kibana.log layout: - kind: pattern + type: pattern loggers: - - context: plugins.myPlugin + - name: plugins.myPlugin appenders: [file] ``` #### logging.json @@ -468,7 +468,7 @@ Suppresses all logging output other than error messages. With new logging, confi with adjusting minimum required [logging level](#log-level). ```yaml loggers: - - context: plugins.myPlugin + - name: plugins.myPlugin appenders: [console] level: error # or for all output @@ -494,32 +494,32 @@ to [specify timezone](#date) for `layout: pattern`. Defaults to host timezone wh logging: appenders: custom-console: - kind: console + type: console layout: - kind: pattern + type: pattern highlight: true pattern: "[%level] [%date{ISO8601_TZ}{America/Los_Angeles}][%logger] %message" ``` #### logging.events -Define a custom logger for a specific context. +Define a custom logger for a specific context name. **`logging.events.ops`** outputs sample system and process information at a regular interval. -With the new logging config, these are provided by a dedicated [context](#logger-hierarchy), +With the new logging config, these are provided by a dedicated [context name](#logger-hierarchy), and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`: ```yaml loggers: - - context: metrics.ops + - name: metrics.ops appenders: [console] level: debug ``` **`logging.events.request` and `logging.events.response`** provide logs for each request handled -by the http service. With the new logging config, these are provided by a dedicated [context](#logger-hierarchy), +by the http service. With the new logging config, these are provided by a dedicated [context name](#logger-hierarchy), and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`: ```yaml loggers: - - context: http.server.response + - name: http.server.response appenders: [console] level: debug ``` @@ -532,7 +532,7 @@ TBD | Parameter | Platform log record in **pattern** format | Legacy Platform log record **text** format | | --------------- | ------------------------------------------ | ------------------------------------------ | | @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | Absolute `23:33:22.011` | -| context | `parent.child` | `['parent', 'child']` | +| context name | `parent.child` | `['parent', 'child']` | | level | `DEBUG` | `['debug']` | | meta | stringified JSON object `{"to": "v8"}` | N/A | | pid | can be configured as `%pid` | N/A | @@ -540,9 +540,9 @@ TBD | Parameter | Platform log record in **json** format | Legacy Platform log record **json** format | | --------------- | ------------------------------------------ | -------------------------------------------- | | @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | ISO8601 `2012-01-31T23:33:22.011Z` | -| context | `context: parent.child` | `tags: ['parent', 'child']` | -| level | `level: DEBUG` | `tags: ['debug']` | +| context name | `log.logger: parent.child` | `tags: ['parent', 'child']` | +| level | `log.level: DEBUG` | `tags: ['debug']` | | meta | separate property `"meta": {"to": "v8"}` | merged in log record `{... "to": "v8"}` | -| pid | `pid: 12345` | `pid: 12345` | +| pid | `process.pid: 12345` | `pid: 12345` | | type | N/A | `type: log` | | error | `{ message, name, stack }` | `{ message, name, stack, code, signal }` | diff --git a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap index 8013aec4a06fd3..81321a3b1fe44c 100644 --- a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap +++ b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap @@ -84,7 +84,7 @@ Object { } `; -exports[`uses \`root\` logger if context is not specified. 1`] = ` +exports[`uses \`root\` logger if context name is not specified. 1`] = ` Array [ Array [ "[2012-01-31T03:33:22.011-05:00][INFO ][root] This message goes to a root context.", diff --git a/src/core/server/logging/appenders/appenders.test.mocks.ts b/src/core/server/logging/appenders/appenders.test.mocks.ts index 85a86ff9306c7b..1427cd7220de71 100644 --- a/src/core/server/logging/appenders/appenders.test.mocks.ts +++ b/src/core/server/logging/appenders/appenders.test.mocks.ts @@ -12,7 +12,7 @@ jest.mock('../layouts/layouts', () => { const { schema } = require('@kbn/config-schema'); return { Layouts: { - configSchema: schema.object({ kind: schema.literal('mock') }), + configSchema: schema.object({ type: schema.literal('mock') }), create: mockCreateLayout, }, }; diff --git a/src/core/server/logging/appenders/appenders.test.ts b/src/core/server/logging/appenders/appenders.test.ts index 8e1c18ae3ded66..bd32e4061049bd 100644 --- a/src/core/server/logging/appenders/appenders.test.ts +++ b/src/core/server/logging/appenders/appenders.test.ts @@ -21,33 +21,33 @@ beforeEach(() => { test('`configSchema` creates correct schema.', () => { const appendersSchema = Appenders.configSchema; - const validConfig1 = { kind: 'file', layout: { kind: 'mock' }, path: 'path' }; + const validConfig1 = { type: 'file', layout: { type: 'mock' }, fileName: 'path' }; expect(appendersSchema.validate(validConfig1)).toEqual({ - kind: 'file', - layout: { kind: 'mock' }, - path: 'path', + type: 'file', + layout: { type: 'mock' }, + fileName: 'path', }); - const validConfig2 = { kind: 'console', layout: { kind: 'mock' } }; + const validConfig2 = { type: 'console', layout: { type: 'mock' } }; expect(appendersSchema.validate(validConfig2)).toEqual({ - kind: 'console', - layout: { kind: 'mock' }, + type: 'console', + layout: { type: 'mock' }, }); const wrongConfig1 = { - kind: 'console', - layout: { kind: 'mock' }, - path: 'path', + type: 'console', + layout: { type: 'mock' }, + fileName: 'path', }; expect(() => appendersSchema.validate(wrongConfig1)).toThrow(); - const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' } }; + const wrongConfig2 = { type: 'file', layout: { type: 'mock' } }; expect(() => appendersSchema.validate(wrongConfig2)).toThrow(); const wrongConfig3 = { - kind: 'console', - layout: { kind: 'mock' }, - path: 'path', + type: 'console', + layout: { type: 'mock' }, + fileName: 'path', }; expect(() => appendersSchema.validate(wrongConfig3)).toThrow(); }); @@ -56,31 +56,31 @@ test('`create()` creates correct appender.', () => { mockCreateLayout.mockReturnValue({ format: () => '' }); const consoleAppender = Appenders.create({ - kind: 'console', - layout: { highlight: true, kind: 'pattern', pattern: '' }, + type: 'console', + layout: { highlight: true, type: 'pattern', pattern: '' }, }); expect(consoleAppender).toBeInstanceOf(ConsoleAppender); const fileAppender = Appenders.create({ - kind: 'file', - layout: { highlight: true, kind: 'pattern', pattern: '' }, - path: 'path', + type: 'file', + layout: { highlight: true, type: 'pattern', pattern: '' }, + fileName: 'path', }); expect(fileAppender).toBeInstanceOf(FileAppender); const legacyAppender = Appenders.create({ - kind: 'legacy-appender', + type: 'legacy-appender', legacyLoggingConfig: { verbose: true }, }); expect(legacyAppender).toBeInstanceOf(LegacyAppender); const rollingFileAppender = Appenders.create({ - kind: 'rolling-file', - path: 'path', - layout: { highlight: true, kind: 'pattern', pattern: '' }, - strategy: { kind: 'numeric', max: 5, pattern: '%i' }, - policy: { kind: 'size-limit', size: ByteSizeValue.parse('15b') }, + type: 'rolling-file', + fileName: 'path', + layout: { highlight: true, type: 'pattern', pattern: '' }, + strategy: { type: 'numeric', max: 5, pattern: '%i' }, + policy: { type: 'size-limit', size: ByteSizeValue.parse('15b') }, }); expect(rollingFileAppender).toBeInstanceOf(RollingFileAppender); }); diff --git a/src/core/server/logging/appenders/appenders.ts b/src/core/server/logging/appenders/appenders.ts index 564def5251c132..a41a6a2f68fa1b 100644 --- a/src/core/server/logging/appenders/appenders.ts +++ b/src/core/server/logging/appenders/appenders.ts @@ -52,11 +52,11 @@ export class Appenders { * @returns Fully constructed `Appender` instance. */ public static create(config: AppenderConfigType): DisposableAppender { - switch (config.kind) { + switch (config.type) { case 'console': return new ConsoleAppender(Layouts.create(config.layout)); case 'file': - return new FileAppender(Layouts.create(config.layout), config.path); + return new FileAppender(Layouts.create(config.layout), config.fileName); case 'rolling-file': return new RollingFileAppender(config); case 'legacy-appender': diff --git a/src/core/server/logging/appenders/console/console_appender.test.ts b/src/core/server/logging/appenders/console/console_appender.test.ts index f5ad853775eea3..1e8f742c1ecda6 100644 --- a/src/core/server/logging/appenders/console/console_appender.test.ts +++ b/src/core/server/logging/appenders/console/console_appender.test.ts @@ -12,7 +12,7 @@ jest.mock('../../layouts/layouts', () => { return { Layouts: { configSchema: schema.object({ - kind: schema.literal('mock'), + type: schema.literal('mock'), }), }, }; @@ -23,16 +23,16 @@ import { ConsoleAppender } from './console_appender'; test('`configSchema` creates correct schema.', () => { const appenderSchema = ConsoleAppender.configSchema; - const validConfig = { kind: 'console', layout: { kind: 'mock' } }; + const validConfig = { type: 'console', layout: { type: 'mock' } }; expect(appenderSchema.validate(validConfig)).toEqual({ - kind: 'console', - layout: { kind: 'mock' }, + type: 'console', + layout: { type: 'mock' }, }); - const wrongConfig1 = { kind: 'not-console', layout: { kind: 'mock' } }; + const wrongConfig1 = { type: 'not-console', layout: { type: 'mock' } }; expect(() => appenderSchema.validate(wrongConfig1)).toThrow(); - const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' }, path: 'path' }; + const wrongConfig2 = { type: 'file', layout: { type: 'mock' }, fileName: 'path' }; expect(() => appenderSchema.validate(wrongConfig2)).toThrow(); }); diff --git a/src/core/server/logging/appenders/console/console_appender.ts b/src/core/server/logging/appenders/console/console_appender.ts index 00d26d0836ee38..739068ff0a126c 100644 --- a/src/core/server/logging/appenders/console/console_appender.ts +++ b/src/core/server/logging/appenders/console/console_appender.ts @@ -13,7 +13,7 @@ import { Layouts, LayoutConfigType } from '../../layouts/layouts'; const { literal, object } = schema; export interface ConsoleAppenderConfig { - kind: 'console'; + type: 'console'; layout: LayoutConfigType; } @@ -24,7 +24,7 @@ export interface ConsoleAppenderConfig { */ export class ConsoleAppender implements DisposableAppender { public static configSchema = object({ - kind: literal('console'), + type: literal('console'), layout: Layouts.configSchema, }); diff --git a/src/core/server/logging/appenders/file/file_appender.test.mocks.ts b/src/core/server/logging/appenders/file/file_appender.test.mocks.ts index 0f87829dbbaf16..2c2a2015b6fd38 100644 --- a/src/core/server/logging/appenders/file/file_appender.test.mocks.ts +++ b/src/core/server/logging/appenders/file/file_appender.test.mocks.ts @@ -12,7 +12,7 @@ jest.mock('../../layouts/layouts', () => { return { Layouts: { configSchema: schema.object({ - kind: schema.literal('mock'), + type: schema.literal('mock'), }), }, }; diff --git a/src/core/server/logging/appenders/file/file_appender.test.ts b/src/core/server/logging/appenders/file/file_appender.test.ts index 5ef91b98e92f42..081cb16afd2ff3 100644 --- a/src/core/server/logging/appenders/file/file_appender.test.ts +++ b/src/core/server/logging/appenders/file/file_appender.test.ts @@ -20,24 +20,24 @@ beforeEach(() => { test('`createConfigSchema()` creates correct schema.', () => { const appenderSchema = FileAppender.configSchema; - const validConfig = { kind: 'file', layout: { kind: 'mock' }, path: 'path' }; + const validConfig = { type: 'file', layout: { type: 'mock' }, fileName: 'path' }; expect(appenderSchema.validate(validConfig)).toEqual({ - kind: 'file', - layout: { kind: 'mock' }, - path: 'path', + type: 'file', + layout: { type: 'mock' }, + fileName: 'path', }); const wrongConfig1 = { - kind: 'not-file', - layout: { kind: 'mock' }, - path: 'path', + type: 'not-file', + layout: { type: 'mock' }, + fileName: 'path', }; expect(() => appenderSchema.validate(wrongConfig1)).toThrow(); - const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' } }; + const wrongConfig2 = { type: 'file', layout: { type: 'mock' } }; expect(() => appenderSchema.validate(wrongConfig2)).toThrow(); - const wrongConfig3 = { kind: 'console', layout: { kind: 'mock' } }; + const wrongConfig3 = { type: 'console', layout: { type: 'mock' } }; expect(() => appenderSchema.validate(wrongConfig3)).toThrow(); }); diff --git a/src/core/server/logging/appenders/file/file_appender.ts b/src/core/server/logging/appenders/file/file_appender.ts index 0f1cb71c76e9fb..be46c261dc9965 100644 --- a/src/core/server/logging/appenders/file/file_appender.ts +++ b/src/core/server/logging/appenders/file/file_appender.ts @@ -13,9 +13,9 @@ import { createWriteStream, WriteStream } from 'fs'; import { Layouts, LayoutConfigType } from '../../layouts/layouts'; export interface FileAppenderConfig { - kind: 'file'; + type: 'file'; layout: LayoutConfigType; - path: string; + fileName: string; } /** @@ -24,9 +24,9 @@ export interface FileAppenderConfig { */ export class FileAppender implements DisposableAppender { public static configSchema = schema.object({ - kind: schema.literal('file'), + type: schema.literal('file'), layout: Layouts.configSchema, - path: schema.string(), + fileName: schema.string(), }); /** diff --git a/src/core/server/logging/appenders/rolling_file/policies/index.ts b/src/core/server/logging/appenders/rolling_file/policies/index.ts index 20038d31eee8bf..e3e33c6cbfdef6 100644 --- a/src/core/server/logging/appenders/rolling_file/policies/index.ts +++ b/src/core/server/logging/appenders/rolling_file/policies/index.ts @@ -34,7 +34,7 @@ export type TriggeringPolicyConfig = | TimeIntervalTriggeringPolicyConfig; const defaultPolicy: TimeIntervalTriggeringPolicyConfig = { - kind: 'time-interval', + type: 'time-interval', interval: moment.duration(24, 'hour'), modulate: true, }; @@ -48,7 +48,7 @@ export const createTriggeringPolicy = ( config: TriggeringPolicyConfig, context: RollingFileContext ): TriggeringPolicy => { - switch (config.kind) { + switch (config.type) { case 'size-limit': return new SizeLimitTriggeringPolicy(config, context); case 'time-interval': diff --git a/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.test.ts b/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.test.ts index 3780bb69a8341a..ee9c96de8a940c 100644 --- a/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.test.ts +++ b/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.test.ts @@ -15,7 +15,7 @@ describe('SizeLimitTriggeringPolicy', () => { let context: RollingFileContext; const createPolicy = (size: ByteSizeValue) => - new SizeLimitTriggeringPolicy({ kind: 'size-limit', size }, context); + new SizeLimitTriggeringPolicy({ type: 'size-limit', size }, context); const createLogRecord = (parts: Partial = {}): LogRecord => ({ timestamp: new Date(), diff --git a/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.ts b/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.ts index 77f0a60b0e95c8..82fee352da8df7 100644 --- a/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.ts +++ b/src/core/server/logging/appenders/rolling_file/policies/size_limit/size_limit_policy.ts @@ -12,7 +12,7 @@ import { RollingFileContext } from '../../rolling_file_context'; import { TriggeringPolicy } from '../policy'; export interface SizeLimitTriggeringPolicyConfig { - kind: 'size-limit'; + type: 'size-limit'; /** * The minimum size the file must have to roll over. @@ -21,7 +21,7 @@ export interface SizeLimitTriggeringPolicyConfig { } export const sizeLimitTriggeringPolicyConfigSchema = schema.object({ - kind: schema.literal('size-limit'), + type: schema.literal('size-limit'), size: schema.byteSize({ min: '1b', defaultValue: '100mb' }), }); diff --git a/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.test.ts b/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.test.ts index 25c5cef65c8851..03f457277b7926 100644 --- a/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.test.ts +++ b/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.test.ts @@ -42,7 +42,7 @@ describe('TimeIntervalTriggeringPolicy', () => { interval: string = '15m', modulate: boolean = false ): TimeIntervalTriggeringPolicyConfig => ({ - kind: 'time-interval', + type: 'time-interval', interval: schema.duration().validate(interval), modulate, }); diff --git a/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.ts b/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.ts index 892dd54672f146..7c4d18d929cb0d 100644 --- a/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.ts +++ b/src/core/server/logging/appenders/rolling_file/policies/time_interval/time_interval_policy.ts @@ -15,7 +15,7 @@ import { getNextRollingTime } from './get_next_rolling_time'; import { isValidRolloverInterval } from './utils'; export interface TimeIntervalTriggeringPolicyConfig { - kind: 'time-interval'; + type: 'time-interval'; /** * How often a rollover should occur. @@ -38,7 +38,7 @@ export interface TimeIntervalTriggeringPolicyConfig { } export const timeIntervalTriggeringPolicyConfigSchema = schema.object({ - kind: schema.literal('time-interval'), + type: schema.literal('time-interval'), interval: schema.duration({ defaultValue: '24h', validate: (interval) => { diff --git a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.test.ts b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.test.ts index bc28e9137b2fd7..a95d995885d8b2 100644 --- a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.test.ts +++ b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.test.ts @@ -20,20 +20,20 @@ import { LogLevel, LogRecord } from '@kbn/logging'; import { RollingFileAppender, RollingFileAppenderConfig } from './rolling_file_appender'; const config: RollingFileAppenderConfig = { - kind: 'rolling-file', - path: '/var/log/kibana.log', + type: 'rolling-file', + fileName: '/var/log/kibana.log', layout: { - kind: 'pattern', + type: 'pattern', pattern: '%message', highlight: false, }, policy: { - kind: 'time-interval', + type: 'time-interval', interval: moment.duration(4, 'hour'), modulate: true, }, strategy: { - kind: 'numeric', + type: 'numeric', max: 5, pattern: '-%i', }, @@ -99,7 +99,7 @@ describe('RollingFileAppender', () => { it('constructs its delegates with the correct parameters', () => { expect(RollingFileContextMock).toHaveBeenCalledTimes(1); - expect(RollingFileContextMock).toHaveBeenCalledWith(config.path); + expect(RollingFileContextMock).toHaveBeenCalledWith(config.fileName); expect(RollingFileManagerMock).toHaveBeenCalledTimes(1); expect(RollingFileManagerMock).toHaveBeenCalledWith(context); diff --git a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts index 748f47504f00ad..452d9493359544 100644 --- a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts +++ b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts @@ -26,7 +26,7 @@ import { RollingFileManager } from './rolling_file_manager'; import { RollingFileContext } from './rolling_file_context'; export interface RollingFileAppenderConfig { - kind: 'rolling-file'; + type: 'rolling-file'; /** * The layout to use when writing log entries */ @@ -34,7 +34,7 @@ export interface RollingFileAppenderConfig { /** * The absolute path of the file to write to. */ - path: string; + fileName: string; /** * The {@link TriggeringPolicy | policy} to use to determine if a rollover should occur. */ @@ -51,9 +51,9 @@ export interface RollingFileAppenderConfig { */ export class RollingFileAppender implements DisposableAppender { public static configSchema = schema.object({ - kind: schema.literal('rolling-file'), + type: schema.literal('rolling-file'), layout: Layouts.configSchema, - path: schema.string(), + fileName: schema.string(), policy: triggeringPolicyConfigSchema, strategy: rollingStrategyConfigSchema, }); @@ -70,7 +70,7 @@ export class RollingFileAppender implements DisposableAppender { private readonly buffer: BufferAppender; constructor(config: RollingFileAppenderConfig) { - this.context = new RollingFileContext(config.path); + this.context = new RollingFileContext(config.fileName); this.context.refreshFileInfo(); this.fileManager = new RollingFileManager(this.context); this.layout = Layouts.create(config.layout); diff --git a/src/core/server/logging/appenders/rolling_file/strategies/index.ts b/src/core/server/logging/appenders/rolling_file/strategies/index.ts index f63b68e4b92af9..c8364b0e590c67 100644 --- a/src/core/server/logging/appenders/rolling_file/strategies/index.ts +++ b/src/core/server/logging/appenders/rolling_file/strategies/index.ts @@ -19,7 +19,7 @@ export { RollingStrategy } from './strategy'; export type RollingStrategyConfig = NumericRollingStrategyConfig; const defaultStrategy: NumericRollingStrategyConfig = { - kind: 'numeric', + type: 'numeric', pattern: '-%i', max: 7, }; diff --git a/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.test.ts b/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.test.ts index d2e65f3880b87f..b4ca0131156a38 100644 --- a/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.test.ts +++ b/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.test.ts @@ -27,8 +27,8 @@ describe('NumericRollingStrategy', () => { let context: ReturnType; let strategy: NumericRollingStrategy; - const createStrategy = (config: Omit) => - new NumericRollingStrategy({ ...config, kind: 'numeric' }, context); + const createStrategy = (config: Omit) => + new NumericRollingStrategy({ ...config, type: 'numeric' }, context); beforeEach(() => { context = rollingFileAppenderMocks.createContext(logFilePath); diff --git a/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.ts b/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.ts index 5ee75bf6fda52a..13a19a40fa561d 100644 --- a/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.ts +++ b/src/core/server/logging/appenders/rolling_file/strategies/numeric/numeric_strategy.ts @@ -19,10 +19,10 @@ import { } from './rolling_tasks'; export interface NumericRollingStrategyConfig { - kind: 'numeric'; + type: 'numeric'; /** * The suffix pattern to apply when renaming a file. The suffix will be applied - * after the `appender.path` file name, but before the file extension. + * after the `appender.fileName` file name, but before the file extension. * * Must include `%i`, as it is the value that will be converted to the file index * @@ -31,8 +31,8 @@ export interface NumericRollingStrategyConfig { * logging: * appenders: * rolling-file: - * kind: rolling-file - * path: /var/logs/kibana.log + * type: rolling-file + * fileName: /var/logs/kibana.log * strategy: * type: default * pattern: "-%i" @@ -52,7 +52,7 @@ export interface NumericRollingStrategyConfig { } export const numericRollingStrategyConfigSchema = schema.object({ - kind: schema.literal('numeric'), + type: schema.literal('numeric'), pattern: schema.string({ defaultValue: '-%i', validate: (pattern) => { @@ -73,8 +73,8 @@ export const numericRollingStrategyConfigSchema = schema.object({ * logging: * appenders: * rolling-file: - * kind: rolling-file - * path: /kibana.log + * type: rolling-file + * fileName: /kibana.log * strategy: * type: numeric * pattern: "-%i" diff --git a/src/core/server/logging/integration_tests/logging.test.ts b/src/core/server/logging/integration_tests/logging.test.ts index 0af6dbfc8611ec..b4eb98546de21b 100644 --- a/src/core/server/logging/integration_tests/logging.test.ts +++ b/src/core/server/logging/integration_tests/logging.test.ts @@ -17,22 +17,22 @@ function createRoot() { silent: true, // set "true" in kbnTestServer appenders: { 'test-console': { - kind: 'console', + type: 'console', layout: { highlight: false, - kind: 'pattern', + type: 'pattern', pattern: '%level|%logger|%message', }, }, }, loggers: [ { - context: 'parent', + name: 'parent', appenders: ['test-console'], level: 'warn', }, { - context: 'parent.child', + name: 'parent.child', appenders: ['test-console'], level: 'error', }, @@ -42,7 +42,7 @@ function createRoot() { } describe('logging service', () => { - describe('logs according to context hierarchy', () => { + describe('logs according to context name hierarchy', () => { let root: ReturnType; let mockConsoleLog: jest.SpyInstance; beforeAll(async () => { @@ -61,7 +61,7 @@ describe('logging service', () => { await root.shutdown(); }); - it('uses the most specific context', () => { + it('uses the most specific context name', () => { const logger = root.logger.get('parent.child'); logger.error('error from "parent.child" context'); @@ -74,7 +74,7 @@ describe('logging service', () => { ); }); - it('uses parent context', () => { + it('uses parent context name', () => { const logger = root.logger.get('parent.another-child'); logger.error('error from "parent.another-child" context'); @@ -104,31 +104,31 @@ describe('logging service', () => { }); }); - describe('custom context configuration', () => { + describe('custom context name configuration', () => { const CUSTOM_LOGGING_CONFIG: LoggerContextConfigInput = { appenders: { customJsonConsole: { - kind: 'console', + type: 'console', layout: { - kind: 'json', + type: 'json', }, }, customPatternConsole: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', pattern: 'CUSTOM - PATTERN [%logger][%level] %message', }, }, }, loggers: [ - { context: 'debug_json', appenders: ['customJsonConsole'], level: 'debug' }, - { context: 'debug_pattern', appenders: ['customPatternConsole'], level: 'debug' }, - { context: 'info_json', appenders: ['customJsonConsole'], level: 'info' }, - { context: 'info_pattern', appenders: ['customPatternConsole'], level: 'info' }, + { name: 'debug_json', appenders: ['customJsonConsole'], level: 'debug' }, + { name: 'debug_pattern', appenders: ['customPatternConsole'], level: 'debug' }, + { name: 'info_json', appenders: ['customJsonConsole'], level: 'info' }, + { name: 'info_pattern', appenders: ['customPatternConsole'], level: 'info' }, { - context: 'all', + name: 'all', appenders: ['customJsonConsole', 'customPatternConsole'], level: 'debug', }, diff --git a/src/core/server/logging/integration_tests/rolling_file_appender.test.ts b/src/core/server/logging/integration_tests/rolling_file_appender.test.ts index fb2a714adb687a..b40ce7a4e7b0e3 100644 --- a/src/core/server/logging/integration_tests/rolling_file_appender.test.ts +++ b/src/core/server/logging/integration_tests/rolling_file_appender.test.ts @@ -25,7 +25,7 @@ function createRoot(appenderConfig: any) { }, loggers: [ { - context: 'test.rolling.file', + name: 'test.rolling.file', appenders: ['rolling-file'], level: 'debug', }, @@ -63,18 +63,18 @@ describe('RollingFileAppender', () => { describe('`size-limit` policy with `numeric` strategy', () => { it('rolls the log file in the correct order', async () => { root = createRoot({ - kind: 'rolling-file', - path: logFile, + type: 'rolling-file', + fileName: logFile, layout: { - kind: 'pattern', + type: 'pattern', pattern: '%message', }, policy: { - kind: 'size-limit', + type: 'size-limit', size: '100b', }, strategy: { - kind: 'numeric', + type: 'numeric', max: 5, pattern: '.%i', }, @@ -108,18 +108,18 @@ describe('RollingFileAppender', () => { it('only keep the correct number of files', async () => { root = createRoot({ - kind: 'rolling-file', - path: logFile, + type: 'rolling-file', + fileName: logFile, layout: { - kind: 'pattern', + type: 'pattern', pattern: '%message', }, policy: { - kind: 'size-limit', + type: 'size-limit', size: '60b', }, strategy: { - kind: 'numeric', + type: 'numeric', max: 2, pattern: '-%i', }, @@ -157,19 +157,19 @@ describe('RollingFileAppender', () => { describe('`time-interval` policy with `numeric` strategy', () => { it('rolls the log file at the given interval', async () => { root = createRoot({ - kind: 'rolling-file', - path: logFile, + type: 'rolling-file', + fileName: logFile, layout: { - kind: 'pattern', + type: 'pattern', pattern: '%message', }, policy: { - kind: 'time-interval', + type: 'time-interval', interval: '1s', modulate: true, }, strategy: { - kind: 'numeric', + type: 'numeric', max: 2, pattern: '-%i', }, diff --git a/src/core/server/logging/layouts/json_layout.test.ts b/src/core/server/logging/layouts/json_layout.test.ts index 2504ad476576fb..e55f69daab1100 100644 --- a/src/core/server/logging/layouts/json_layout.test.ts +++ b/src/core/server/logging/layouts/json_layout.test.ts @@ -63,7 +63,7 @@ const records: LogRecord[] = [ test('`createConfigSchema()` creates correct schema.', () => { const layoutSchema = JsonLayout.configSchema; - expect(layoutSchema.validate({ kind: 'json' })).toEqual({ kind: 'json' }); + expect(layoutSchema.validate({ type: 'json' })).toEqual({ type: 'json' }); }); test('`format()` correctly formats record.', () => { diff --git a/src/core/server/logging/layouts/json_layout.ts b/src/core/server/logging/layouts/json_layout.ts index 9e81303bedea07..bb8423f8240af9 100644 --- a/src/core/server/logging/layouts/json_layout.ts +++ b/src/core/server/logging/layouts/json_layout.ts @@ -14,12 +14,12 @@ import { LogRecord, Layout } from '@kbn/logging'; const { literal, object } = schema; const jsonLayoutSchema = object({ - kind: literal('json'), + type: literal('json'), }); /** @internal */ export interface JsonLayoutConfigType { - kind: 'json'; + type: 'json'; } /** diff --git a/src/core/server/logging/layouts/layouts.test.ts b/src/core/server/logging/layouts/layouts.test.ts index df91994564da17..3ff2fe23aae343 100644 --- a/src/core/server/logging/layouts/layouts.test.ts +++ b/src/core/server/logging/layouts/layouts.test.ts @@ -12,43 +12,43 @@ import { PatternLayout } from './pattern_layout'; test('`configSchema` creates correct schema for `pattern` layout.', () => { const layoutsSchema = Layouts.configSchema; - const validConfigWithOptional = { kind: 'pattern' }; + const validConfigWithOptional = { type: 'pattern' }; expect(layoutsSchema.validate(validConfigWithOptional)).toEqual({ highlight: undefined, - kind: 'pattern', + type: 'pattern', pattern: undefined, }); const validConfig = { highlight: true, - kind: 'pattern', + type: 'pattern', pattern: '%message', }; expect(layoutsSchema.validate(validConfig)).toEqual({ highlight: true, - kind: 'pattern', + type: 'pattern', pattern: '%message', }); - const wrongConfig2 = { kind: 'pattern', pattern: 1 }; + const wrongConfig2 = { type: 'pattern', pattern: 1 }; expect(() => layoutsSchema.validate(wrongConfig2)).toThrow(); }); test('`createConfigSchema()` creates correct schema for `json` layout.', () => { const layoutsSchema = Layouts.configSchema; - const validConfig = { kind: 'json' }; - expect(layoutsSchema.validate(validConfig)).toEqual({ kind: 'json' }); + const validConfig = { type: 'json' }; + expect(layoutsSchema.validate(validConfig)).toEqual({ type: 'json' }); }); test('`create()` creates correct layout.', () => { const patternLayout = Layouts.create({ highlight: false, - kind: 'pattern', + type: 'pattern', pattern: '[%date][%level][%logger] %message', }); expect(patternLayout).toBeInstanceOf(PatternLayout); - const jsonLayout = Layouts.create({ kind: 'json' }); + const jsonLayout = Layouts.create({ type: 'json' }); expect(jsonLayout).toBeInstanceOf(JsonLayout); }); diff --git a/src/core/server/logging/layouts/layouts.ts b/src/core/server/logging/layouts/layouts.ts index d6c14f3713b2c6..9abc8cd753f97b 100644 --- a/src/core/server/logging/layouts/layouts.ts +++ b/src/core/server/logging/layouts/layouts.ts @@ -27,7 +27,7 @@ export class Layouts { * @returns Fully constructed `Layout` instance. */ public static create(config: LayoutConfigType): Layout { - switch (config.kind) { + switch (config.type) { case 'json': return new JsonLayout(); diff --git a/src/core/server/logging/layouts/pattern_layout.test.ts b/src/core/server/logging/layouts/pattern_layout.test.ts index 7dd3c7c51f833c..abdc2f4fb929cb 100644 --- a/src/core/server/logging/layouts/pattern_layout.test.ts +++ b/src/core/server/logging/layouts/pattern_layout.test.ts @@ -66,28 +66,28 @@ expect.addSnapshotSerializer(stripAnsiSnapshotSerializer); test('`createConfigSchema()` creates correct schema.', () => { const layoutSchema = PatternLayout.configSchema; - const validConfigWithOptional = { kind: 'pattern' }; + const validConfigWithOptional = { type: 'pattern' }; expect(layoutSchema.validate(validConfigWithOptional)).toEqual({ highlight: undefined, - kind: 'pattern', + type: 'pattern', pattern: undefined, }); const validConfig = { highlight: true, - kind: 'pattern', + type: 'pattern', pattern: '%message', }; expect(layoutSchema.validate(validConfig)).toEqual({ highlight: true, - kind: 'pattern', + type: 'pattern', pattern: '%message', }); - const wrongConfig1 = { kind: 'json' }; + const wrongConfig1 = { type: 'json' }; expect(() => layoutSchema.validate(wrongConfig1)).toThrow(); - const wrongConfig2 = { kind: 'pattern', pattern: 1 }; + const wrongConfig2 = { type: 'pattern', pattern: 1 }; expect(() => layoutSchema.validate(wrongConfig2)).toThrow(); }); diff --git a/src/core/server/logging/layouts/pattern_layout.ts b/src/core/server/logging/layouts/pattern_layout.ts index a5e9c0be8409bd..a5dc41786c4400 100644 --- a/src/core/server/logging/layouts/pattern_layout.ts +++ b/src/core/server/logging/layouts/pattern_layout.ts @@ -32,7 +32,7 @@ export const patternSchema = schema.string({ const patternLayoutSchema = schema.object({ highlight: schema.maybe(schema.boolean()), - kind: schema.literal('pattern'), + type: schema.literal('pattern'), pattern: schema.maybe(patternSchema), }); @@ -47,7 +47,7 @@ const conversions: Conversion[] = [ /** @internal */ export interface PatternLayoutConfigType { - kind: 'pattern'; + type: 'pattern'; highlight?: boolean; pattern?: string; } diff --git a/src/core/server/logging/logging_config.test.ts b/src/core/server/logging/logging_config.test.ts index e494ae2413229a..2cb5831a8fb4ce 100644 --- a/src/core/server/logging/logging_config.test.ts +++ b/src/core/server/logging/logging_config.test.ts @@ -51,12 +51,12 @@ test('correctly fills in default config.', () => { expect(configValue.appenders.size).toBe(2); expect(configValue.appenders.get('default')).toEqual({ - kind: 'console', - layout: { kind: 'pattern', highlight: true }, + type: 'console', + layout: { type: 'pattern', highlight: true }, }); expect(configValue.appenders.get('console')).toEqual({ - kind: 'console', - layout: { kind: 'pattern', highlight: true }, + type: 'console', + layout: { type: 'pattern', highlight: true }, }); }); @@ -65,8 +65,8 @@ test('correctly fills in custom `appenders` config.', () => { config.schema.validate({ appenders: { console: { - kind: 'console', - layout: { kind: 'pattern' }, + type: 'console', + layout: { type: 'pattern' }, }, }, }) @@ -75,13 +75,13 @@ test('correctly fills in custom `appenders` config.', () => { expect(configValue.appenders.size).toBe(2); expect(configValue.appenders.get('default')).toEqual({ - kind: 'console', - layout: { kind: 'pattern', highlight: true }, + type: 'console', + layout: { type: 'pattern', highlight: true }, }); expect(configValue.appenders.get('console')).toEqual({ - kind: 'console', - layout: { kind: 'pattern' }, + type: 'console', + layout: { type: 'pattern' }, }); }); @@ -91,7 +91,7 @@ test('correctly fills in default `loggers` config.', () => { expect(configValue.loggers.size).toBe(1); expect(configValue.loggers.get('root')).toEqual({ appenders: ['default'], - context: 'root', + name: 'root', level: 'info', }); }); @@ -101,24 +101,24 @@ test('correctly fills in custom `loggers` config.', () => { config.schema.validate({ appenders: { file: { - kind: 'file', - layout: { kind: 'pattern' }, - path: 'path', + type: 'file', + layout: { type: 'pattern' }, + fileName: 'path', }, }, loggers: [ { appenders: ['file'], - context: 'plugins', + name: 'plugins', level: 'warn', }, { - context: 'plugins.pid', + name: 'plugins.pid', level: 'trace', }, { appenders: ['default'], - context: 'http', + name: 'http', level: 'error', }, ], @@ -128,22 +128,22 @@ test('correctly fills in custom `loggers` config.', () => { expect(configValue.loggers.size).toBe(4); expect(configValue.loggers.get('root')).toEqual({ appenders: ['default'], - context: 'root', + name: 'root', level: 'info', }); expect(configValue.loggers.get('plugins')).toEqual({ appenders: ['file'], - context: 'plugins', + name: 'plugins', level: 'warn', }); expect(configValue.loggers.get('plugins.pid')).toEqual({ appenders: ['file'], - context: 'plugins.pid', + name: 'plugins.pid', level: 'trace', }); expect(configValue.loggers.get('http')).toEqual({ appenders: ['default'], - context: 'http', + name: 'http', level: 'error', }); }); @@ -153,7 +153,7 @@ test('fails if loggers use unknown appenders.', () => { loggers: [ { appenders: ['unknown'], - context: 'some.nested.context', + name: 'some.nested.context', }, ], }); @@ -167,9 +167,9 @@ describe('extend', () => { config.schema.validate({ appenders: { file1: { - kind: 'file', - layout: { kind: 'pattern' }, - path: 'path', + type: 'file', + layout: { type: 'pattern' }, + fileName: 'path', }, }, }) @@ -179,9 +179,9 @@ describe('extend', () => { config.schema.validate({ appenders: { file2: { - kind: 'file', - layout: { kind: 'pattern' }, - path: 'path', + type: 'file', + layout: { type: 'pattern' }, + fileName: 'path', }, }, }) @@ -200,9 +200,9 @@ describe('extend', () => { config.schema.validate({ appenders: { file1: { - kind: 'file', - layout: { kind: 'pattern' }, - path: 'path', + type: 'file', + layout: { type: 'pattern' }, + fileName: 'path', }, }, }) @@ -212,18 +212,18 @@ describe('extend', () => { config.schema.validate({ appenders: { file1: { - kind: 'file', - layout: { kind: 'json' }, - path: 'updatedPath', + type: 'file', + layout: { type: 'json' }, + fileName: 'updatedPath', }, }, }) ); expect(mergedConfigValue.appenders.get('file1')).toEqual({ - kind: 'file', - layout: { kind: 'json' }, - path: 'updatedPath', + type: 'file', + layout: { type: 'json' }, + fileName: 'updatedPath', }); }); @@ -232,7 +232,7 @@ describe('extend', () => { config.schema.validate({ loggers: [ { - context: 'plugins', + name: 'plugins', level: 'warn', }, ], @@ -243,7 +243,7 @@ describe('extend', () => { config.schema.validate({ loggers: [ { - context: 'plugins.pid', + name: 'plugins.pid', level: 'trace', }, ], @@ -258,7 +258,7 @@ describe('extend', () => { config.schema.validate({ loggers: [ { - context: 'plugins', + name: 'plugins', level: 'warn', }, ], @@ -270,7 +270,7 @@ describe('extend', () => { loggers: [ { appenders: ['console'], - context: 'plugins', + name: 'plugins', level: 'trace', }, ], @@ -279,7 +279,7 @@ describe('extend', () => { expect(mergedConfigValue.loggers.get('plugins')).toEqual({ appenders: ['console'], - context: 'plugins', + name: 'plugins', level: 'trace', }); }); diff --git a/src/core/server/logging/logging_config.ts b/src/core/server/logging/logging_config.ts index 5b79b4e8e15d5b..24496289fb4c84 100644 --- a/src/core/server/logging/logging_config.ts +++ b/src/core/server/logging/logging_config.ts @@ -51,7 +51,7 @@ const levelSchema = schema.oneOf( */ export const loggerSchema = schema.object({ appenders: schema.arrayOf(schema.string(), { defaultValue: [] }), - context: schema.string(), + name: schema.string(), level: levelSchema, }); @@ -148,15 +148,15 @@ export class LoggingConfig { [ 'default', { - kind: 'console', - layout: { kind: 'pattern', highlight: true }, + type: 'console', + layout: { type: 'pattern', highlight: true }, } as AppenderConfigType, ], [ 'console', { - kind: 'console', - layout: { kind: 'pattern', highlight: true }, + type: 'console', + layout: { type: 'pattern', highlight: true }, } as AppenderConfigType, ], ]); @@ -182,8 +182,8 @@ export class LoggingConfig { public extend(contextConfig: LoggerContextConfigType) { // Use a Map to de-dupe any loggers for the same context. contextConfig overrides existing config. const mergedLoggers = new Map([ - ...this.configType.loggers.map((l) => [l.context, l] as [string, LoggerConfigType]), - ...contextConfig.loggers.map((l) => [l.context, l] as [string, LoggerConfigType]), + ...this.configType.loggers.map((l) => [l.name, l] as [string, LoggerConfigType]), + ...contextConfig.loggers.map((l) => [l.name, l] as [string, LoggerConfigType]), ]); const mergedConfig: LoggingConfigType = { @@ -204,13 +204,10 @@ export class LoggingConfig { private fillLoggersConfig(loggingConfig: LoggingConfigType) { // Include `root` logger into common logger list so that it can easily be a part // of the logger hierarchy and put all the loggers in map for easier retrieval. - const loggers = [ - { context: ROOT_CONTEXT_NAME, ...loggingConfig.root }, - ...loggingConfig.loggers, - ]; + const loggers = [{ name: ROOT_CONTEXT_NAME, ...loggingConfig.root }, ...loggingConfig.loggers]; const loggerConfigByContext = new Map( - loggers.map((loggerConfig) => toTuple(loggerConfig.context, loggerConfig)) + loggers.map((loggerConfig) => toTuple(loggerConfig.name, loggerConfig)) ); for (const [loggerContext, loggerConfig] of loggerConfigByContext) { @@ -247,7 +244,7 @@ function getAppenders( loggerConfig: LoggerConfigType, loggerConfigByContext: Map ) { - let currentContext = loggerConfig.context; + let currentContext = loggerConfig.name; let appenders = loggerConfig.appenders; while (appenders.length === 0) { diff --git a/src/core/server/logging/logging_service.test.ts b/src/core/server/logging/logging_service.test.ts index 66f1c67f114024..341a04736b87a4 100644 --- a/src/core/server/logging/logging_service.test.ts +++ b/src/core/server/logging/logging_service.test.ts @@ -30,11 +30,11 @@ describe('LoggingService', () => { it('forwards configuration changes to logging system', () => { const config1: LoggerContextConfigType = { appenders: new Map(), - loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }], + loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }], }; const config2: LoggerContextConfigType = { appenders: new Map(), - loggers: [{ context: 'subcontext', appenders: ['default'], level: 'all' }], + loggers: [{ name: 'subcontext', appenders: ['default'], level: 'all' }], }; setup.configure(['test', 'context'], of(config1, config2)); @@ -54,11 +54,11 @@ describe('LoggingService', () => { const updates$ = new Subject(); const config1: LoggerContextConfigType = { appenders: new Map(), - loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }], + loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }], }; const config2: LoggerContextConfigType = { appenders: new Map(), - loggers: [{ context: 'subcontext', appenders: ['default'], level: 'all' }], + loggers: [{ name: 'subcontext', appenders: ['default'], level: 'all' }], }; setup.configure(['test', 'context'], updates$); @@ -78,7 +78,7 @@ describe('LoggingService', () => { const updates$ = new Subject(); const config1: LoggerContextConfigType = { appenders: new Map(), - loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }], + loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }], }; setup.configure(['test', 'context'], updates$); diff --git a/src/core/server/logging/logging_service.ts b/src/core/server/logging/logging_service.ts index f76533dadd5c84..f5a4717fdbfaf4 100644 --- a/src/core/server/logging/logging_service.ts +++ b/src/core/server/logging/logging_service.ts @@ -31,7 +31,7 @@ export interface LoggingServiceSetup { * core.logging.configure( * of({ * appenders: new Map(), - * loggers: [{ context: 'search', appenders: ['default'] }] + * loggers: [{ name: 'search', appenders: ['default'] }] * }) * ) * ``` diff --git a/src/core/server/logging/logging_system.test.ts b/src/core/server/logging/logging_system.test.ts index 4d4ed191e60f8e..f68d6c6a97fbc4 100644 --- a/src/core/server/logging/logging_system.test.ts +++ b/src/core/server/logging/logging_system.test.ts @@ -46,7 +46,7 @@ test('uses default memory buffer logger until config is provided', () => { const logger = system.get('test', 'context'); logger.trace('trace message'); - // We shouldn't create new buffer appender for another context. + // We shouldn't create new buffer appender for another context name. const anotherLogger = system.get('test', 'context2'); anotherLogger.fatal('fatal message', { some: 'value' }); @@ -69,7 +69,7 @@ test('flushes memory buffer logger and switches to real logger once config is pr // Switch to console appender with `info` level, so that `trace` message won't go through. await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -102,12 +102,12 @@ test('appends records via multiple appenders.', async () => { await system.upgrade( config.schema.validate({ appenders: { - default: { kind: 'console', layout: { kind: 'pattern' } }, - file: { kind: 'file', layout: { kind: 'pattern' }, path: 'path' }, + default: { type: 'console', layout: { type: 'pattern' } }, + file: { type: 'file', layout: { type: 'pattern' }, fileName: 'path' }, }, loggers: [ - { appenders: ['file'], context: 'tests', level: 'warn' }, - { context: 'tests.child', level: 'error' }, + { appenders: ['file'], name: 'tests', level: 'warn' }, + { name: 'tests.child', level: 'error' }, ], }) ); @@ -121,10 +121,10 @@ test('appends records via multiple appenders.', async () => { expect(mockStreamWrite.mock.calls[1][0]).toMatchSnapshot('file logs'); }); -test('uses `root` logger if context is not specified.', async () => { +test('uses `root` logger if context name is not specified.', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'pattern' } } }, + appenders: { default: { type: 'console', layout: { type: 'pattern' } } }, }) ); @@ -137,7 +137,7 @@ test('uses `root` logger if context is not specified.', async () => { test('`stop()` disposes all appenders.', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -156,7 +156,7 @@ test('asLoggerFactory() only allows to create new loggers.', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'all' }, }) ); @@ -180,7 +180,7 @@ test('setContextConfig() updates config with relative contexts', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -189,10 +189,10 @@ test('setContextConfig() updates config with relative contexts', async () => { appenders: new Map([ [ 'custom', - { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + { type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } }, ], ]), - loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], + loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], }); testsLogger.warn('tests log to default!'); @@ -235,7 +235,7 @@ test('setContextConfig() updates config for a root context', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -244,10 +244,10 @@ test('setContextConfig() updates config for a root context', async () => { appenders: new Map([ [ 'custom', - { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + { type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } }, ], ]), - loggers: [{ context: '', appenders: ['custom'], level: 'debug' }], + loggers: [{ name: '', appenders: ['custom'], level: 'debug' }], }); testsLogger.warn('tests log to default!'); @@ -273,21 +273,21 @@ test('setContextConfig() updates config for a root context', async () => { ); }); -test('custom context configs are applied on subsequent calls to update()', async () => { +test('custom context name configs are applied on subsequent calls to update()', async () => { await system.setContextConfig(['tests', 'child'], { appenders: new Map([ [ 'custom', - { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + { type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } }, ], ]), - loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], + loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], }); // Calling upgrade after setContextConfig should not throw away the context-specific config await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -310,10 +310,10 @@ test('custom context configs are applied on subsequent calls to update()', async ); }); -test('subsequent calls to setContextConfig() for the same context override the previous config', async () => { +test('subsequent calls to setContextConfig() for the same context name override the previous config', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -322,10 +322,10 @@ test('subsequent calls to setContextConfig() for the same context override the p appenders: new Map([ [ 'custom', - { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + { type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } }, ], ]), - loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], + loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], }); // Call again, this time with level: 'warn' and a different pattern @@ -334,12 +334,12 @@ test('subsequent calls to setContextConfig() for the same context override the p [ 'custom', { - kind: 'console', - layout: { kind: 'pattern', pattern: '[%level][%logger] second pattern! %message' }, + type: 'console', + layout: { type: 'pattern', pattern: '[%level][%logger] second pattern! %message' }, }, ], ]), - loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'warn' }], + loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'warn' }], }); const logger = system.get('tests', 'child', 'grandchild'); @@ -360,10 +360,10 @@ test('subsequent calls to setContextConfig() for the same context override the p ); }); -test('subsequent calls to setContextConfig() for the same context can disable the previous config', async () => { +test('subsequent calls to setContextConfig() for the same context name can disable the previous config', async () => { await system.upgrade( config.schema.validate({ - appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, + appenders: { default: { type: 'console', layout: { type: 'json' } } }, root: { level: 'info' }, }) ); @@ -372,10 +372,10 @@ test('subsequent calls to setContextConfig() for the same context can disable th appenders: new Map([ [ 'custom', - { kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } }, + { type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } }, ], ]), - loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], + loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }], }); // Call again, this time no customizations (effectively disabling) diff --git a/src/core/server/logging/logging_system.ts b/src/core/server/logging/logging_system.ts index 9c22cea23720b7..9ae434aff41d3c 100644 --- a/src/core/server/logging/logging_system.ts +++ b/src/core/server/logging/logging_system.ts @@ -79,7 +79,7 @@ export class LoggingSystem implements LoggerFactory { * loggingSystem.setContextConfig( * ['plugins', 'data'], * { - * loggers: [{ context: 'search', appenders: ['default'] }] + * loggers: [{ name: 'search', appenders: ['default'] }] * } * ) * ``` @@ -95,9 +95,7 @@ export class LoggingSystem implements LoggerFactory { // Automatically prepend the base context to the logger sub-contexts loggers: contextConfig.loggers.map((l) => ({ ...l, - context: LoggingConfig.getLoggerContext( - l.context.length > 0 ? [context, l.context] : [context] - ), + name: LoggingConfig.getLoggerContext(l.name.length > 0 ? [context, l.name] : [context]), })), }); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/migration.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/migration.test.ts index 317bfe33b3a199..95a867934307a4 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/migration.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/migration.test.ts @@ -45,16 +45,16 @@ describe('migration v2', () => { logging: { appenders: { file: { - kind: 'file', - path: join(__dirname, 'migration_test_kibana.log'), + type: 'file', + fileName: join(__dirname, 'migration_test_kibana.log'), layout: { - kind: 'json', + type: 'json', }, }, }, loggers: [ { - context: 'root', + name: 'root', appenders: ['file'], }, ], diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_7.7.2_xpack_100k.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_7.7.2_xpack_100k.test.ts index 16ba0c855867ce..c26d4593bede19 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_7.7.2_xpack_100k.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_7.7.2_xpack_100k.test.ts @@ -47,16 +47,16 @@ describe.skip('migration from 7.7.2-xpack with 100k objects', () => { logging: { appenders: { file: { - kind: 'file', - path: join(__dirname, 'migration_test_kibana.log'), + type: 'file', + fileName: join(__dirname, 'migration_test_kibana.log'), layout: { - kind: 'json', + type: 'json', }, }, }, loggers: [ { - context: 'root', + name: 'root', appenders: ['file'], }, ], diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index 3b07d766d7cb46..f59fd6ecdec919 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -76,9 +76,9 @@ describe('#setup', () => { config: { enabled: true, appender: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', }, }, }, @@ -102,9 +102,9 @@ describe('#setup', () => { config: { enabled: true, appender: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', }, }, }, @@ -251,9 +251,9 @@ describe('#createLoggingConfig', () => { createLoggingConfig({ enabled: true, appender: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', }, }, }) @@ -264,10 +264,10 @@ describe('#createLoggingConfig', () => { Object { "appenders": Object { "auditTrailAppender": Object { - "kind": "console", "layout": Object { - "kind": "pattern", + "type": "pattern", }, + "type": "console", }, }, "loggers": Array [ @@ -275,8 +275,8 @@ describe('#createLoggingConfig', () => { "appenders": Array [ "auditTrailAppender", ], - "context": "audit.ecs", "level": "info", + "name": "audit.ecs", }, ], } @@ -293,9 +293,9 @@ describe('#createLoggingConfig', () => { createLoggingConfig({ enabled: false, appender: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', }, }, }) @@ -331,9 +331,9 @@ describe('#createLoggingConfig', () => { createLoggingConfig({ enabled: true, appender: { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', }, }, }) diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts index 42e36e50d6d42d..99dd2c82ec9fe5 100644 --- a/x-pack/plugins/security/server/audit/audit_service.ts +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -224,16 +224,16 @@ export const createLoggingConfig = (config: ConfigType['audit']) => map, LoggerContextConfigInput>((features) => ({ appenders: { auditTrailAppender: config.appender ?? { - kind: 'console', + type: 'console', layout: { - kind: 'pattern', + type: 'pattern', highlight: true, }, }, }, loggers: [ { - context: 'audit.ecs', + name: 'audit.ecs', level: config.enabled && config.appender && features.allowAuditLogging ? 'info' : 'off', appenders: ['auditTrailAppender'], }, diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index d4dcca8bebb0c1..53e4152b3c8fbf 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -1558,21 +1558,21 @@ describe('createConfig()', () => { ConfigSchema.validate({ audit: { appender: { - kind: 'file', - path: '/path/to/file.txt', + type: 'file', + fileName: '/path/to/file.txt', layout: { - kind: 'json', + type: 'json', }, }, }, }).audit.appender ).toMatchInlineSnapshot(` Object { - "kind": "file", + "fileName": "/path/to/file.txt", "layout": Object { - "kind": "json", + "type": "json", }, - "path": "/path/to/file.txt", + "type": "file", } `); }); @@ -1583,12 +1583,12 @@ describe('createConfig()', () => { audit: { // no layout configured appender: { - kind: 'file', + type: 'file', path: '/path/to/file.txt', }, }, }) - ).toThrow('[audit.appender.2.kind]: expected value to equal [legacy-appender]'); + ).toThrow('[audit.appender.2.type]: expected value to equal [legacy-appender]'); }); it('rejects an ignore_filter when no appender is configured', () => { diff --git a/x-pack/plugins/security/server/config_deprecations.test.ts b/x-pack/plugins/security/server/config_deprecations.test.ts index bdb02d8ed99750..c4c7f399e7b5d3 100644 --- a/x-pack/plugins/security/server/config_deprecations.test.ts +++ b/x-pack/plugins/security/server/config_deprecations.test.ts @@ -52,6 +52,117 @@ describe('Config Deprecations', () => { `); }); + it('renames audit.appender.kind to audit.appender.type', () => { + const config = { + xpack: { + security: { + audit: { + appender: { + kind: 'console', + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender.kind).not.toBeDefined(); + expect(migrated.xpack.security.audit.appender.type).toEqual('console'); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"xpack.security.audit.appender.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.type\\"", + ] + `); + }); + + it('renames audit.appender.layout.kind to audit.appender.layout.type', () => { + const config = { + xpack: { + security: { + audit: { + appender: { + layout: { kind: 'pattern' }, + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender.layout.kind).not.toBeDefined(); + expect(migrated.xpack.security.audit.appender.layout.type).toEqual('pattern'); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"xpack.security.audit.appender.layout.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.layout.type\\"", + ] + `); + }); + + it('renames audit.appender.policy.kind to audit.appender.policy.type', () => { + const config = { + xpack: { + security: { + audit: { + appender: { + policy: { kind: 'time-interval' }, + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender.policy.kind).not.toBeDefined(); + expect(migrated.xpack.security.audit.appender.policy.type).toEqual('time-interval'); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"xpack.security.audit.appender.policy.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.policy.type\\"", + ] + `); + }); + + it('renames audit.appender.strategy.kind to audit.appender.strategy.type', () => { + const config = { + xpack: { + security: { + audit: { + appender: { + strategy: { kind: 'numeric' }, + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender.strategy.kind).not.toBeDefined(); + expect(migrated.xpack.security.audit.appender.strategy.type).toEqual('numeric'); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"xpack.security.audit.appender.strategy.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.strategy.type\\"", + ] + `); + }); + + it('renames audit.appender.path to audit.appender.fileName', () => { + const config = { + xpack: { + security: { + audit: { + appender: { + type: 'file', + path: './audit.log', + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender.path).not.toBeDefined(); + expect(migrated.xpack.security.audit.appender.fileName).toEqual('./audit.log'); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"xpack.security.audit.appender.path\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.fileName\\"", + ] + `); + }); + it(`warns that 'authorization.legacyFallback.enabled' is unused`, () => { const config = { xpack: { diff --git a/x-pack/plugins/security/server/config_deprecations.ts b/x-pack/plugins/security/server/config_deprecations.ts index 65d18f0a4e7eb3..a7bb5e09fb919d 100644 --- a/x-pack/plugins/security/server/config_deprecations.ts +++ b/x-pack/plugins/security/server/config_deprecations.ts @@ -12,6 +12,13 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({ unused, }) => [ rename('sessionTimeout', 'session.idleTimeout'), + + rename('audit.appender.kind', 'audit.appender.type'), + rename('audit.appender.layout.kind', 'audit.appender.layout.type'), + rename('audit.appender.policy.kind', 'audit.appender.policy.type'), + rename('audit.appender.strategy.kind', 'audit.appender.strategy.type'), + rename('audit.appender.path', 'audit.appender.fileName'), + unused('authorization.legacyFallback.enabled'), unused('authc.saml.maxRedirectURLSize'), // Deprecation warning for the old array-based format of `xpack.security.authc.providers`. diff --git a/x-pack/test/security_api_integration/audit.config.ts b/x-pack/test/security_api_integration/audit.config.ts index adf36bdc99b5a9..60b1c0bf1fa808 100644 --- a/x-pack/test/security_api_integration/audit.config.ts +++ b/x-pack/test/security_api_integration/audit.config.ts @@ -29,9 +29,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), `--plugin-path=${auditLogPlugin}`, '--xpack.security.audit.enabled=true', - '--xpack.security.audit.appender.kind=file', - `--xpack.security.audit.appender.path=${auditLogPath}`, - '--xpack.security.audit.appender.layout.kind=json', + '--xpack.security.audit.appender.type=file', + `--xpack.security.audit.appender.fileName=${auditLogPath}`, + '--xpack.security.audit.appender.layout.type=json', ], }, }; From e81b5c1e400c06537adb780e36f666ea40d2ef1f Mon Sep 17 00:00:00 2001 From: Bohdan Tsymbala Date: Tue, 16 Feb 2021 20:31:36 +0100 Subject: [PATCH 16/46] [Security Solution][Artifacts] implemented policy specific trusted apps support in the manifest manager (#90991) * Implemented policy specific trusted apps support in the manifest manager. --- .../fleet/common/types/rest_spec/common.ts | 7 + x-pack/plugins/fleet/server/mocks.ts | 1 + .../routes/package_policy/handlers.test.ts | 1 + .../fleet/server/services/package_policy.ts | 27 +- x-pack/plugins/lists/common/shared_exports.ts | 2 +- .../server/saved_objects/migrations.test.ts | 249 +++-- .../lists/server/saved_objects/migrations.ts | 24 + .../common/shared_imports.ts | 1 + .../endpoint/lib/artifacts/lists.test.ts | 918 ++++++++++-------- .../server/endpoint/lib/artifacts/lists.ts | 40 +- .../routes/trusted_apps/mapping.test.ts | 4 +- .../endpoint/routes/trusted_apps/mapping.ts | 4 +- .../endpoint/routes/trusted_apps/service.ts | 2 +- .../schemas/artifacts/saved_objects.mock.ts | 6 +- .../manifest_manager/manifest_manager.mock.ts | 21 +- .../manifest_manager/manifest_manager.test.ts | 139 ++- .../manifest_manager/manifest_manager.ts | 273 +++--- 17 files changed, 1084 insertions(+), 635 deletions(-) diff --git a/x-pack/plugins/fleet/common/types/rest_spec/common.ts b/x-pack/plugins/fleet/common/types/rest_spec/common.ts index d03129efd8fad0..de5e87d2e59a5d 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/common.ts @@ -14,3 +14,10 @@ export interface ListWithKuery extends HttpFetchQuery { sortOrder?: 'desc' | 'asc'; kuery?: string; } + +export interface ListResult { + items: T[]; + total: number; + page: number; + perPage: number; +} diff --git a/x-pack/plugins/fleet/server/mocks.ts b/x-pack/plugins/fleet/server/mocks.ts index c650995c809cbb..430e38bd1bc3ef 100644 --- a/x-pack/plugins/fleet/server/mocks.ts +++ b/x-pack/plugins/fleet/server/mocks.ts @@ -53,6 +53,7 @@ export const createPackagePolicyServiceMock = () => { get: jest.fn(), getByIDs: jest.fn(), list: jest.fn(), + listIds: jest.fn(), update: jest.fn(), runExternalCallbacks: jest.fn(), } as jest.Mocked; diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts index 2b44975cc3b4de..813279f2a800fc 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts @@ -47,6 +47,7 @@ jest.mock('../../services/package_policy', (): { get: jest.fn(), getByIDs: jest.fn(), list: jest.fn(), + listIds: jest.fn(), update: jest.fn(), runExternalCallbacks: jest.fn((callbackType, newPackagePolicy, context, request) => Promise.resolve(newPackagePolicy) diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index a882ceb0037f24..335cd7c956faf9 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -20,6 +20,7 @@ import { PackagePolicyInputStream, PackageInfo, ListWithKuery, + ListResult, packageToPackagePolicy, isPackageLimited, doesAgentPolicyAlreadyIncludePackage, @@ -248,7 +249,7 @@ class PackagePolicyService { public async list( soClient: SavedObjectsClientContract, options: ListWithKuery - ): Promise<{ items: PackagePolicy[]; total: number; page: number; perPage: number }> { + ): Promise> { const { page = 1, perPage = 20, sortField = 'updated_at', sortOrder = 'desc', kuery } = options; const packagePolicies = await soClient.find({ @@ -272,6 +273,30 @@ class PackagePolicyService { }; } + public async listIds( + soClient: SavedObjectsClientContract, + options: ListWithKuery + ): Promise> { + const { page = 1, perPage = 20, sortField = 'updated_at', sortOrder = 'desc', kuery } = options; + + const packagePolicies = await soClient.find<{}>({ + type: SAVED_OBJECT_TYPE, + sortField, + sortOrder, + page, + perPage, + fields: [], + filter: kuery ? normalizeKuery(SAVED_OBJECT_TYPE, kuery) : undefined, + }); + + return { + items: packagePolicies.saved_objects.map((packagePolicySO) => packagePolicySO.id), + total: packagePolicies.total, + page, + perPage, + }; + } + public async update( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, diff --git a/x-pack/plugins/lists/common/shared_exports.ts b/x-pack/plugins/lists/common/shared_exports.ts index ba5891092fe124..6dcda5d1f8c24d 100644 --- a/x-pack/plugins/lists/common/shared_exports.ts +++ b/x-pack/plugins/lists/common/shared_exports.ts @@ -47,4 +47,4 @@ export { OsTypeArray, } from './schemas'; -export { ENDPOINT_LIST_ID } from './constants'; +export { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from './constants'; diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.test.ts b/x-pack/plugins/lists/server/saved_objects/migrations.test.ts index 143443b9320923..f71109b9bb85dc 100644 --- a/x-pack/plugins/lists/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/lists/server/saved_objects/migrations.test.ts @@ -6,61 +6,102 @@ */ import { SavedObjectUnsanitizedDoc } from 'kibana/server'; +import uuid from 'uuid'; -import { ENDPOINT_LIST_ID } from '../../common/constants'; +import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants'; +import { ExceptionListSoSchema } from '../../common/schemas/saved_objects'; import { OldExceptionListSoSchema, migrations } from './migrations'; +const DEFAULT_EXCEPTION_LIST_SO: ExceptionListSoSchema = { + comments: undefined, + created_at: '2020-06-09T20:18:20.349Z', + created_by: 'user', + description: 'description', + entries: undefined, + immutable: false, + item_id: undefined, + list_id: 'some_list', + list_type: 'list', + meta: undefined, + name: 'name', + os_types: [], + tags: [], + tie_breaker_id: uuid.v4(), + type: 'endpoint', + updated_by: 'user', + version: undefined, +}; + +const DEFAULT_OLD_EXCEPTION_LIST_SO: OldExceptionListSoSchema = { + ...DEFAULT_EXCEPTION_LIST_SO, + _tags: [], +}; + +const createOldExceptionListSoSchemaSavedObject = ( + attributes: Partial +): SavedObjectUnsanitizedDoc => ({ + attributes: { ...DEFAULT_OLD_EXCEPTION_LIST_SO, ...attributes }, + id: 'abcd', + migrationVersion: {}, + references: [], + type: 'so-type', + updated_at: '2020-06-09T20:18:20.349Z', +}); + +const createExceptionListSoSchemaSavedObject = ( + attributes: Partial +): SavedObjectUnsanitizedDoc => ({ + attributes: { ...DEFAULT_EXCEPTION_LIST_SO, ...attributes }, + id: 'abcd', + migrationVersion: {}, + references: [], + type: 'so-type', + updated_at: '2020-06-09T20:18:20.349Z', +}); + describe('7.10.0 lists migrations', () => { const migration = migrations['7.10.0']; test('properly converts .text fields to .caseless', () => { - const doc = { - attributes: { - entries: [ - { - field: 'file.path.text', - operator: 'included', - type: 'match', - value: 'C:\\Windows\\explorer.exe', - }, - { - field: 'host.os.name', - operator: 'included', - type: 'match', - value: 'my-host', - }, - { - entries: [ - { - field: 'process.command_line.text', - operator: 'included', - type: 'match', - value: '/usr/bin/bash', - }, - { - field: 'process.parent.command_line.text', - operator: 'included', - type: 'match', - value: '/usr/bin/bash', - }, - ], - field: 'nested.field', - type: 'nested', - }, - ], - list_id: ENDPOINT_LIST_ID, - }, - id: 'abcd', - migrationVersion: {}, - references: [], - type: 'so-type', - updated_at: '2020-06-09T20:18:20.349Z', - }; - expect( - migration((doc as unknown) as SavedObjectUnsanitizedDoc) - ).toEqual({ - attributes: { + const doc = createOldExceptionListSoSchemaSavedObject({ + entries: [ + { + field: 'file.path.text', + operator: 'included', + type: 'match', + value: 'C:\\Windows\\explorer.exe', + }, + { + field: 'host.os.name', + operator: 'included', + type: 'match', + value: 'my-host', + }, + { + entries: [ + { + field: 'process.command_line.text', + operator: 'included', + type: 'match', + value: '/usr/bin/bash', + }, + { + field: 'process.parent.command_line.text', + operator: 'included', + type: 'match', + value: '/usr/bin/bash', + }, + ], + field: 'nested.field', + type: 'nested', + }, + ], + list_id: ENDPOINT_LIST_ID, + }); + + expect(migration(doc)).toEqual( + createOldExceptionListSoSchemaSavedObject({ entries: [ { field: 'file.path.caseless', @@ -94,40 +135,98 @@ describe('7.10.0 lists migrations', () => { }, ], list_id: ENDPOINT_LIST_ID, - }, - id: 'abcd', - migrationVersion: {}, - references: [], - type: 'so-type', - updated_at: '2020-06-09T20:18:20.349Z', - }); + }) + ); }); test('properly copies os tags to os_types', () => { - const doc = { - attributes: { - _tags: ['1234', 'os:windows'], - comments: [], - }, - id: 'abcd', - migrationVersion: {}, - references: [], - type: 'so-type', - updated_at: '2020-06-09T20:18:20.349Z', - }; - expect( - migration((doc as unknown) as SavedObjectUnsanitizedDoc) - ).toEqual({ - attributes: { + const doc = createOldExceptionListSoSchemaSavedObject({ + _tags: ['1234', 'os:windows'], + comments: [], + }); + + expect(migration(doc)).toEqual( + createOldExceptionListSoSchemaSavedObject({ _tags: ['1234', 'os:windows'], comments: [], os_types: ['windows'], - }, - id: 'abcd', - migrationVersion: {}, - references: [], - type: 'so-type', - updated_at: '2020-06-09T20:18:20.349Z', + }) + ); + }); +}); + +describe('7.12.0 lists migrations', () => { + const migration = migrations['7.12.0']; + + test('should not convert non trusted apps lists', () => { + const doc = createExceptionListSoSchemaSavedObject({ list_id: ENDPOINT_LIST_ID, tags: [] }); + + expect(migration(doc)).toEqual( + createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_LIST_ID, + tags: [], + tie_breaker_id: expect.anything(), + }) + ); + }); + + test('converts empty tags to contain list containing "policy:all" tag', () => { + const doc = createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: [], + }); + + expect(migration(doc)).toEqual( + createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['policy:all'], + tie_breaker_id: expect.anything(), + }) + ); + }); + + test('preserves existing non policy related tags', () => { + const doc = createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['tag1', 'tag2'], + }); + + expect(migration(doc)).toEqual( + createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['tag1', 'tag2', 'policy:all'], + tie_breaker_id: expect.anything(), + }) + ); + }); + + test('preserves existing "policy:all" tag and does not add another one', () => { + const doc = createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['policy:all', 'tag1', 'tag2'], + }); + + expect(migration(doc)).toEqual( + createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['policy:all', 'tag1', 'tag2'], + tie_breaker_id: expect.anything(), + }) + ); + }); + + test('preserves existing policy reference tag and does not add "policy:all" tag', () => { + const doc = createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['policy:056d2d4645421fb92e5cd39f33d70856', 'tag1', 'tag2'], }); + + expect(migration(doc)).toEqual( + createExceptionListSoSchemaSavedObject({ + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + tags: ['policy:056d2d4645421fb92e5cd39f33d70856', 'tag1', 'tag2'], + tie_breaker_id: expect.anything(), + }) + ); }); }); diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.ts b/x-pack/plugins/lists/server/saved_objects/migrations.ts index 43faa7a5e8fb64..2fa19a6810a8ad 100644 --- a/x-pack/plugins/lists/server/saved_objects/migrations.ts +++ b/x-pack/plugins/lists/server/saved_objects/migrations.ts @@ -40,6 +40,9 @@ const reduceOsTypes = (acc: string[], tag: string): string[] => { return [...acc]; }; +const containsPolicyTags = (tags: string[]): boolean => + tags.some((tag) => tag.startsWith('policy:')); + export type OldExceptionListSoSchema = ExceptionListSoSchema & { _tags: string[]; }; @@ -64,4 +67,25 @@ export const migrations = { }, references: doc.references || [], }), + '7.12.0': ( + doc: SavedObjectUnsanitizedDoc + ): SavedObjectSanitizedDoc => { + if (doc.attributes.list_id === ENDPOINT_TRUSTED_APPS_LIST_ID) { + return { + ...doc, + ...{ + attributes: { + ...doc.attributes, + tags: [ + ...(doc.attributes.tags || []), + ...(containsPolicyTags(doc.attributes.tags) ? [] : ['policy:all']), + ], + }, + }, + references: doc.references || [], + }; + } else { + return { ...doc, references: doc.references || [] }; + } + }, }; diff --git a/x-pack/plugins/security_solution/common/shared_imports.ts b/x-pack/plugins/security_solution/common/shared_imports.ts index d6ec668e1b0f9f..988f0ad0c125d4 100644 --- a/x-pack/plugins/security_solution/common/shared_imports.ts +++ b/x-pack/plugins/security_solution/common/shared_imports.ts @@ -43,6 +43,7 @@ export { ExceptionListType, Type, ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, osTypeArray, OsTypeArray, } from '../../lists/common'; diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts index 2833a5ad24f2a3..88bf7941c84643 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts @@ -10,12 +10,17 @@ import { listMock } from '../../../../../lists/server/mocks'; import { getFoundExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { EntriesArray, EntryList } from '../../../../../lists/common/schemas/types'; -import { buildArtifact, getFullEndpointExceptionList } from './lists'; +import { + buildArtifact, + getEndpointExceptionList, + getEndpointTrustedAppsList, + getFilteredEndpointExceptionList, +} from './lists'; import { TranslatedEntry, TranslatedExceptionListItem } from '../../schemas/artifacts'; import { ArtifactConstants } from './common'; -import { ENDPOINT_LIST_ID } from '../../../../../lists/common'; +import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; -describe('buildEventTypeSignal', () => { +describe('artifacts lists', () => { let mockExceptionClient: ExceptionListClient; beforeEach(() => { @@ -23,214 +28,384 @@ describe('buildEventTypeSignal', () => { mockExceptionClient = listMock.getExceptionListClient(); }); - test('it should convert the exception lists response to the proper endpoint format', async () => { - const expectedEndpointExceptions = { - type: 'simple', - entries: [ - { - entries: [ - { - field: 'nested.field', - operator: 'included', - type: 'exact_cased', - value: 'some value', - }, - ], - field: 'some.parentField', - type: 'nested', - }, - { - field: 'some.not.nested.field', - operator: 'included', - type: 'exact_cased', - value: 'some value', - }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], + describe('getFilteredEndpointExceptionList', () => { + const TEST_FILTER = 'exception-list-agnostic.attributes.os_types:"linux"'; + + test('it should convert the exception lists response to the proper endpoint format', async () => { + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + { + field: 'some.not.nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); }); - }); - test('it should convert simple fields', async () => { - const testEntries: EntriesArray = [ - { field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' }, - { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, - { field: 'host.hostname', operator: 'included', type: 'match', value: 'estc' }, - ]; + test('it should convert simple fields', async () => { + const testEntries: EntriesArray = [ + { field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' }, + { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, + { field: 'host.hostname', operator: 'included', type: 'match', value: 'estc' }, + ]; - const expectedEndpointExceptions = { - type: 'simple', - entries: [ - { - field: 'host.os.full', - operator: 'included', - type: 'exact_cased', - value: 'windows', - }, + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + field: 'host.os.full', + operator: 'included', + type: 'exact_cased', + value: 'windows', + }, + { + field: 'server.ip', + operator: 'included', + type: 'exact_cased', + value: '192.168.1.1', + }, + { + field: 'host.hostname', + operator: 'included', + type: 'exact_cased', + value: 'estc', + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); + }); + + test('it should convert fields case sensitive', async () => { + const testEntries: EntriesArray = [ + { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, + { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, { - field: 'server.ip', + field: 'host.hostname.caseless', operator: 'included', - type: 'exact_cased', - value: '192.168.1.1', + type: 'match_any', + value: ['estc', 'kibana'], }, + ]; + + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + field: 'host.os.full', + operator: 'included', + type: 'exact_caseless', + value: 'windows', + }, + { + field: 'server.ip', + operator: 'included', + type: 'exact_cased', + value: '192.168.1.1', + }, + { + field: 'host.hostname', + operator: 'included', + type: 'exact_caseless_any', + value: ['estc', 'kibana'], + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); + }); + + test('it should deduplicate exception entries', async () => { + const testEntries: EntriesArray = [ + { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, + { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, + { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, + { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, { field: 'host.hostname', operator: 'included', - type: 'exact_cased', - value: 'estc', + type: 'match_any', + value: ['estc', 'kibana'], }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], - }); - }); + ]; - test('it should convert fields case sensitive', async () => { - const testEntries: EntriesArray = [ - { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, - { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, - { - field: 'host.hostname.caseless', - operator: 'included', - type: 'match_any', - value: ['estc', 'kibana'], - }, - ]; + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + field: 'host.os.full', + operator: 'included', + type: 'exact_caseless', + value: 'windows', + }, + { + field: 'server.ip', + operator: 'included', + type: 'exact_cased', + value: '192.168.1.1', + }, + { + field: 'host.hostname', + operator: 'included', + type: 'exact_cased_any', + value: ['estc', 'kibana'], + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); + }); - const expectedEndpointExceptions = { - type: 'simple', - entries: [ - { - field: 'host.os.full', - operator: 'included', - type: 'exact_caseless', - value: 'windows', - }, - { - field: 'server.ip', - operator: 'included', - type: 'exact_cased', - value: '192.168.1.1', - }, + test('it should not deduplicate exception entries across nested boundaries', async () => { + const testEntries: EntriesArray = [ { - field: 'host.hostname', - operator: 'included', - type: 'exact_caseless_any', - value: ['estc', 'kibana'], + entries: [ + { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, + ], + field: 'some.parentField', + type: 'nested', }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], + // Same as above but not inside the nest + { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, + ]; + + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + { + field: 'nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); }); - }); - test('it should deduplicate exception entries', async () => { - const testEntries: EntriesArray = [ - { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, - { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, - { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, - { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, - { - field: 'host.hostname', - operator: 'included', - type: 'match_any', - value: ['estc', 'kibana'], - }, - ]; + test('it should deduplicate exception items', async () => { + const testEntries: EntriesArray = [ + { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, + { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, + ]; - const expectedEndpointExceptions = { - type: 'simple', - entries: [ + const expectedEndpointExceptions = { + type: 'simple', + entries: [ + { + field: 'host.os.full', + operator: 'included', + type: 'exact_caseless', + value: 'windows', + }, + { + field: 'server.ip', + operator: 'included', + type: 'exact_cased', + value: '192.168.1.1', + }, + ], + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + + // Create a second exception item with the same entries + first.data[1] = getExceptionListItemSchemaMock(); + first.data[1].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); + }); + + test('it should ignore unsupported entries', async () => { + // Lists and exists are not supported by the Endpoint + const testEntries: EntriesArray = [ + { field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' }, { field: 'host.os.full', operator: 'included', - type: 'exact_caseless', - value: 'windows', - }, - { - field: 'server.ip', - operator: 'included', - type: 'exact_cased', - value: '192.168.1.1', - }, - { - field: 'host.hostname', - operator: 'included', - type: 'exact_cased_any', - value: ['estc', 'kibana'], - }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], - }); - }); + type: 'list', + list: { + id: 'lists_not_supported', + type: 'keyword', + }, + } as EntryList, + { field: 'server.ip', operator: 'included', type: 'exists' }, + ]; - test('it should not deduplicate exception entries across nested boundaries', async () => { - const testEntries: EntriesArray = [ - { + const expectedEndpointExceptions = { + type: 'simple', entries: [ - { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, + { + field: 'host.os.full', + operator: 'included', + type: 'exact_cased', + value: 'windows', + }, ], - field: 'some.parentField', - type: 'nested', - }, - // Same as above but not inside the nest - { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, - ]; + }; + + const first = getFoundExceptionListItemSchemaMock(); + first.data[0].entries = testEntries; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp).toEqual({ + entries: [expectedEndpointExceptions], + }); + }); + + test('it should convert the exception lists response to the proper endpoint format while paging', async () => { + // The first call returns two exceptions + const first = getFoundExceptionListItemSchemaMock(); + first.per_page = 2; + first.total = 4; + first.data.push(getExceptionListItemSchemaMock()); + + // The second call returns two exceptions + const second = getFoundExceptionListItemSchemaMock(); + second.per_page = 2; + second.total = 4; + second.data.push(getExceptionListItemSchemaMock()); + + mockExceptionClient.findExceptionListItem = jest + .fn() + .mockReturnValueOnce(first) + .mockReturnValueOnce(second); + + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + + // Expect 2 exceptions, the first two calls returned the same exception list items + expect(resp.entries.length).toEqual(2); + }); + + test('it should handle no exceptions', async () => { + const exceptionsResponse = getFoundExceptionListItemSchemaMock(); + exceptionsResponse.data = []; + exceptionsResponse.total = 0; + mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(exceptionsResponse); + const resp = await getFilteredEndpointExceptionList( + mockExceptionClient, + 'v1', + TEST_FILTER, + ENDPOINT_LIST_ID + ); + expect(resp.entries.length).toEqual(0); + }); - const expectedEndpointExceptions = { - type: 'simple', - entries: [ + test('it should return a stable hash regardless of order of entries', async () => { + const translatedEntries: TranslatedEntry[] = [ { entries: [ { - field: 'nested.field', + field: 'some.nested.field', operator: 'included', type: 'exact_cased', value: 'some value', @@ -245,218 +420,107 @@ describe('buildEventTypeSignal', () => { type: 'exact_cased', value: 'some value', }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], - }); - }); - - test('it should deduplicate exception items', async () => { - const testEntries: EntriesArray = [ - { field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' }, - { field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' }, - ]; - - const expectedEndpointExceptions = { - type: 'simple', - entries: [ - { - field: 'host.os.full', - operator: 'included', - type: 'exact_caseless', - value: 'windows', - }, - { - field: 'server.ip', - operator: 'included', - type: 'exact_cased', - value: '192.168.1.1', - }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - - // Create a second exception item with the same entries - first.data[1] = getExceptionListItemSchemaMock(); - first.data[1].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], - }); - }); - - test('it should ignore unsupported entries', async () => { - // Lists and exists are not supported by the Endpoint - const testEntries: EntriesArray = [ - { field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' }, - { - field: 'host.os.full', - operator: 'included', - type: 'list', - list: { - id: 'lists_not_supported', - type: 'keyword', - }, - } as EntryList, - { field: 'server.ip', operator: 'included', type: 'exists' }, - ]; - - const expectedEndpointExceptions = { - type: 'simple', - entries: [ - { - field: 'host.os.full', - operator: 'included', - type: 'exact_cased', - value: 'windows', - }, - ], - }; - - const first = getFoundExceptionListItemSchemaMock(); - first.data[0].entries = testEntries; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(first); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp).toEqual({ - entries: [expectedEndpointExceptions], - }); - }); + ]; + const translatedEntriesReversed = translatedEntries.reverse(); - test('it should convert the exception lists response to the proper endpoint format while paging', async () => { - // The first call returns two exceptions - const first = getFoundExceptionListItemSchemaMock(); - first.per_page = 2; - first.total = 4; - first.data.push(getExceptionListItemSchemaMock()); - - // The second call returns two exceptions - const second = getFoundExceptionListItemSchemaMock(); - second.per_page = 2; - second.total = 4; - second.data.push(getExceptionListItemSchemaMock()); - - mockExceptionClient.findExceptionListItem = jest - .fn() - .mockReturnValueOnce(first) - .mockReturnValueOnce(second); - - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - - // Expect 2 exceptions, the first two calls returned the same exception list items - expect(resp.entries.length).toEqual(2); - }); - - test('it should handle no exceptions', async () => { - const exceptionsResponse = getFoundExceptionListItemSchemaMock(); - exceptionsResponse.data = []; - exceptionsResponse.total = 0; - mockExceptionClient.findExceptionListItem = jest.fn().mockReturnValueOnce(exceptionsResponse); - const resp = await getFullEndpointExceptionList( - mockExceptionClient, - 'linux', - 'v1', - ENDPOINT_LIST_ID - ); - expect(resp.entries.length).toEqual(0); - }); + const translatedExceptionList = { + entries: [ + { + type: 'simple', + entries: translatedEntries, + }, + ], + }; - test('it should return a stable hash regardless of order of entries', async () => { - const translatedEntries: TranslatedEntry[] = [ - { + const translatedExceptionListReversed = { entries: [ { - field: 'some.nested.field', - operator: 'included', - type: 'exact_cased', - value: 'some value', + type: 'simple', + entries: translatedEntriesReversed, }, ], - field: 'some.parentField', - type: 'nested', - }, - { - field: 'nested.field', - operator: 'included', - type: 'exact_cased', - value: 'some value', - }, - ]; - const translatedEntriesReversed = translatedEntries.reverse(); + }; + + const artifact1 = await buildArtifact( + translatedExceptionList, + 'v1', + 'linux', + ArtifactConstants.GLOBAL_ALLOWLIST_NAME + ); + const artifact2 = await buildArtifact( + translatedExceptionListReversed, + 'v1', + 'linux', + ArtifactConstants.GLOBAL_ALLOWLIST_NAME + ); + expect(artifact1.decodedSha256).toEqual(artifact2.decodedSha256); + }); - const translatedExceptionList = { - entries: [ + test('it should return a stable hash regardless of order of items', async () => { + const translatedItems: TranslatedExceptionListItem[] = [ { type: 'simple', - entries: translatedEntries, + entries: [ + { + entries: [ + { + field: 'some.nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + ], }, - ], - }; - - const translatedExceptionListReversed = { - entries: [ { type: 'simple', - entries: translatedEntriesReversed, + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'exact_cased', + value: 'some value', + }, + ], }, - ], - }; - - const artifact1 = await buildArtifact( - translatedExceptionList, - 'linux', - 'v1', - ArtifactConstants.GLOBAL_ALLOWLIST_NAME - ); - const artifact2 = await buildArtifact( - translatedExceptionListReversed, - 'linux', - 'v1', - ArtifactConstants.GLOBAL_ALLOWLIST_NAME - ); - expect(artifact1.decodedSha256).toEqual(artifact2.decodedSha256); + ]; + + const translatedExceptionList = { + entries: translatedItems, + }; + + const translatedExceptionListReversed = { + entries: translatedItems.reverse(), + }; + + const artifact1 = await buildArtifact( + translatedExceptionList, + 'v1', + 'linux', + ArtifactConstants.GLOBAL_ALLOWLIST_NAME + ); + const artifact2 = await buildArtifact( + translatedExceptionListReversed, + 'v1', + 'linux', + ArtifactConstants.GLOBAL_ALLOWLIST_NAME + ); + expect(artifact1.decodedSha256).toEqual(artifact2.decodedSha256); + }); }); - test('it should return a stable hash regardless of order of items', async () => { - const translatedItems: TranslatedExceptionListItem[] = [ + const TEST_EXCEPTION_LIST_ITEM = { + entries: [ { type: 'simple', entries: [ { entries: [ { - field: 'some.nested.field', + field: 'nested.field', operator: 'included', type: 'exact_cased', value: 'some value', @@ -465,41 +529,87 @@ describe('buildEventTypeSignal', () => { field: 'some.parentField', type: 'nested', }, - ], - }, - { - type: 'simple', - entries: [ { - field: 'nested.field', + field: 'some.not.nested.field', operator: 'included', type: 'exact_cased', value: 'some value', }, ], }, - ]; - - const translatedExceptionList = { - entries: translatedItems, - }; - - const translatedExceptionListReversed = { - entries: translatedItems.reverse(), - }; - - const artifact1 = await buildArtifact( - translatedExceptionList, - 'linux', - 'v1', - ArtifactConstants.GLOBAL_ALLOWLIST_NAME - ); - const artifact2 = await buildArtifact( - translatedExceptionListReversed, - 'linux', - 'v1', - ArtifactConstants.GLOBAL_ALLOWLIST_NAME - ); - expect(artifact1.decodedSha256).toEqual(artifact2.decodedSha256); + ], + }; + + describe('getEndpointExceptionList', () => { + test('it should build proper kuery', async () => { + mockExceptionClient.findExceptionListItem = jest + .fn() + .mockReturnValueOnce(getFoundExceptionListItemSchemaMock()); + + const resp = await getEndpointExceptionList(mockExceptionClient, 'v1', 'windows'); + + expect(resp).toEqual(TEST_EXCEPTION_LIST_ITEM); + + expect(mockExceptionClient.findExceptionListItem).toHaveBeenCalledWith({ + listId: ENDPOINT_LIST_ID, + namespaceType: 'agnostic', + filter: 'exception-list-agnostic.attributes.os_types:"windows"', + perPage: 100, + page: 1, + sortField: 'created_at', + sortOrder: 'desc', + }); + }); + }); + + describe('getEndpointTrustedAppsList', () => { + test('it should build proper kuery without policy', async () => { + mockExceptionClient.findExceptionListItem = jest + .fn() + .mockReturnValueOnce(getFoundExceptionListItemSchemaMock()); + + const resp = await getEndpointTrustedAppsList(mockExceptionClient, 'v1', 'macos'); + + expect(resp).toEqual(TEST_EXCEPTION_LIST_ITEM); + + expect(mockExceptionClient.findExceptionListItem).toHaveBeenCalledWith({ + listId: ENDPOINT_TRUSTED_APPS_LIST_ID, + namespaceType: 'agnostic', + filter: + 'exception-list-agnostic.attributes.os_types:"macos" and (exception-list-agnostic.attributes.tags:"policy:all")', + perPage: 100, + page: 1, + sortField: 'created_at', + sortOrder: 'desc', + }); + }); + + test('it should build proper kuery with policy', async () => { + mockExceptionClient.findExceptionListItem = jest + .fn() + .mockReturnValueOnce(getFoundExceptionListItemSchemaMock()); + + const resp = await getEndpointTrustedAppsList( + mockExceptionClient, + 'v1', + 'macos', + 'c6d16e42-c32d-4dce-8a88-113cfe276ad1' + ); + + expect(resp).toEqual(TEST_EXCEPTION_LIST_ITEM); + + expect(mockExceptionClient.findExceptionListItem).toHaveBeenCalledWith({ + listId: ENDPOINT_TRUSTED_APPS_LIST_ID, + namespaceType: 'agnostic', + filter: + 'exception-list-agnostic.attributes.os_types:"macos" and ' + + '(exception-list-agnostic.attributes.tags:"policy:all" or ' + + 'exception-list-agnostic.attributes.tags:"policy:c6d16e42-c32d-4dce-8a88-113cfe276ad1")', + perPage: 100, + page: 1, + sortField: 'created_at', + sortOrder: 'desc', + }); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts index 6cc6a821eba334..322bb2ca47a45c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts @@ -12,7 +12,7 @@ import { validate } from '../../../../common/validate'; import { Entry, EntryNested } from '../../../../../lists/common/schemas/types'; import { ExceptionListClient } from '../../../../../lists/server'; -import { ENDPOINT_LIST_ID } from '../../../../common/shared_imports'; +import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../common/shared_imports'; import { InternalArtifactSchema, TranslatedEntry, @@ -28,12 +28,11 @@ import { internalArtifactCompleteSchema, InternalArtifactCompleteSchema, } from '../../schemas'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; export async function buildArtifact( exceptions: WrappedTranslatedExceptionList, - os: string, schemaVersion: string, + os: string, name: string ): Promise { const exceptionsBuffer = Buffer.from(JSON.stringify(exceptions)); @@ -74,10 +73,10 @@ export function isCompressed(artifact: InternalArtifactSchema) { return artifact.compressionAlgorithm === 'zlib'; } -export async function getFullEndpointExceptionList( +export async function getFilteredEndpointExceptionList( eClient: ExceptionListClient, - os: string, schemaVersion: string, + filter: string, listId: typeof ENDPOINT_LIST_ID | typeof ENDPOINT_TRUSTED_APPS_LIST_ID ): Promise { const exceptions: WrappedTranslatedExceptionList = { entries: [] }; @@ -88,7 +87,7 @@ export async function getFullEndpointExceptionList( const response = await eClient.findExceptionListItem({ listId, namespaceType: 'agnostic', - filter: `exception-list-agnostic.attributes.os_types:\"${os}\"`, + filter, perPage: 100, page, sortField: 'created_at', @@ -114,6 +113,35 @@ export async function getFullEndpointExceptionList( return validated as WrappedTranslatedExceptionList; } +export async function getEndpointExceptionList( + eClient: ExceptionListClient, + schemaVersion: string, + os: string +): Promise { + const filter = `exception-list-agnostic.attributes.os_types:\"${os}\"`; + + return getFilteredEndpointExceptionList(eClient, schemaVersion, filter, ENDPOINT_LIST_ID); +} + +export async function getEndpointTrustedAppsList( + eClient: ExceptionListClient, + schemaVersion: string, + os: string, + policyId?: string +): Promise { + const osFilter = `exception-list-agnostic.attributes.os_types:\"${os}\"`; + const policyFilter = `(exception-list-agnostic.attributes.tags:\"policy:all\"${ + policyId ? ` or exception-list-agnostic.attributes.tags:\"policy:${policyId}\"` : '' + })`; + + return getFilteredEndpointExceptionList( + eClient, + schemaVersion, + `${osFilter} and ${policyFilter}`, + ENDPOINT_TRUSTED_APPS_LIST_ID + ); +} + /** * Translates Exception list items to Exceptions the endpoint can understand * @param exceptions diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts index 972c4f3153a1c8..b8b1e13f2052b5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts @@ -35,7 +35,7 @@ const createExceptionListItemOptions = ( name: '', namespaceType: 'agnostic', osTypes: [], - tags: [], + tags: ['policy:all'], type: 'simple', ...options, }); @@ -56,7 +56,7 @@ const exceptionListItemSchema = ( name: '', namespace_type: 'agnostic', os_types: [], - tags: [], + tags: ['policy:all'], type: 'simple', tie_breaker_id: '123', updated_at: '11/11/2011T11:11:11.111', diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index 4d2238ea96ee15..41b4b7b1d55fdd 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -15,7 +15,7 @@ import { ExceptionListItemSchema, NestedEntriesArray, } from '../../../../../lists/common/shared_exports'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; import { CreateExceptionListItemOptions } from '../../../../../lists/server'; import { ConditionEntry, @@ -184,7 +184,7 @@ export const newTrustedAppToCreateExceptionListItemOptions = ({ name, namespaceType: 'agnostic', osTypes: [OPERATING_SYSTEM_TO_OS_TYPE[os]], - tags: [], + tags: ['policy:all'], type: 'simple', }; }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts index dc3c369494d4e2..97a8451bf25d83 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts @@ -6,7 +6,7 @@ */ import { ExceptionListClient } from '../../../../../lists/server'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; import { DeleteTrustedAppsRequestParams, diff --git a/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/saved_objects.mock.ts b/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/saved_objects.mock.ts index dedbcc25e2373e..1975c2a92cc16f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/saved_objects.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/saved_objects.mock.ts @@ -36,8 +36,8 @@ export const getInternalArtifactMock = async ( ): Promise => { const artifact = await buildArtifact( getTranslatedExceptionListMock(), - os, schemaVersion, + os, artifactName ); return opts?.compress ? compressArtifact(artifact) : artifact; @@ -49,7 +49,7 @@ export const getEmptyInternalArtifactMock = async ( opts?: { compress: boolean }, artifactName: string = ArtifactConstants.GLOBAL_ALLOWLIST_NAME ): Promise => { - const artifact = await buildArtifact({ entries: [] }, os, schemaVersion, artifactName); + const artifact = await buildArtifact({ entries: [] }, schemaVersion, os, artifactName); return opts?.compress ? compressArtifact(artifact) : artifact; }; @@ -62,8 +62,8 @@ export const getInternalArtifactMockWithDiffs = async ( mock.entries.pop(); const artifact = await buildArtifact( mock, - os, schemaVersion, + os, ArtifactConstants.GLOBAL_ALLOWLIST_NAME ); return opts?.compress ? compressArtifact(artifact) : artifact; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts index a8bbfca0d41e58..b0e0d5d8ebfbea 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts @@ -33,17 +33,24 @@ export const createExceptionListResponse = (data: ExceptionListItemSchema[], tot type FindExceptionListItemOptions = Parameters[0]; -const FILTER_REGEXP = /^exception-list-agnostic\.attributes\.os_types:"(\w+)"$/; +const FILTER_PROPERTY_PREFIX = 'exception-list-agnostic\\.attributes'; +const FILTER_REGEXP = new RegExp( + `^${FILTER_PROPERTY_PREFIX}\.os_types:"([^"]+)"( and \\(${FILTER_PROPERTY_PREFIX}\.tags:"policy:all"( or ${FILTER_PROPERTY_PREFIX}\.tags:"policy:([^"]+)")?\\))?$` +); export const mockFindExceptionListItemResponses = ( responses: Record> ) => { return jest.fn().mockImplementation((options: FindExceptionListItemOptions) => { - const os = FILTER_REGEXP.test(options.filter || '') - ? options.filter!.match(FILTER_REGEXP)![1] - : ''; - - return createExceptionListResponse(responses[options.listId]?.[os] || []); + const matches = options.filter!.match(FILTER_REGEXP) || []; + + if (matches[4] && responses[options.listId]?.[`${matches![1]}-${matches[4]}`]) { + return createExceptionListResponse( + responses[options.listId]?.[`${matches![1]}-${matches[4]}`] || [] + ); + } else { + return createExceptionListResponse(responses[options.listId]?.[matches![1] || ''] || []); + } }); }; @@ -118,7 +125,7 @@ export const getManifestManagerMock = ( context.exceptionListClient.findExceptionListItem = jest .fn() .mockRejectedValue(new Error('unexpected thing happened')); - return super.buildExceptionListArtifacts('v1'); + return super.buildExceptionListArtifacts(); case ManifestManagerMockType.NormalFlow: return getMockArtifactsWithDiff(); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index 52897f473189fb..26db49be459fa2 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -8,8 +8,7 @@ import { inflateSync } from 'zlib'; import { SavedObjectsErrorHelpers } from 'src/core/server'; import { savedObjectsClientMock } from 'src/core/server/mocks'; -import { ENDPOINT_LIST_ID } from '../../../../../../lists/common'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../../lists/common/constants'; +import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../../lists/common'; import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { PackagePolicy } from '../../../../../../fleet/common/types/models'; import { getEmptyInternalArtifactMock } from '../../../schemas/artifacts/saved_objects.mock'; @@ -211,10 +210,19 @@ describe('ManifestManager', () => { ARTIFACT_NAME_TRUSTED_APPS_LINUX, ]; - const getArtifactIds = (artifacts: InternalArtifactSchema[]) => - artifacts.map((artifact) => artifact.identifier); + const getArtifactIds = (artifacts: InternalArtifactSchema[]) => [ + ...new Set(artifacts.map((artifact) => artifact.identifier)).values(), + ]; + + const mockPolicyListIdsResponse = (items: string[]) => + jest.fn().mockResolvedValue({ + items, + page: 1, + per_page: 100, + total: items.length, + }); - test('Fails when exception list list client fails', async () => { + test('Fails when exception list client fails', async () => { const context = buildManifestManagerContextMock({}); const manifestManager = new ManifestManager(context); @@ -228,6 +236,7 @@ describe('ManifestManager', () => { const manifestManager = new ManifestManager(context); context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({}); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); const manifest = await manifestManager.buildNewManifest(); @@ -237,11 +246,16 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); + expect(artifacts.length).toBe(5); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); for (const artifact of artifacts) { expect(await uncompressArtifact(artifact)).toStrictEqual({ entries: [] }); + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); } }); @@ -255,6 +269,7 @@ describe('ManifestManager', () => { [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, }); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); const manifest = await manifestManager.buildNewManifest(); @@ -264,21 +279,25 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); + expect(artifacts.length).toBe(5); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); + expect(await uncompressArtifact(artifacts[0])).toStrictEqual({ + entries: translateToEndpointExceptions([exceptionListItem], 'v1'), + }); + expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ + entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), + }); + for (const artifact of artifacts) { - if (artifact.identifier === ARTIFACT_NAME_EXCEPTIONS_MACOS) { - expect(await uncompressArtifact(artifact)).toStrictEqual({ - entries: translateToEndpointExceptions([exceptionListItem], 'v1'), - }); - } else if (artifact.identifier === 'endpoint-trustlist-linux-v1') { - expect(await uncompressArtifact(artifact)).toStrictEqual({ - entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), - }); - } else { - expect(await uncompressArtifact(artifact)).toStrictEqual({ entries: [] }); - } + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); } }); @@ -291,6 +310,7 @@ describe('ManifestManager', () => { context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, }); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); const oldManifest = await manifestManager.buildNewManifest(); @@ -307,20 +327,89 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); + expect(artifacts.length).toBe(5); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); + expect(artifacts[0]).toStrictEqual(oldManifest.getAllArtifacts()[0]); + expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ + entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), + }); + for (const artifact of artifacts) { - if (artifact.identifier === ARTIFACT_NAME_EXCEPTIONS_MACOS) { - expect(artifact).toStrictEqual(oldManifest.getAllArtifacts()[0]); - } else if (artifact.identifier === 'endpoint-trustlist-linux-v1') { - expect(await uncompressArtifact(artifact)).toStrictEqual({ - entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), - }); - } else { - expect(await uncompressArtifact(artifact)).toStrictEqual({ entries: [] }); - } + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); + } + }); + + test('Builds manifest with policy specific exception list items for trusted apps', async () => { + const exceptionListItem = getExceptionListItemSchemaMock({ os_types: ['macos'] }); + const trustedAppListItem = getExceptionListItemSchemaMock({ os_types: ['linux'] }); + const trustedAppListItemPolicy2 = getExceptionListItemSchemaMock({ + os_types: ['linux'], + entries: [ + { field: 'other.field', operator: 'included', type: 'match', value: 'other value' }, + ], + }); + const context = buildManifestManagerContextMock({}); + const manifestManager = new ManifestManager(context); + + context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ + [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, + [ENDPOINT_TRUSTED_APPS_LIST_ID]: { + linux: [trustedAppListItem], + [`linux-${TEST_POLICY_ID_2}`]: [trustedAppListItem, trustedAppListItemPolicy2], + }, + }); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([ + TEST_POLICY_ID_1, + TEST_POLICY_ID_2, + ]); + + const manifest = await manifestManager.buildNewManifest(); + + expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); + expect(manifest?.getSemanticVersion()).toStrictEqual('1.0.0'); + expect(manifest?.getSavedObjectVersion()).toBeUndefined(); + + const artifacts = manifest.getAllArtifacts(); + + expect(artifacts.length).toBe(6); + expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); + expect(artifacts.every(isCompressed)).toBe(true); + + expect(await uncompressArtifact(artifacts[0])).toStrictEqual({ + entries: translateToEndpointExceptions([exceptionListItem], 'v1'), + }); + expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ + entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), + }); + expect(await uncompressArtifact(artifacts[5])).toStrictEqual({ + entries: translateToEndpointExceptions( + [trustedAppListItem, trustedAppListItemPolicy2], + 'v1' + ), + }); + + for (const artifact of artifacts.slice(0, 4)) { + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1, TEST_POLICY_ID_2]) + ); } + + expect(manifest.isDefaultArtifact(artifacts[5])).toBe(false); + expect(manifest.getArtifactTargetPolicies(artifacts[5])).toStrictEqual( + new Set([TEST_POLICY_ID_2]) + ); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts index 6b9cbb55415a01..f49f2a3e226eef 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts @@ -9,6 +9,7 @@ import semver from 'semver'; import LRU from 'lru-cache'; import { isEqual } from 'lodash'; import { Logger, SavedObjectsClientContract } from 'src/core/server'; +import { ListResult } from '../../../../../../fleet/common'; import { PackagePolicyServiceInterface } from '../../../../../../fleet/server'; import { ExceptionListClient } from '../../../../../../lists/server'; import { ManifestSchemaVersion } from '../../../../../common/endpoint/schema/common'; @@ -21,7 +22,8 @@ import { ArtifactConstants, buildArtifact, getArtifactId, - getFullEndpointExceptionList, + getEndpointExceptionList, + getEndpointTrustedAppsList, isCompressed, Manifest, maybeCompressArtifact, @@ -32,9 +34,45 @@ import { } from '../../../schemas/artifacts'; import { ArtifactClient } from '../artifact_client'; import { ManifestClient } from '../manifest_client'; -import { ENDPOINT_LIST_ID } from '../../../../../../lists/common'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../../lists/common/constants'; -import { PackagePolicy } from '../../../../../../fleet/common/types/models'; + +interface ArtifactsBuildResult { + defaultArtifacts: InternalArtifactCompleteSchema[]; + policySpecificArtifacts: Record; +} + +const iterateArtifactsBuildResult = async ( + result: ArtifactsBuildResult, + callback: (artifact: InternalArtifactCompleteSchema, policyId?: string) => Promise +) => { + for (const artifact of result.defaultArtifacts) { + await callback(artifact); + } + + for (const policyId of Object.keys(result.policySpecificArtifacts)) { + for (const artifact of result.policySpecificArtifacts[policyId]) { + await callback(artifact, policyId); + } + } +}; + +const iterateAllListItems = async ( + pageSupplier: (page: number) => Promise>, + itemCallback: (item: T) => void +) => { + let paging = true; + let page = 1; + + while (paging) { + const { items, total } = await pageSupplier(page); + + for (const item of items) { + await itemCallback(item); + } + + paging = (page - 1) * 20 + items.length < total; + page++; + } +}; export interface ManifestManagerContext { savedObjectsClient: SavedObjectsClientContract; @@ -81,6 +119,19 @@ export class ManifestManager { return new ManifestClient(this.savedObjectsClient, this.schemaVersion); } + /** + * Builds an artifact (one per supported OS) based on the current + * state of exception-list-agnostic SOs. + */ + protected async buildExceptionListArtifact(os: string): Promise { + return buildArtifact( + await getEndpointExceptionList(this.exceptionListClient, this.schemaVersion, os), + this.schemaVersion, + os, + ArtifactConstants.GLOBAL_ALLOWLIST_NAME + ); + } + /** * Builds an array of artifacts (one per supported OS) based on the current * state of exception-list-agnostic SOs. @@ -88,54 +139,60 @@ export class ManifestManager { * @returns {Promise} An array of uncompressed artifacts built from exception-list-agnostic SOs. * @throws Throws/rejects if there are errors building the list. */ - protected async buildExceptionListArtifacts( - artifactSchemaVersion?: string - ): Promise { - const artifacts: InternalArtifactCompleteSchema[] = []; + protected async buildExceptionListArtifacts(): Promise { + const defaultArtifacts: InternalArtifactCompleteSchema[] = []; + const policySpecificArtifacts: Record = {}; + for (const os of ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS) { - const exceptionList = await getFullEndpointExceptionList( - this.exceptionListClient, - os, - artifactSchemaVersion ?? 'v1', - ENDPOINT_LIST_ID - ); - const artifact = await buildArtifact( - exceptionList, - os, - artifactSchemaVersion ?? 'v1', - ArtifactConstants.GLOBAL_ALLOWLIST_NAME - ); - artifacts.push(artifact); + defaultArtifacts.push(await this.buildExceptionListArtifact(os)); } - return artifacts; + + await iterateAllListItems( + (page) => this.listEndpointPolicyIds(page), + async (policyId) => { + policySpecificArtifacts[policyId] = defaultArtifacts; + } + ); + + return { defaultArtifacts, policySpecificArtifacts }; + } + + /** + * Builds an artifact (one per supported OS) based on the current state of the + * Trusted Apps list (which uses the `exception-list-agnostic` SO type) + */ + protected async buildTrustedAppsArtifact(os: string, policyId?: string) { + return buildArtifact( + await getEndpointTrustedAppsList(this.exceptionListClient, this.schemaVersion, os, policyId), + this.schemaVersion, + os, + ArtifactConstants.GLOBAL_TRUSTED_APPS_NAME + ); } /** * Builds an array of artifacts (one per supported OS) based on the current state of the * Trusted Apps list (which uses the `exception-list-agnostic` SO type) - * @param artifactSchemaVersion */ - protected async buildTrustedAppsArtifacts( - artifactSchemaVersion?: string - ): Promise { - const artifacts: InternalArtifactCompleteSchema[] = []; + protected async buildTrustedAppsArtifacts(): Promise { + const defaultArtifacts: InternalArtifactCompleteSchema[] = []; + const policySpecificArtifacts: Record = {}; for (const os of ArtifactConstants.SUPPORTED_TRUSTED_APPS_OPERATING_SYSTEMS) { - const trustedApps = await getFullEndpointExceptionList( - this.exceptionListClient, - os, - artifactSchemaVersion ?? 'v1', - ENDPOINT_TRUSTED_APPS_LIST_ID - ); - const artifact = await buildArtifact( - trustedApps, - os, - 'v1', - ArtifactConstants.GLOBAL_TRUSTED_APPS_NAME - ); - artifacts.push(artifact); + defaultArtifacts.push(await this.buildTrustedAppsArtifact(os)); } - return artifacts; + + await iterateAllListItems( + (page) => this.listEndpointPolicyIds(page), + async (policyId) => { + for (const os of ArtifactConstants.SUPPORTED_TRUSTED_APPS_OPERATING_SYSTEMS) { + policySpecificArtifacts[policyId] = policySpecificArtifacts[policyId] || []; + policySpecificArtifacts[policyId].push(await this.buildTrustedAppsArtifact(os, policyId)); + } + } + ); + + return { defaultArtifacts, policySpecificArtifacts }; } /** @@ -251,32 +308,33 @@ export class ManifestManager { public async buildNewManifest( baselineManifest: Manifest = Manifest.getDefault(this.schemaVersion) ): Promise { - // Build new exception list artifacts - const artifacts = ( - await Promise.all([this.buildExceptionListArtifacts(), this.buildTrustedAppsArtifacts()]) - ).flat(); + const results = await Promise.all([ + this.buildExceptionListArtifacts(), + this.buildTrustedAppsArtifacts(), + ]); - // Build new manifest const manifest = new Manifest({ schemaVersion: this.schemaVersion, semanticVersion: baselineManifest.getSemanticVersion(), soVersion: baselineManifest.getSavedObjectVersion(), }); - for (const artifact of artifacts) { - let artifactToAdd = baselineManifest.getArtifact(getArtifactId(artifact)) || artifact; - - if (!isCompressed(artifactToAdd)) { - artifactToAdd = await maybeCompressArtifact(artifactToAdd); + for (const result of results) { + await iterateArtifactsBuildResult(result, async (artifact, policyId) => { + let artifactToAdd = baselineManifest.getArtifact(getArtifactId(artifact)) || artifact; if (!isCompressed(artifactToAdd)) { - throw new Error(`Unable to compress artifact: ${getArtifactId(artifactToAdd)}`); - } else if (!internalArtifactCompleteSchema.is(artifactToAdd)) { - throw new Error(`Incomplete artifact detected: ${getArtifactId(artifactToAdd)}`); + artifactToAdd = await maybeCompressArtifact(artifactToAdd); + + if (!isCompressed(artifactToAdd)) { + throw new Error(`Unable to compress artifact: ${getArtifactId(artifactToAdd)}`); + } else if (!internalArtifactCompleteSchema.is(artifactToAdd)) { + throw new Error(`Incomplete artifact detected: ${getArtifactId(artifactToAdd)}`); + } } - } - manifest.addEntry(artifactToAdd); + manifest.addEntry(artifactToAdd, policyId); + }); } return manifest; @@ -292,49 +350,52 @@ export class ManifestManager { public async tryDispatch(manifest: Manifest): Promise { const errors: Error[] = []; - await this.forEachPolicy(async (packagePolicy) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { id, revision, updated_at, updated_by, ...newPackagePolicy } = packagePolicy; - if (newPackagePolicy.inputs.length > 0 && newPackagePolicy.inputs[0].config !== undefined) { - const oldManifest = newPackagePolicy.inputs[0].config.artifact_manifest ?? { - value: {}, - }; - - const newManifestVersion = manifest.getSemanticVersion(); - if (semver.gt(newManifestVersion, oldManifest.value.manifest_version)) { - const serializedManifest = manifest.toPackagePolicyManifest(packagePolicy.id); - - if (!manifestDispatchSchema.is(serializedManifest)) { - errors.push(new Error(`Invalid manifest for policy ${packagePolicy.id}`)); - } else if (!manifestsEqual(serializedManifest, oldManifest.value)) { - newPackagePolicy.inputs[0].config.artifact_manifest = { value: serializedManifest }; - - try { - await this.packagePolicyService.update( - this.savedObjectsClient, - // @ts-ignore - undefined, - id, - newPackagePolicy - ); + await iterateAllListItems( + (page) => this.listEndpointPolicies(page), + async (packagePolicy) => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { id, revision, updated_at, updated_by, ...newPackagePolicy } = packagePolicy; + if (newPackagePolicy.inputs.length > 0 && newPackagePolicy.inputs[0].config !== undefined) { + const oldManifest = newPackagePolicy.inputs[0].config.artifact_manifest ?? { + value: {}, + }; + + const newManifestVersion = manifest.getSemanticVersion(); + if (semver.gt(newManifestVersion, oldManifest.value.manifest_version)) { + const serializedManifest = manifest.toPackagePolicyManifest(packagePolicy.id); + + if (!manifestDispatchSchema.is(serializedManifest)) { + errors.push(new Error(`Invalid manifest for policy ${packagePolicy.id}`)); + } else if (!manifestsEqual(serializedManifest, oldManifest.value)) { + newPackagePolicy.inputs[0].config.artifact_manifest = { value: serializedManifest }; + + try { + await this.packagePolicyService.update( + this.savedObjectsClient, + // @ts-ignore + undefined, + id, + newPackagePolicy + ); + this.logger.debug( + `Updated package policy ${id} with manifest version ${manifest.getSemanticVersion()}` + ); + } catch (err) { + errors.push(err); + } + } else { this.logger.debug( - `Updated package policy ${id} with manifest version ${manifest.getSemanticVersion()}` + `No change in manifest content for package policy: ${id}. Staying on old version` ); - } catch (err) { - errors.push(err); } } else { - this.logger.debug( - `No change in manifest content for package policy: ${id}. Staying on old version` - ); + this.logger.debug(`No change in manifest version for package policy: ${id}`); } } else { - this.logger.debug(`No change in manifest version for package policy: ${id}`); + errors.push(new Error(`Package Policy ${id} has no config.`)); } - } else { - errors.push(new Error(`Package Policy ${id} has no config.`)); } - }); + ); return errors; } @@ -363,23 +424,19 @@ export class ManifestManager { this.logger.info(`Committed manifest ${manifest.getSemanticVersion()}`); } - private async forEachPolicy(callback: (policy: PackagePolicy) => Promise) { - let paging = true; - let page = 1; - - while (paging) { - const { items, total } = await this.packagePolicyService.list(this.savedObjectsClient, { - page, - perPage: 20, - kuery: 'ingest-package-policies.package.name:endpoint', - }); - - for (const packagePolicy of items) { - await callback(packagePolicy); - } + private async listEndpointPolicies(page: number) { + return this.packagePolicyService.list(this.savedObjectsClient, { + page, + perPage: 20, + kuery: 'ingest-package-policies.package.name:endpoint', + }); + } - paging = (page - 1) * 20 + items.length < total; - page++; - } + private async listEndpointPolicyIds(page: number) { + return this.packagePolicyService.listIds(this.savedObjectsClient, { + page, + perPage: 20, + kuery: 'ingest-package-policies.package.name:endpoint', + }); } } From 3a003d9b79c31a516c1dc33d113c829a379110dc Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Tue, 16 Feb 2021 15:02:47 -0500 Subject: [PATCH 17/46] [ML] Anomaly Detection: when no anomalies present for time range show no results message (#91151) * single metric viewer callout color to blue.show empty results in explorer. * update snapshot for empty results view * check if selected job still running * update resultsWithAnomalies check * update no overall data message. remove unnecessary component prop --- .../anomaly_detection_jobs/summary_job.ts | 1 + .../explorer_no_results_found.test.js.snap | 10 +-- .../explorer_no_results_found.js | 68 ++++++++++++------- .../explorer/components/no_overall_data.tsx | 2 +- .../public/application/explorer/explorer.js | 13 +++- .../application/routing/routes/explorer.tsx | 4 ++ .../timeseriesexplorer/timeseriesexplorer.js | 1 - 7 files changed, 62 insertions(+), 37 deletions(-) diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts index bb6b331c10fc18..09f5c37ac9aeaf 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts @@ -49,6 +49,7 @@ export type MlSummaryJobs = MlSummaryJob[]; export interface MlJobWithTimeRange extends CombinedJobWithStats { id: string; + isRunning?: boolean; isNotSingleMetricViewerJobMessage?: string; timeRange: { from: number; diff --git a/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/__snapshots__/explorer_no_results_found.test.js.snap b/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/__snapshots__/explorer_no_results_found.test.js.snap index dc7e567380fdf9..388e2f590edf28 100644 --- a/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/__snapshots__/explorer_no_results_found.test.js.snap +++ b/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/__snapshots__/explorer_no_results_found.test.js.snap @@ -14,14 +14,6 @@ exports[`ExplorerNoInfluencersFound snapshot 1`] = ` } iconType="iInCircle" - title={ -

- -

- } + title={

} /> `; diff --git a/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/explorer_no_results_found.js b/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/explorer_no_results_found.js index 6e058a8fc8c610..799437e1799f00 100644 --- a/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/explorer_no_results_found.js +++ b/x-pack/plugins/ml/public/application/explorer/components/explorer_no_results_found/explorer_no_results_found.js @@ -14,26 +14,48 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiEmptyPrompt } from '@elastic/eui'; -export const ExplorerNoResultsFound = () => ( - - -

- } - body={ - -

- -

-
- } - /> -); +export const ExplorerNoResultsFound = ({ hasResults, selectedJobsRunning }) => { + const resultsHaveNoAnomalies = hasResults === true; + const noResults = hasResults === false; + return ( + + {resultsHaveNoAnomalies && ( + + )} + {noResults && ( + + )} + + } + body={ + + {selectedJobsRunning && noResults && ( +

+ +

+ )} + {!selectedJobsRunning && ( +

+ +

+ )} +
+ } + /> + ); +}; diff --git a/x-pack/plugins/ml/public/application/explorer/components/no_overall_data.tsx b/x-pack/plugins/ml/public/application/explorer/components/no_overall_data.tsx index fe77fdf235b58d..65935050ee218a 100644 --- a/x-pack/plugins/ml/public/application/explorer/components/no_overall_data.tsx +++ b/x-pack/plugins/ml/public/application/explorer/components/no_overall_data.tsx @@ -12,7 +12,7 @@ export const NoOverallData: FC = () => { return ( ); }; diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index 9f77260ab3320f..abf8197f51634d 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -142,6 +142,7 @@ export class Explorer extends React.Component { setSelectedCells: PropTypes.func.isRequired, severity: PropTypes.number.isRequired, showCharts: PropTypes.bool.isRequired, + selectedJobsRunning: PropTypes.bool.isRequired, }; state = { filterIconTriggeredQuery: undefined, language: DEFAULT_QUERY_LANG }; @@ -223,7 +224,7 @@ export class Explorer extends React.Component { updateLanguage = (language) => this.setState({ language }); render() { - const { showCharts, severity, stoppedPartitions } = this.props; + const { showCharts, severity, stoppedPartitions, selectedJobsRunning } = this.props; const { annotations, @@ -248,6 +249,9 @@ export class Explorer extends React.Component { const noJobsFound = selectedJobs === null || selectedJobs.length === 0; const hasResults = overallSwimlaneData.points && overallSwimlaneData.points.length > 0; + const hasResultsWithAnomalies = + (hasResults && overallSwimlaneData.points.some((v) => v.value > 0)) || + tableData.anomalies?.length > 0; if (noJobsFound && !loading) { return ( @@ -257,10 +261,13 @@ export class Explorer extends React.Component { ); } - if (noJobsFound && hasResults === false && !loading) { + if (hasResultsWithAnomalies === false && !loading) { return ( - + ); } diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index 052be41ca1eb70..e65ca22effd768 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -87,6 +87,9 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim const timefilter = useTimefilter({ timeRangeSelector: true, autoRefreshSelector: true }); const { jobIds } = useJobSelection(jobsWithTimeRange); + const selectedJobsRunning = jobsWithTimeRange.some( + (job) => jobIds.includes(job.id) && job.isRunning === true + ); const explorerAppState = useObservable(explorerService.appState$); const explorerState = useObservable(explorerService.state$); @@ -261,6 +264,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim severity: tableSeverity.val, stoppedPartitions, invalidTimeRangeError, + selectedJobsRunning, }} /> diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 33e5183fa79493..06a0f7e17e1649 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -1000,7 +1000,6 @@ export class TimeSeriesExplorer extends React.Component { }} /> } - color="warning" iconType="help" size="s" /> From 8126488021b2efd674ea1ddec3c99c24029879f5 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Tue, 16 Feb 2021 14:06:25 -0600 Subject: [PATCH 18/46] Upgrade EUI to v31.7.0 (#91210) * eui to 31.6.0 * flyout, collapsible snapshot updates * initial overlaymask removal * undo jest * overlaymask src snapshot updates * more overlaymask removals * overlaymask removal xpack test updates * saved objects modal form * eui to 31.7.0 * code, codeblock types * snapshot update * tooltip * remove ownFocus from ConfirmModal * remove fragments --- package.json | 2 +- .../collapsible_nav.test.tsx.snap | 18 + .../header/__snapshots__/header.test.tsx.snap | 3 + .../flyout_service.test.tsx.snap | 4 +- .../__snapshots__/modal_service.test.tsx.snap | 248 +++--- .../public/overlays/modal/modal_service.tsx | 22 +- .../application/components/settings_modal.tsx | 181 +++-- .../__snapshots__/clone_modal.test.js.snap | 112 ++- .../application/top_nav/clone_modal.tsx | 117 ++- .../ui/saved_query_form/save_query_form.tsx | 63 +- .../saved_query_list_item.tsx | 60 +- .../confirmation_modal.test.tsx.snap | 18 +- .../confirmation_modal/confirmation_modal.tsx | 20 +- .../confirmation_modal.test.tsx.snap | 62 +- .../confirmation_modal/confirmation_modal.tsx | 58 +- .../components/field_editor/field_editor.tsx | 71 +- .../table_list_view/table_list_view.tsx | 71 +- .../saved_object_save_modal.test.tsx.snap | 704 +++++++++--------- .../save_modal/saved_object_save_modal.tsx | 85 +-- .../components/delete_confirm_modal.tsx | 166 ++--- .../objects_table/components/export_modal.tsx | 143 ++-- .../components/overwrite_modal.tsx | 54 +- .../public/wizard/new_vis_modal.tsx | 4 +- .../List/ConfirmDeleteModal.tsx | 68 +- .../table/controls/action_control.tsx | 62 +- .../public/pages/overview/enrolled_beats.tsx | 101 ++- .../asset_manager/asset_manager.component.tsx | 127 ++-- .../confirm_modal/confirm_modal.tsx | 30 +- .../datasource_preview/datasource_preview.js | 81 +- .../keyboard_shortcuts_doc.stories.storyshot | 2 +- .../saved_elements_modal.component.tsx | 81 +- .../components/toolbar/toolbar.component.tsx | 19 +- .../var_config.stories.storyshot | 3 + .../edit_menu/edit_menu.component.tsx | 14 +- .../__snapshots__/pdf_panel.stories.storyshot | 3 + .../auto_follow_pattern_delete_provider.js | 78 +- .../follower_index_pause_provider.js | 110 ++- .../follower_index_resume_provider.js | 130 ++-- .../follower_index_unfollow_provider.js | 96 ++- .../follower_index_edit.js | 77 +- .../components/actions/delete_button.tsx | 36 +- .../components/actions/extend_button.tsx | 40 +- .../search_experience/customization_modal.tsx | 162 ++-- .../log_retention_confirmation_modal.tsx | 6 +- .../shared/schema/schema_add_field_modal.tsx | 123 ++- .../display_settings/field_editor_modal.tsx | 81 +- .../components/source_settings.tsx | 39 +- .../views/content_sources/sources_view.tsx | 122 ++- .../components/add_group_modal.test.tsx | 3 +- .../groups/components/add_group_modal.tsx | 59 +- .../components/group_manager_modal.test.tsx | 3 +- .../groups/components/group_manager_modal.tsx | 17 +- .../groups/components/group_overview.tsx | 23 +- .../views/security/security.tsx | 23 +- .../settings/components/oauth_application.tsx | 42 +- .../settings/components/source_config.tsx | 31 +- .../components/agent_policy_copy_provider.tsx | 118 ++- .../agent_policy_delete_provider.tsx | 114 ++- .../components/agent_policy_yaml_flyout.tsx | 2 - .../components/confirm_deploy_modal.tsx | 100 ++- .../package_policy_delete_provider.tsx | 128 ++-- .../components/agent_unenroll_modal/index.tsx | 154 ++-- .../components/agent_upgrade_modal/index.tsx | 154 ++-- .../components/confirm_delete_modal.tsx | 54 +- .../settings/confirm_package_install.tsx | 80 +- .../settings/confirm_package_uninstall.tsx | 88 ++- .../add_policy_to_template_confirm_modal.tsx | 79 +- .../components/confirm_delete.tsx | 54 +- .../add_lifecycle_confirm_modal.tsx | 99 ++- .../remove_lifecycle_confirm_modal.tsx | 84 +-- .../component_template_list/delete_modal.tsx | 80 +- .../modal_confirmation_delete_fields.tsx | 98 ++- .../load_mappings/load_mappings_provider.tsx | 109 ++- .../runtime_fields/delete_field_provider.tsx | 32 +- .../constants/data_types_definition.tsx | 4 +- .../components/template_delete_modal.tsx | 166 ++--- .../delete_data_stream_confirmation_modal.tsx | 118 ++- .../index_actions_context_menu.js | 483 ++++++------ .../components/saved_views/create_modal.tsx | 119 ++- .../components/saved_views/update_modal.tsx | 119 ++- .../saved_views/view_list_modal.tsx | 98 ++- .../logs/stream/page_view_log_in_context.tsx | 48 +- .../load_from_json/modal_provider.tsx | 108 ++- .../processor_form/processors/csv.tsx | 4 +- .../processor_form/processors/date.tsx | 6 +- .../processors/date_index_name.tsx | 8 +- .../processor_form/processors/dissect.tsx | 2 +- .../processor_form/processors/geoip.tsx | 4 +- .../processor_form/processors/inference.tsx | 2 +- .../processor_form/processors/user_agent.tsx | 2 +- .../components/processor_remove_modal.tsx | 68 +- .../shared/map_processor_type_to_form.tsx | 2 +- .../tab_documents/reset_documents_modal.tsx | 26 +- .../sections/pipelines_list/delete_modal.tsx | 80 +- .../upload_license.test.tsx.snap | 230 +++--- .../revert_to_basic/revert_to_basic.js | 78 +- .../start_trial/start_trial.tsx | 277 ++++--- .../sections/upload_license/upload_license.js | 69 +- ...confirm_delete_pipeline_modal.test.js.snap | 70 +- .../confirm_delete_pipeline_modal.js | 58 +- .../confirm_delete_modal.test.js.snap | 162 ++-- .../pipeline_list/confirm_delete_modal.js | 36 +- .../layer_control/layer_toc/toc_entry/view.js | 28 +- .../delete_annotation_modal/index.tsx | 54 +- .../delete_job_check_modal.tsx | 119 ++- .../close_job_confirm/close_job_confirm.tsx | 93 ++- .../edit_model_snapshot_flyout.tsx | 33 +- .../revert_model_snapshot_flyout.tsx | 55 +- .../delete_rule_modal.test.js.snap | 56 +- .../select_rule_action/delete_rule_modal.js | 52 +- .../validate_job/validate_job_view.js | 32 +- .../action_delete/delete_action_modal.tsx | 120 ++- .../action_start/start_action_modal.tsx | 60 +- .../action_stop/stop_action_modal.tsx | 62 +- .../models_management/delete_models_modal.tsx | 91 ++- .../source_selection/source_selection.tsx | 120 ++- .../explorer/add_to_dashboard_control.tsx | 181 +++-- .../delete_job_modal/delete_job_modal.tsx | 125 ++-- .../edit_job_flyout/edit_job_flyout.js | 63 +- .../edit_job_flyout/tabs/custom_urls.tsx | 43 +- .../start_datafeed_modal.js | 139 ++-- .../components/reset_query/reset_query.tsx | 60 +- .../advanced_detector_modal/modal_wrapper.tsx | 71 +- .../settings/calendars/edit/new_calendar.js | 18 +- .../settings/calendars/list/calendars_list.js | 61 +- .../delete_filter_list_modal.test.js.snap | 68 +- .../delete_filter_list_modal.js | 46 +- .../components/forecasting_modal/modal.js | 73 +- .../remove_cluster_button_provider.js | 6 +- .../report_info_button.test.tsx.snap | 8 +- .../buttons/report_delete_button.tsx | 26 +- .../confirm_delete_modal.js | 44 +- .../public/components/confirm_modal.tsx | 88 +-- .../invalidate_provider.tsx | 102 ++- .../delete_provider/delete_provider.tsx | 104 ++- .../rule_editor_panel/rule_editor_panel.tsx | 67 +- .../rule_editor_panel/rule_group_title.tsx | 77 +- .../roles/edit_role/delete_role_button.tsx | 76 +- .../confirm_delete/confirm_delete.tsx | 109 ++- .../confirm_delete_users.tsx | 80 +- .../users/edit_user/confirm_delete_users.tsx | 1 - .../users/edit_user/confirm_disable_users.tsx | 1 - .../users/edit_user/confirm_enable_users.tsx | 1 - .../cypress/tasks/timeline.ts | 2 +- .../components/confirm_delete_case/index.tsx | 28 +- .../use_all_cases_modal/all_cases_modal.tsx | 26 +- .../create_case_modal.tsx | 36 +- .../exceptions/add_exception_modal/index.tsx | 241 +++--- .../exceptions/edit_exception_modal/index.tsx | 233 +++--- .../__snapshots__/index.test.tsx.snap | 116 ++- .../components/import_data_modal/index.tsx | 87 ++- .../common/components/inspect/modal.tsx | 37 +- .../__snapshots__/index.test.tsx.snap | 8 + .../modal_all_errors.test.tsx.snap | 90 ++- .../components/toasters/modal_all_errors.tsx | 55 +- .../value_lists_management_modal/modal.tsx | 5 +- .../reference_error_modal.tsx | 44 +- .../rules/all/rules_tables.tsx | 23 +- .../pages/policy/view/policy_details.tsx | 102 ++- .../view/trusted_app_deletion_dialog.tsx | 53 +- .../delete_timeline_modal/index.tsx | 20 +- .../open_timeline_modal/index.tsx | 32 +- .../__snapshots__/index.test.tsx.snap | 6 +- .../timeline/header/title_and_description.tsx | 146 ++-- .../components/policy_delete_provider.tsx | 94 ++- .../components/policy_execute_provider.tsx | 52 +- .../components/repository_delete_provider.tsx | 130 ++-- .../retention_execute_modal_provider.tsx | 50 +- .../retention_update_modal_provider.tsx | 295 ++++---- .../components/snapshot_delete_provider.tsx | 159 ++-- .../repository_details/repository_details.tsx | 4 +- .../confirm_delete_modal.test.tsx.snap | 164 ++-- .../confirm_delete_modal.tsx | 151 ++-- ...irm_alter_active_space_modal.test.tsx.snap | 46 +- .../confirm_alter_active_space_modal.tsx | 56 +- .../components/switch_modal/switch_modal.tsx | 30 +- .../action_delete/delete_action_modal.tsx | 33 +- .../action_start/start_action_modal.tsx | 42 +- .../transform_management_section.tsx | 17 +- .../components/delete_modal_confirmation.tsx | 98 ++- .../connector_add_modal.tsx | 172 ++--- .../alert_form/confirm_alert_close.tsx | 66 +- .../alert_form/confirm_alert_save.tsx | 66 +- .../components/manage_license_modal.tsx | 64 +- .../__snapshots__/donut_chart.test.tsx.snap | 8 + .../confirm_delete.test.tsx.snap | 96 ++- .../ml/__snapshots__/ml_flyout.test.tsx.snap | 2 +- .../monitor/ml/confirm_alert_delete.tsx | 38 +- .../components/monitor/ml/confirm_delete.tsx | 78 +- .../components/confirm_watches_modal.tsx | 48 +- .../components/delete_watches_modal.tsx | 84 +-- yarn.lock | 8 +- 192 files changed, 6996 insertions(+), 7510 deletions(-) diff --git a/package.json b/package.json index 67f1f019e73a3e..33d8f6a9c52806 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "@elastic/datemath": "link:packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary", "@elastic/ems-client": "7.12.0", - "@elastic/eui": "31.4.0", + "@elastic/eui": "31.7.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "^9.0.1-kibana3", "@elastic/node-crypto": "1.2.1", diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 80e23a32ca5570..575a247ffeccb5 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -715,8 +715,11 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
Flyout content
"`; +exports[`FlyoutService openFlyout() renders a flyout to the DOM 2`] = `"
Flyout content
"`; exports[`FlyoutService openFlyout() with a currently active flyout replaces the current flyout with a new one 1`] = ` Array [ @@ -59,4 +59,4 @@ Array [ ] `; -exports[`FlyoutService openFlyout() with a currently active flyout replaces the current flyout with a new one 2`] = `"
Flyout content 2
"`; +exports[`FlyoutService openFlyout() with a currently active flyout replaces the current flyout with a new one 2`] = `"
Flyout content 2
"`; diff --git a/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap b/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap index 7e79725c20307b..d52cc090d5d195 100644 --- a/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap +++ b/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap @@ -11,21 +11,19 @@ Array [ exports[`ModalService openConfirm() renders a mountpoint confirm message 1`] = ` Array [ Array [ - - - - - - - , + + + + + ,
, ], ] @@ -36,18 +34,16 @@ exports[`ModalService openConfirm() renders a mountpoint confirm message 2`] = ` exports[`ModalService openConfirm() renders a string confirm message 1`] = ` Array [ Array [ - - - - Some message - - - , + + + Some message + + ,
, ], ] @@ -58,33 +54,29 @@ exports[`ModalService openConfirm() renders a string confirm message 2`] = `" - - - confirm 1 - - - , + + + confirm 1 + + ,
, ], Array [ - - - - some confirm - - - , + + + some confirm + + ,
, ], ] @@ -93,33 +85,29 @@ Array [ exports[`ModalService openConfirm() with a currently active modal replaces the current modal with the new confirm 1`] = ` Array [ Array [ - - - - - - - , + + + + + ,
, ], Array [ - - - - some confirm - - - , + + + some confirm + + ,
, ], ] @@ -128,18 +116,16 @@ Array [ exports[`ModalService openModal() renders a modal to the DOM 1`] = ` Array [ Array [ - - - - - - - , + + + + + ,
, ], ] @@ -150,33 +136,29 @@ exports[`ModalService openModal() renders a modal to the DOM 2`] = `"
- - - confirm 1 - - - , + + + confirm 1 + + ,
, ], Array [ - - - - some confirm - - - , + + + some confirm + + ,
, ], ] @@ -185,33 +167,29 @@ Array [ exports[`ModalService openModal() with a currently active modal replaces the current modal with a new one 1`] = ` Array [ Array [ - - - - - - - , + + + + + ,
, ], Array [ - - - - - - - , + + + + + ,
, ], ] diff --git a/src/core/public/overlays/modal/modal_service.tsx b/src/core/public/overlays/modal/modal_service.tsx index 1f96e00fef0f89..7e4aee94c958ec 100644 --- a/src/core/public/overlays/modal/modal_service.tsx +++ b/src/core/public/overlays/modal/modal_service.tsx @@ -9,7 +9,7 @@ /* eslint-disable max-classes-per-file */ import { i18n as t } from '@kbn/i18n'; -import { EuiModal, EuiConfirmModal, EuiOverlayMask, EuiConfirmModalProps } from '@elastic/eui'; +import { EuiModal, EuiConfirmModal, EuiConfirmModalProps } from '@elastic/eui'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subject } from 'rxjs'; @@ -137,13 +137,11 @@ export class ModalService { this.activeModal = modal; render( - - - modal.close()}> - - - - , + + modal.close()}> + + + , targetDomElement ); @@ -199,11 +197,9 @@ export class ModalService { }; render( - - - - - , + + + , targetDomElement ); }); diff --git a/src/plugins/console/public/application/components/settings_modal.tsx b/src/plugins/console/public/application/components/settings_modal.tsx index f3c8954d01254b..161b67500b47c7 100644 --- a/src/plugins/console/public/application/components/settings_modal.tsx +++ b/src/plugins/console/public/application/components/settings_modal.tsx @@ -22,7 +22,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSwitch, } from '@elastic/eui'; @@ -151,115 +150,107 @@ export function DevToolsSettingsModal(props: Props) { ) : undefined; return ( - - - - - - - + + + + + + + + + + } + > + { + const val = parseInt(e.target.value, 10); + if (!val) return; + setFontSize(val); + }} + /> + - - + } - > - { - const val = parseInt(e.target.value, 10); - if (!val) return; - setFontSize(val); - }} - /> - + onChange={(e) => setWrapMode(e.target.checked)} + /> + - - - } - onChange={(e) => setWrapMode(e.target.checked)} + - - - + } - > - - } - onChange={(e) => setTripleQuotes(e.target.checked)} - /> - + onChange={(e) => setTripleQuotes(e.target.checked)} + /> + - - } - > - { - const { stateSetter, ...rest } = opts; - return rest; - })} - idToSelectedMap={checkboxIdToSelectedMap} - onChange={(e: any) => { - onAutocompleteChange(e as AutocompleteOptions); - }} + - + } + > + { + const { stateSetter, ...rest } = opts; + return rest; + })} + idToSelectedMap={checkboxIdToSelectedMap} + onChange={(e: any) => { + onAutocompleteChange(e as AutocompleteOptions); + }} + /> + - {pollingFields} - + {pollingFields} + - - - - + + + + - - - - - - + + + + + ); } diff --git a/src/plugins/dashboard/public/application/top_nav/__snapshots__/clone_modal.test.js.snap b/src/plugins/dashboard/public/application/top_nav/__snapshots__/clone_modal.test.js.snap index d289d267a2fd6d..1e029e6960cdfa 100644 --- a/src/plugins/dashboard/public/application/top_nav/__snapshots__/clone_modal.test.js.snap +++ b/src/plugins/dashboard/public/application/top_nav/__snapshots__/clone_modal.test.js.snap @@ -1,65 +1,63 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders DashboardCloneModal 1`] = ` - - - - - - - - - -

- -

-
- - + + + -
- - - - - + + + + +

- - - - +

+
+ + +
+ + + + + + + + +
`; diff --git a/src/plugins/dashboard/public/application/top_nav/clone_modal.tsx b/src/plugins/dashboard/public/application/top_nav/clone_modal.tsx index c1bcad51babf9f..3af186f841a5d0 100644 --- a/src/plugins/dashboard/public/application/top_nav/clone_modal.tsx +++ b/src/plugins/dashboard/public/application/top_nav/clone_modal.tsx @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, EuiText, EuiCallOut, @@ -138,69 +137,67 @@ export class DashboardCloneModal extends React.Component { render() { return ( - - - - - - - - - - -

- -

-
- - - - + + + + + - {this.renderDuplicateTitleCallout()} -
- - - + + +

- - - - - - - - +

+
+ + + + + + {this.renderDuplicateTitleCallout()} +
+ + + + + + + + + + +
); } } diff --git a/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx b/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx index 7873886432cbec..077b9ac47286d9 100644 --- a/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx +++ b/src/plugins/data/public/ui/saved_query_form/save_query_form.tsx @@ -9,7 +9,6 @@ import React, { useEffect, useState, useCallback } from 'react'; import { EuiButtonEmpty, - EuiOverlayMask, EuiModal, EuiButton, EuiModalHeader, @@ -208,37 +207,35 @@ export function SaveQueryForm({ ); return ( - - - - - {i18n.translate('data.search.searchBar.savedQueryFormTitle', { - defaultMessage: 'Save query', - })} - - - - {saveQueryForm} - - - - {i18n.translate('data.search.searchBar.savedQueryFormCancelButtonText', { - defaultMessage: 'Cancel', - })} - - - - {i18n.translate('data.search.searchBar.savedQueryFormSaveButtonText', { - defaultMessage: 'Save', - })} - - - - + + + + {i18n.translate('data.search.searchBar.savedQueryFormTitle', { + defaultMessage: 'Save query', + })} + + + + {saveQueryForm} + + + + {i18n.translate('data.search.searchBar.savedQueryFormCancelButtonText', { + defaultMessage: 'Cancel', + })} + + + + {i18n.translate('data.search.searchBar.savedQueryFormSaveButtonText', { + defaultMessage: 'Save', + })} + + + ); } diff --git a/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx b/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx index 47a2d050a9bfa3..b7ba3215eb5aa3 100644 --- a/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx +++ b/src/plugins/data/public/ui/saved_query_management/saved_query_list_item.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { EuiListGroupItem, EuiConfirmModal, EuiOverlayMask, EuiIconTip } from '@elastic/eui'; +import { EuiListGroupItem, EuiConfirmModal, EuiIconTip } from '@elastic/eui'; import React, { Fragment, useState } from 'react'; import classNames from 'classnames'; @@ -114,36 +114,34 @@ export const SavedQueryListItem = ({ /> {showDeletionConfirmationModal && ( - - { - onDelete(savedQuery); - setShowDeletionConfirmationModal(false); - }} - buttonColor="danger" - onCancel={() => { - setShowDeletionConfirmationModal(false); - }} - /> - + { + onDelete(savedQuery); + setShowDeletionConfirmationModal(false); + }} + buttonColor="danger" + onCancel={() => { + setShowDeletionConfirmationModal(false); + }} + /> )} ); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap index 2b320782cb1634..eaaccdb499b0b4 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap @@ -1,14 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DeleteScritpedFieldConfirmationModal should render normally 1`] = ` - - - + `; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/confirmation_modal.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/confirmation_modal.tsx index 5fbd3118b800bb..36069f408f3543 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/confirmation_modal.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/confirmation_modal/confirmation_modal.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal } from '@elastic/eui'; import { ScriptedFieldItem } from '../../types'; @@ -42,15 +42,13 @@ export const DeleteScritpedFieldConfirmationModal = ({ ); return ( - - - + ); }; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap index 9d92a3689b6983..736dbb611dbbdf 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/__snapshots__/confirmation_modal.test.tsx.snap @@ -1,37 +1,35 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Header should render normally 1`] = ` - - - } - confirmButtonText={ - - } - defaultFocusedButton="confirm" - onCancel={[Function]} - onConfirm={[Function]} - title={ - + } + confirmButtonText={ + + } + defaultFocusedButton="confirm" + onCancel={[Function]} + onConfirm={[Function]} + title={ + - } - /> - + } + /> + } +/> `; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/confirmation_modal.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/confirmation_modal.tsx index 6715d7a6780ae4..fb8d4a38bfe63e 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/confirmation_modal.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/components/confirmation_modal/confirmation_modal.tsx @@ -10,7 +10,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiOverlayMask, EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; interface DeleteFilterConfirmationModalProps { filterToDeleteValue: string; @@ -26,35 +26,33 @@ export const DeleteFilterConfirmationModal = ({ onDeleteFilter, }: DeleteFilterConfirmationModalProps) => { return ( - - - } - onCancel={onCancelConfirmationModal} - onConfirm={onDeleteFilter} - cancelButtonText={ - - } - buttonColor="danger" - confirmButtonText={ - - } - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - /> - + + } + onCancel={onCancelConfirmationModal} + onConfirm={onDeleteFilter} + cancelButtonText={ + + } + buttonColor="danger" + confirmButtonText={ + + } + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + /> ); }; diff --git a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx index f22981de857497..829536063a26c9 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx +++ b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx @@ -25,7 +25,6 @@ import { EuiFormRow, EuiIcon, EuiLink, - EuiOverlayMask, EuiSelect, EuiSpacer, EuiText, @@ -643,42 +642,40 @@ export class FieldEditor extends PureComponent - { - this.hideDeleteModal(); - this.deleteField(); - }} - cancelButtonText={i18n.translate('indexPatternManagement.deleteField.cancelButton', { - defaultMessage: 'Cancel', - })} - confirmButtonText={i18n.translate('indexPatternManagement.deleteField.deleteButton', { - defaultMessage: 'Delete', - })} - buttonColor="danger" - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - > -

- -
-
- - ), - }} - /> -

-
-
+ { + this.hideDeleteModal(); + this.deleteField(); + }} + cancelButtonText={i18n.translate('indexPatternManagement.deleteField.cancelButton', { + defaultMessage: 'Cancel', + })} + confirmButtonText={i18n.translate('indexPatternManagement.deleteField.deleteButton', { + defaultMessage: 'Delete', + })} + buttonColor="danger" + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + > +

+ +
+
+ + ), + }} + /> +

+
) : null; }; diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 7b3322f5f6c2d0..fa0a32fc3d542a 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -21,7 +21,6 @@ import { EuiFlexItem, EuiButton, EuiSpacer, - EuiOverlayMask, EuiConfirmModal, EuiCallOut, EuiBasicTableColumn, @@ -238,42 +237,40 @@ class TableListView extends React.Component - - } - buttonColor="danger" - onCancel={this.closeDeleteModal} - onConfirm={this.deleteSelectedItems} - cancelButtonText={ - - } - confirmButtonText={deleteButton} - defaultFocusedButton="cancel" - > -

- -

-
-
+ + } + buttonColor="danger" + onCancel={this.closeDeleteModal} + onConfirm={this.deleteSelectedItems} + cancelButtonText={ + + } + confirmButtonText={deleteButton} + defaultFocusedButton="cancel" + > +

+ +

+
); } diff --git a/src/plugins/saved_objects/public/save_modal/__snapshots__/saved_object_save_modal.test.tsx.snap b/src/plugins/saved_objects/public/save_modal/__snapshots__/saved_object_save_modal.test.tsx.snap index f88039fbda9bad..1f05ed6b944051 100644 --- a/src/plugins/saved_objects/public/save_modal/__snapshots__/saved_object_save_modal.test.tsx.snap +++ b/src/plugins/saved_objects/public/save_modal/__snapshots__/saved_object_save_modal.test.tsx.snap @@ -1,407 +1,399 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SavedObjectSaveModal should render matching snapshot 1`] = ` - +
- - - - - - - - - + + + - + + + + + - - + - } - labelType="label" - > - + + - - - - - - - - - Save - - - + + + + + + + + + Save + +
-
+ `; exports[`SavedObjectSaveModal should render matching snapshot when custom isValid is set 1`] = ` - +
- - - - + + - - - - - - } - labelType="label" - > - + + + + + - - + - } - labelType="label" - > - + + - - - - - - - - - Save - - - + + + + + + + + + Save + +
-
+ `; exports[`SavedObjectSaveModal should render matching snapshot when custom isValid is set 2`] = ` - +
- - - - + + - - - - - - } - labelType="label" - > - + + + + + - - + - } - labelType="label" - > - + + - - - - - - - - - Save - - - + + + + + + + + + Save + +
-
+ `; exports[`SavedObjectSaveModal should render matching snapshot when given options 1`] = ` - +
- - - - + + - - - - - - - - } - labelType="label" - > - + + + + + + + - - + - } - labelType="label" - > - + + - -
- Hello! Main options -
-
- -
- Hey there! Options on the right -
-
-
-
-
- - - - - - Save - - -
+ } + labelType="label" + > + + +
+ Hello! Main options +
+ + +
+ Hey there! Options on the right +
+
+ + + + + + + + + Save + + -
+ `; diff --git a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx index 39c87c9da60c2b..e476d62a0e793b 100644 --- a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx +++ b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx @@ -21,7 +21,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, EuiSwitch, EuiSwitchEvent, @@ -123,52 +122,48 @@ export class SavedObjectSaveModal extends React.Component ); return ( - +
- - - - - - - - - {this.renderDuplicateTitleCallout(duplicateWarningId)} - - - {!this.props.showDescription && this.props.description && ( - - {this.props.description} - - )} - {formBody} - {this.renderCopyOnSave()} - - - - - - - - - {this.renderConfirmButton()} - - + + + + + + + + {this.renderDuplicateTitleCallout(duplicateWarningId)} + + + {!this.props.showDescription && this.props.description && ( + + {this.props.description} + + )} + {formBody} + {this.renderCopyOnSave()} + + + + + + + + + {this.renderConfirmButton()} +
-
+ ); } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx index f67e7bd0b568cd..f6f00c95d9bf19 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx @@ -53,90 +53,88 @@ export const DeleteConfirmModal: FC = ({ // can't use `EuiConfirmModal` here as the confirm modal body is wrapped // inside a `

` element, causing UI glitches with the table. return ( - - - - - - - - -

- -

- - ( - - - - ), - }, - { - field: 'id', - name: i18n.translate( - 'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName', - { defaultMessage: 'Id' } - ), - }, - { - field: 'meta.title', - name: i18n.translate( - 'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName', - { defaultMessage: 'Title' } - ), - }, - ]} - pagination={true} - sorting={false} + + + + - - - - - - - - - - - - - - - - - - - - - + + + +

+ +

+ + ( + + + + ), + }, + { + field: 'id', + name: i18n.translate( + 'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName', + { defaultMessage: 'Id' } + ), + }, + { + field: 'meta.title', + name: i18n.translate( + 'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName', + { defaultMessage: 'Title' } + ), + }, + ]} + pagination={true} + sorting={false} + /> +
+ + + + + + + + + + + + + + + + + + + ); }; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/export_modal.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/export_modal.tsx index 693fe00ffedccb..0699f77f575219 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/export_modal.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/export_modal.tsx @@ -8,7 +8,6 @@ import React, { FC } from 'react'; import { - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -47,80 +46,78 @@ export const ExportModal: FC = ({ onIncludeReferenceChange, }) => { return ( - - - - + + + + + + + + - - - - - } - labelType="legend" - > - { - onSelectedOptionsChange({ - ...selectedOptions, - ...{ - [optionId]: !selectedOptions[optionId], - }, - }); - }} + id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription" + defaultMessage="Select which types to export" /> - - - - } - checked={includeReferences} - onChange={() => onIncludeReferenceChange(!includeReferences)} + } + labelType="legend" + > + { + onSelectedOptionsChange({ + ...selectedOptions, + ...{ + [optionId]: !selectedOptions[optionId], + }, + }); + }} /> - - - - - - - - - - - - - - - - - - - - - + + + + } + checked={includeReferences} + onChange={() => onIncludeReferenceChange(!includeReferences)} + /> + + + + + + + + + + + + + + + + + + + + ); }; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx index 66753e81ccd3ff..cfe0b2be1d3c05 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx @@ -7,13 +7,7 @@ */ import React, { useState, Fragment, ReactNode } from 'react'; -import { - EuiOverlayMask, - EuiConfirmModal, - EUI_MODAL_CONFIRM_BUTTON, - EuiText, - EuiSuperSelect, -} from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON, EuiText, EuiSuperSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import moment from 'moment'; import { FailedImportConflict } from '../../../lib/resolve_import_errors'; @@ -98,29 +92,27 @@ export const OverwriteModal = ({ conflict, onFinish }: OverwriteModalProps) => { } ); return ( - - onFinish(false)} - onConfirm={() => onFinish(true, destinationId)} - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - maxWidth="500px" - > -

{bodyText}

- {selectControl} -
-
+ onFinish(false)} + onConfirm={() => onFinish(true, destinationId)} + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + maxWidth="500px" + > +

{bodyText}

+ {selectControl} +
); }; diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx index ff352003609a99..d36b734f75be2e 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx @@ -8,7 +8,7 @@ import React from 'react'; -import { EuiModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; @@ -121,7 +121,7 @@ class NewVisModal extends React.Component ); - return {selectionModal}; + return selectionModal; } private onCloseModal = () => { diff --git a/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx index 6554f48ea3c2b3..081a3dbc907c5a 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx @@ -6,7 +6,7 @@ */ import React, { useState } from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { NotificationsStart } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { getOptionLabel } from '../../../../../../common/agent_configuration/all_option'; @@ -29,41 +29,39 @@ export function ConfirmDeleteModal({ config, onCancel, onConfirm }: Props) { const { toasts } = useApmPluginContext().core.notifications; return ( - - { + setIsDeleting(true); + await deleteConfig(config, toasts); + setIsDeleting(false); + onConfirm(); + }} + cancelButtonText={i18n.translate( + 'xpack.apm.agentConfig.deleteModal.cancel', + { defaultMessage: `Cancel` } + )} + confirmButtonText={i18n.translate( + 'xpack.apm.agentConfig.deleteModal.confirm', + { defaultMessage: `Delete` } + )} + confirmButtonDisabled={isDeleting} + buttonColor="danger" + defaultFocusedButton="confirm" + > +

+ {i18n.translate('xpack.apm.agentConfig.deleteModal.text', { + defaultMessage: `You are about to delete the configuration for service "{serviceName}" and environment "{environment}".`, + values: { + serviceName: getOptionLabel(config.service.name), + environment: getOptionLabel(config.service.environment), + }, })} - onCancel={onCancel} - onConfirm={async () => { - setIsDeleting(true); - await deleteConfig(config, toasts); - setIsDeleting(false); - onConfirm(); - }} - cancelButtonText={i18n.translate( - 'xpack.apm.agentConfig.deleteModal.cancel', - { defaultMessage: `Cancel` } - )} - confirmButtonText={i18n.translate( - 'xpack.apm.agentConfig.deleteModal.confirm', - { defaultMessage: `Delete` } - )} - confirmButtonDisabled={isDeleting} - buttonColor="danger" - defaultFocusedButton="confirm" - > -

- {i18n.translate('xpack.apm.agentConfig.deleteModal.text', { - defaultMessage: `You are about to delete the configuration for service "{serviceName}" and environment "{environment}".`, - values: { - serviceName: getOptionLabel(config.service.name), - environment: getOptionLabel(config.service.environment), - }, - })} -

-
-
+

+ ); } diff --git a/x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx b/x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx index c498f9e06e1d36..5badef9a71fe17 100644 --- a/x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx +++ b/x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButton, EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiButton, EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; import { AssignmentActionType } from '../table'; @@ -58,40 +58,38 @@ export class ActionControl extends React.PureComponent {this.state.showModal && ( - - + } + confirmButtonText={ + + } + onConfirm={() => { + actionHandler(action); + this.setState({ showModal: false }); + }} + onCancel={() => this.setState({ showModal: false })} + title={ + warningHeading ? ( + warningHeading + ) : ( - } - confirmButtonText={ - - } - onConfirm={() => { - actionHandler(action); - this.setState({ showModal: false }); - }} - onCancel={() => this.setState({ showModal: false })} - title={ - warningHeading ? ( - warningHeading - ) : ( - - ) - } - > - {warningMessage} - - + ) + } + > + {warningMessage} + )}
); diff --git a/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx b/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx index f09d34eaa6e614..0ab02430e90e61 100644 --- a/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx +++ b/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx @@ -13,7 +13,6 @@ import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; @@ -104,58 +103,56 @@ class BeatsPageComponent extends React.PureComponent { {this.props.location.pathname === '/overview/enrolled_beats/enroll' && ( - - { - this.props.setUrlState({ - enrollmentToken: '', - }); - this.props.goTo(`/overview/enrolled_beats`); - }} - style={{ width: '640px' }} - > - - - - - - - { - const enrollmentTokens = await this.props.libs.tokens.createEnrollmentTokens(); - this.props.setUrlState({ - enrollmentToken: enrollmentTokens[0], - }); - }} - onBeatEnrolled={() => { - this.props.setUrlState({ - enrollmentToken: '', - }); - }} + { + this.props.setUrlState({ + enrollmentToken: '', + }); + this.props.goTo(`/overview/enrolled_beats`); + }} + style={{ width: '640px' }} + > + + + - {!this.props.urlState.enrollmentToken && ( - - { - this.props.goTo('/overview/enrolled_beats'); - }} - > - Done - - - )} - - - + + + + { + const enrollmentTokens = await this.props.libs.tokens.createEnrollmentTokens(); + this.props.setUrlState({ + enrollmentToken: enrollmentTokens[0], + }); + }} + onBeatEnrolled={() => { + this.props.setUrlState({ + enrollmentToken: '', + }); + }} + /> + {!this.props.urlState.enrollmentToken && ( + + { + this.props.goTo('/overview/enrolled_beats'); + }} + > + Done + + + )} + + )} ); diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx index f06c305e47beaa..7795aa9671b83d 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.component.tsx @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiPanel, EuiProgress, EuiSpacer, @@ -75,71 +74,69 @@ export const AssetManager: FC = (props) => { }; return ( - - onClose()} - className="canvasAssetManager canvasModal--fixedSize" - maxWidth="1000px" - > - - - {strings.getModalTitle()} - - - - {isLoading ? ( - - ) : ( - - )} - - - - - -

{strings.getDescription()}

-
- - {assets.length ? ( - - {assets.map((asset) => ( - - ))} - - ) : ( - emptyAssets - )} -
- - - - onClose()} + className="canvasAssetManager canvasModal--fixedSize" + maxWidth="1000px" + > + + + {strings.getModalTitle()} + + + + {isLoading ? ( + + ) : ( + - - - - {strings.getSpaceUsedText(percentageUsed)} - - - - onClose()}> - {strings.getModalCloseButtonLabel()} - - -
-
+ )} + + + + + +

{strings.getDescription()}

+
+ + {assets.length ? ( + + {assets.map((asset) => ( + + ))} + + ) : ( + emptyAssets + )} +
+ + + + + + + + {strings.getSpaceUsedText(percentageUsed)} + + + + onClose()}> + {strings.getModalCloseButtonLabel()} + + + ); }; diff --git a/x-pack/plugins/canvas/public/components/confirm_modal/confirm_modal.tsx b/x-pack/plugins/canvas/public/components/confirm_modal/confirm_modal.tsx index 38be3b8559af2c..521ced0d731f2c 100644 --- a/x-pack/plugins/canvas/public/components/confirm_modal/confirm_modal.tsx +++ b/x-pack/plugins/canvas/public/components/confirm_modal/confirm_modal.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import PropTypes from 'prop-types'; import React, { FunctionComponent } from 'react'; @@ -39,21 +39,19 @@ export const ConfirmModal: FunctionComponent = (props) => { } return ( - - - {message} - - + + {message} + ); }; diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js index 4a5861b41d06cc..a55f73a0874676 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js @@ -8,7 +8,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - EuiOverlayMask, EuiModal, EuiModalBody, EuiModalHeader, @@ -27,48 +26,46 @@ const { DatasourceDatasourcePreview: strings } = ComponentStrings; const { DatasourceDatasourceComponent: datasourceStrings } = ComponentStrings; export const DatasourcePreview = ({ done, datatable }) => ( - - - - {strings.getModalTitle()} - - - -

- {datasourceStrings.getSaveButtonLabel()}, - }} + + + {strings.getModalTitle()} + + + +

+ {datasourceStrings.getSaveButtonLabel()}, + }} + /> +

+
+ + {datatable.type === 'error' ? ( + + ) : ( + + {datatable.rows.length > 0 ? ( + + ) : ( + {strings.getEmptyTitle()}} + titleSize="s" + body={ +

+ {strings.getEmptyFirstLineDescription()} +
+ {strings.getEmptySecondLineDescription()} +

+ } /> -

- - - {datatable.type === 'error' ? ( - - ) : ( - - {datatable.rows.length > 0 ? ( - - ) : ( - {strings.getEmptyTitle()}} - titleSize="s" - body={ -

- {strings.getEmptyFirstLineDescription()} -
- {strings.getEmptySecondLineDescription()} -

- } - /> - )} -
- )} -
-
-
+ )} + + )} + + ); DatasourcePreview.propTypes = { diff --git a/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/__stories__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot b/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/__stories__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot index aea9626d7b57ad..a28986c0418a29 100644 --- a/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/__stories__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/keyboard_shortcuts_doc/__stories__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot @@ -5,7 +5,7 @@ exports[`Storyshots components/KeyboardShortcutsDoc default 1`] = ` data-eui="EuiFocusTrap" >
diff --git a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx index e99cc60dfcaa4b..bc0039245f4322 100644 --- a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx +++ b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.component.tsx @@ -23,7 +23,6 @@ import { EuiEmptyPrompt, EuiFieldSearch, EuiSpacer, - EuiOverlayMask, EuiButton, } from '@elastic/eui'; import { sortBy } from 'lodash'; @@ -117,16 +116,14 @@ export const SavedElementsModal: FunctionComponent = ({ } return ( - - - + ); }; @@ -176,40 +173,34 @@ export const SavedElementsModal: FunctionComponent = ({ return ( - - - - - {strings.getModalTitle()} - - - - - - - {customElementContent} - - - - {strings.getSavedElementsModalCloseButtonLabel()} - - - - + + + + {strings.getModalTitle()} + + + + + + + {customElementContent} + + + + {strings.getSavedElementsModalCloseButtonLabel()} + + + {renderDeleteModal()} {renderEditModal()} diff --git a/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx b/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx index edf7d33eff79c4..6e5c936a113bf8 100644 --- a/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx +++ b/x-pack/plugins/canvas/public/components/toolbar/toolbar.component.tsx @@ -12,7 +12,6 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, - EuiOverlayMask, EuiModal, EuiModalFooter, EuiButton, @@ -93,16 +92,14 @@ export const Toolbar: FC = ({ const openWorkpadManager = () => setShowWorkpadManager(true); const workpadManager = ( - - - - - - {strings.getWorkpadManagerCloseButtonLabel()} - - - - + + + + + {strings.getWorkpadManagerCloseButtonLabel()} + + + ); const trays = { diff --git a/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot b/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot index bf5629596d6b67..6277c599032c1e 100644 --- a/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/var_config/__stories__/__snapshots__/var_config.stories.storyshot @@ -77,8 +77,11 @@ exports[`Storyshots components/Variables/VarConfig default 1`] = `
= ({ )} {isModalVisible ? ( - - - + ) : null} ); diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/__stories__/__snapshots__/pdf_panel.stories.storyshot b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/__stories__/__snapshots__/pdf_panel.stories.storyshot index 4e84a9d5a0d211..010037bee4a0fd 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/__stories__/__snapshots__/pdf_panel.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/__stories__/__snapshots__/pdf_panel.stories.storyshot @@ -150,8 +150,11 @@ exports[`Storyshots components/WorkpadHeader/ShareMenu/PDFPanel default 1`] = `
diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js index b07583837636ed..034e08b5c6ab84 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js @@ -9,7 +9,7 @@ import React, { PureComponent, Fragment } from 'react'; import { connect } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { deleteAutoFollowPattern } from '../store/actions'; import { arrify } from '../../../common/services/utils'; @@ -61,45 +61,43 @@ class AutoFollowPatternDeleteProviderUi extends PureComponent { ); return ( - - {/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} - - {!isSingle && ( - -

- -

-
    - {ids.map((id) => ( -
  • {id}
  • - ))} -
-
- )} -
-
+ // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events + + {!isSingle && ( + +

+ +

+
    + {ids.map((id) => ( +
  • {id}
  • + ))} +
+
+ )} +
); }; diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.js index e84816d0d71af9..34697a80121ccf 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.js @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { pauseFollowerIndex } from '../../store/actions'; import { arrify } from '../../../../common/services/utils'; @@ -69,64 +69,62 @@ class FollowerIndexPauseProviderUi extends PureComponent { const hasCustomSettings = indices.some((index) => !areAllSettingsDefault(index)); return ( - - {/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} - - {hasCustomSettings && ( -

- {isSingle ? ( - + {hasCustomSettings && ( +

+ {isSingle ? ( + - ) : ( - - )} + /> + )} +

+ )} + + {!isSingle && ( + +

+

- )} - - {!isSingle && ( - -

- -

- -
    - {indices.map((index) => ( -
  • {index.name}
  • - ))} -
-
- )} -
-
+ +
    + {indices.map((index) => ( +
  • {index.name}
  • + ))} +
+ + )} + ); }; diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.js index 0517f841599122..91c6cb6e243acd 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.js @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiLink, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal, EuiLink } from '@elastic/eui'; import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; import { routing } from '../../services/routing'; import { resumeFollowerIndex } from '../../store/actions'; @@ -68,77 +68,75 @@ class FollowerIndexResumeProviderUi extends PureComponent { ); return ( - - {/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} - - {isSingle ? ( + // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events + + {isSingle ? ( +

+ + + + ), + }} + /> +

+ ) : ( +

- - - ), - }} + id="xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.multipleResumeDescriptionWithSettingWarning" + defaultMessage="Replication resumes using the default advanced settings." />

- ) : ( - -

- -

-

- -

+

+ +

-
    - {ids.map((id) => ( -
  • {id}
  • - ))} -
-
- )} -
-
+
    + {ids.map((id) => ( +
  • {id}
  • + ))} +
+ + )} + ); }; diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.js index 9b0f0ad3111e03..72d262bcf7af32 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.js @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { unfollowLeaderIndex } from '../../store/actions'; import { arrify } from '../../../../common/services/utils'; @@ -67,58 +67,56 @@ class FollowerIndexUnfollowProviderUi extends PureComponent { ); return ( - - {/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} - - {isSingle ? ( - -

- + {isSingle ? ( + +

+ -

-
- ) : ( - -

- -

-
    - {ids.map((id) => ( -
  • {id}
  • - ))} -
-
- )} -
-
+ /> +

+
    + {ids.map((id) => ( +
  • {id}
  • + ))} +
+ + )} + ); }; diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js index 8fb4fb27006cb9..8d6e47d4004b6e 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js @@ -15,7 +15,6 @@ import { EuiConfirmModal, EuiFlexGroup, EuiFlexItem, - EuiOverlayMask, EuiPageContent, EuiSpacer, } from '@elastic/eui'; @@ -182,47 +181,45 @@ export class FollowerIndexEdit extends PureComponent { ); return ( - - - ) : ( - - ) + -

- {isPaused ? ( - - ) : ( - + ) : ( + + ) + } + > +

+ {isPaused ? ( + + ) : ( + - )} -

-
-
+ /> + )} +

+ ); }; diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx index d505752ec3fad9..6a952d2f8d9d74 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState } from 'react'; @@ -44,24 +44,22 @@ const DeleteConfirm = ({ }); return ( - - { - setIsLoading(true); - await api.sendCancel(id); - onActionComplete(); - }} - confirmButtonText={confirm} - confirmButtonDisabled={isLoading} - cancelButtonText={cancel} - defaultFocusedButton="confirm" - buttonColor="danger" - > - {message} - - + { + setIsLoading(true); + await api.sendCancel(id); + onActionComplete(); + }} + confirmButtonText={confirm} + confirmButtonDisabled={isLoading} + cancelButtonText={cancel} + defaultFocusedButton="confirm" + buttonColor="danger" + > + {message} + ); }; diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx index 381c44b1bf7bef..856e7c8d434835 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState } from 'react'; @@ -52,26 +52,24 @@ const ExtendConfirm = ({ }); return ( - - { - setIsLoading(true); - await api.sendExtend(id, `${newExpiration.toISOString()}`); - setIsLoading(false); - onConfirmDismiss(); - onActionComplete(); - }} - confirmButtonText={confirm} - confirmButtonDisabled={isLoading} - cancelButtonText={extend} - defaultFocusedButton="confirm" - buttonColor="primary" - > - {message} - - + { + setIsLoading(true); + await api.sendExtend(id, `${newExpiration.toISOString()}`); + setIsLoading(false); + onConfirmDismiss(); + onActionComplete(); + }} + confirmButtonText={confirm} + confirmButtonDisabled={isLoading} + cancelButtonText={extend} + defaultFocusedButton="confirm" + buttonColor="primary" + > + {message} + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx index e05fc10053ff1c..9bc838c01f636e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx @@ -20,7 +20,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -62,97 +61,94 @@ export const CustomizationModal: React.FC = ({ ); return ( - - - - - {i18n.translate( - 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.title', + + + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.title', + { + defaultMessage: 'Customize document search', + } + )} + + + + + - - - - - - - - - - - - - - {i18n.translate( - 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.cancel', + fullWidth + helpText={i18n.translate( + 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.filterFields', { - defaultMessage: 'Cancel', + defaultMessage: + 'Faceted values rendered as filters and available as query refinement', } )} - - { - onSave({ - filterFields: selectedFilterFields.map(comboBoxOptionToFieldName), - sortFields: selectedSortFields.map(comboBoxOptionToFieldName), - }); - }} > - {i18n.translate( - 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.save', + + + - - - + > + + + + + + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.cancel', + { + defaultMessage: 'Cancel', + } + )} + + { + onSave({ + filterFields: selectedFilterFields.map(comboBoxOptionToFieldName), + sortFields: selectedSortFields.map(comboBoxOptionToFieldName), + }); + }} + > + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.save', + { + defaultMessage: 'Save', + } + )} + + + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx index ca1fa9a8d0737b..ba79d62cfe615a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { EuiTextColor, EuiOverlayMask } from '@elastic/eui'; +import { EuiTextColor } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { LogRetentionLogic, LogRetentionOptions } from '../../log_retention'; @@ -40,7 +40,7 @@ export const LogRetentionConfirmationModal: React.FC = () => { } return ( - + <> {openedModal === LogRetentionOptions.Analytics && ( { onSave={() => saveLogRetention(LogRetentionOptions.API, false)} /> )} - + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.tsx index bbde6c5d3b55de..bd9b6b51a43b1b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.tsx @@ -20,7 +20,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSelect, EuiSpacer, } from '@elastic/eui'; @@ -79,71 +78,69 @@ export const SchemaAddFieldModal: React.FC = ({ ); return ( - +
- - - {FIELD_NAME_MODAL_TITLE} - - -

{FIELD_NAME_MODAL_DESCRIPTION}

- - - - - + {FIELD_NAME_MODAL_TITLE} + + +

{FIELD_NAME_MODAL_DESCRIPTION}

+ + + + + + - - - - - - updateNewFieldType(e.target.value)} - data-test-subj="SchemaSelect" - /> - - - - -
- - {FIELD_NAME_MODAL_CANCEL} - - {FIELD_NAME_MODAL_ADD_FIELD} - - -
+ autoFocus + isLoading={loading} + data-test-subj="SchemaAddFieldNameField" + /> + + + + + updateNewFieldType(e.target.value)} + data-test-subj="SchemaSelect" + /> + + + + + + + {FIELD_NAME_MODAL_CANCEL} + + {FIELD_NAME_MODAL_ADD_FIELD} + +
-
+ ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx index 9a6af035c1c8d8..717eebf5cf8733 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx @@ -20,7 +20,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSelect, } from '@elastic/eui'; @@ -59,48 +58,46 @@ export const FieldEditorModal: React.FC = () => { const ACTION_LABEL = isEditing ? UPDATE_LABEL : ADD_LABEL; return ( - +
- - - - {ACTION_LABEL} {FIELD_LABEL} - - - - - - setName(e.target.value)} - /> - - - setLabel(e.target.value)} - /> - - - - - {CANCEL_BUTTON} - - {ACTION_LABEL} {FIELD_LABEL} - - - + + + {ACTION_LABEL} {FIELD_LABEL} + + + + + + setName(e.target.value)} + /> + + + setLabel(e.target.value)} + /> + + + + + {CANCEL_BUTTON} + + {ACTION_LABEL} {FIELD_LABEL} + +
-
+ ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx index 75a1779a1fda8e..d99f9a4cb1a463 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx @@ -15,7 +15,6 @@ import { EuiButton, EuiButtonEmpty, EuiConfirmModal, - EuiOverlayMask, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -101,26 +100,24 @@ export const SourceSettings: React.FC = () => { }; const confirmModal = ( - - - , - }} - /> - - + + , + }} + /> + ); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx index c62f0b00258d65..247df5556ada01 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -53,70 +52,65 @@ export const SourcesView: React.FC = ({ children }) => { addedSourceName: string; serviceType: string; }) => ( - - - - - - - - - - {i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.sourcesView.modal.heading', - { - defaultMessage: '{addedSourceName} requires additional configuration', - values: { addedSourceName }, - } - )} - - - - - - -

- - {EXTERNAL_IDENTITIES_LINK} - - ), - }} - /> -

+ + + + + + + + + {i18n.translate('xpack.enterpriseSearch.workplaceSearch.sourcesView.modal.heading', { + defaultMessage: '{addedSourceName} requires additional configuration', + values: { addedSourceName }, + })} + + + + + + +

+ + {EXTERNAL_IDENTITIES_LINK} + + ), + }} + /> +

-

- - {DOCUMENT_PERMISSIONS_LINK} - - ), - }} - /> -

-
-
- - - {UNDERSTAND_BUTTON} - - -
-
+

+ + {DOCUMENT_PERMISSIONS_LINK} + + ), + }} + /> +

+ + + + + {UNDERSTAND_BUTTON} + + + ); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx index 26ac5e484f0d77..784544b0001fa0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiModal } from '@elastic/eui'; import { AddGroupModal } from './add_group_modal'; @@ -36,7 +36,6 @@ describe('AddGroupModal', () => { const wrapper = shallow(); expect(wrapper.find(EuiModal)).toHaveLength(1); - expect(wrapper.find(EuiOverlayMask)).toHaveLength(1); }); it('updates the input value', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx index fb82e9393f2a22..2c5732b4b71573 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -49,37 +48,35 @@ export const AddGroupModal: React.FC<{}> = () => { }; return ( - - -
- - {ADD_GROUP_HEADER} - + + + + {ADD_GROUP_HEADER} + - - - setNewGroupName(e.target.value)} - /> - - + + + setNewGroupName(e.target.value)} + /> + + - - {CANCEL_BUTTON} - - {ADD_GROUP_SUBMIT} - - - -
-
+ + {CANCEL_BUTTON} + + {ADD_GROUP_SUBMIT} + + + + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx index 949ae9d502e73a..7c39414f158eff 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx @@ -13,7 +13,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiOverlayMask, EuiModal, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiModal, EuiEmptyPrompt } from '@elastic/eui'; import { GroupManagerModal } from './group_manager_modal'; @@ -46,7 +46,6 @@ describe('GroupManagerModal', () => { const wrapper = shallow(); expect(wrapper.find(EuiModal)).toHaveLength(1); - expect(wrapper.find(EuiOverlayMask)).toHaveLength(1); }); it('renders empty state', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx index b4317ed9bd417c..1b051394dcdcf6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx @@ -21,7 +21,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -161,14 +160,12 @@ export const GroupManagerModal: React.FC = ({ ); return ( - - - {showEmptyState ? emptyState : modalContent} - - + + {showEmptyState ? emptyState : modalContent} + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx index df9c0b5db9b7d1..375ac7476f9b69 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx @@ -12,7 +12,6 @@ import { useActions, useValues } from 'kea'; import { EuiButton, EuiConfirmModal, - EuiOverlayMask, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -226,18 +225,16 @@ export const GroupOverview: React.FC = () => { {confirmDeleteModalVisible && ( - - - {CONFIRM_REMOVE_DESCRIPTION} - - + + {CONFIRM_REMOVE_DESCRIPTION} + )} { ); const confirmModal = ( - - - {PRIVATE_SOURCES_UPDATE_CONFIRMATION_TEXT} - - + + {PRIVATE_SOURCES_UPDATE_CONFIRMATION_TEXT} + ); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx index 28e7e2a33eaa18..3f2e55d23722c2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx @@ -18,7 +18,6 @@ import { EuiSwitch, EuiCode, EuiSpacer, - EuiOverlayMask, EuiLink, EuiModal, EuiModalBody, @@ -93,25 +92,28 @@ export const OauthApplication: React.FC = () => { }; const licenseModal = ( - - - - - - - -

{LICENSE_MODAL_TITLE}

-
- - {LICENSE_MODAL_DESCRIPTION} - - - {LICENSE_MODAL_LINK} - - -
-
-
+ + + + + + +

{LICENSE_MODAL_TITLE}

+
+ + {LICENSE_MODAL_DESCRIPTION} + + + {LICENSE_MODAL_LINK} + + +
+
); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx index 4ed223931d6a46..47a24e7912c3c9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx @@ -9,7 +9,7 @@ import React, { useEffect, useState } from 'react'; import { useActions, useValues } from 'kea'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Loading } from '../../../../shared/loading'; @@ -56,22 +56,19 @@ export const SourceConfig: React.FC = ({ sourceIndex }) => { header={header} /> {confirmModalVisible && ( - - deleteSourceConfig(serviceType, name)} - onCancel={hideConfirmModal} - buttonColor="danger" - > - {i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.settings.confirmRemoveConfig.message', - { - defaultMessage: - 'Are you sure you want to remove the OAuth configuration for {name}?', - values: { name }, - } - )} - - + deleteSourceConfig(serviceType, name)} + onCancel={hideConfirmModal} + buttonColor="danger" + > + {i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.settings.confirmRemoveConfig.message', + { + defaultMessage: 'Are you sure you want to remove the OAuth configuration for {name}?', + values: { name }, + } + )} + )} ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx index d161dfcc5894c1..2b7ecc75195b0c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useRef, useState } from 'react'; -import { EuiConfirmModal, EuiOverlayMask, EuiFormRow, EuiFieldText } from '@elastic/eui'; +import { EuiConfirmModal, EuiFormRow, EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../types'; @@ -92,75 +92,71 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr } return ( - - - - - } - onCancel={closeModal} - onConfirm={copyAgentPolicy} - cancelButtonText={ + - } - confirmButtonText={ + + } + onCancel={closeModal} + onConfirm={copyAgentPolicy} + cancelButtonText={ + + } + confirmButtonText={ + + } + confirmButtonDisabled={isLoading || !newAgentPolicy.name.trim()} + > +

+ +

+ } - confirmButtonDisabled={isLoading || !newAgentPolicy.name.trim()} + fullWidth > -

- -

- - } + - setNewAgentPolicy({ ...newAgentPolicy, name: e.target.value })} + value={newAgentPolicy.name} + onChange={(e) => setNewAgentPolicy({ ...newAgentPolicy, name: e.target.value })} + /> + + - - - } + } + fullWidth + > + - - setNewAgentPolicy({ ...newAgentPolicy, description: e.target.value }) - } - /> - -
-
+ value={newAgentPolicy.description} + onChange={(e) => setNewAgentPolicy({ ...newAgentPolicy, description: e.target.value })} + /> + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index b03d70a78c51a3..014af7f54d020b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useRef, useState } from 'react'; -import { EuiConfirmModal, EuiOverlayMask, EuiCallOut } from '@elastic/eui'; +import { EuiConfirmModal, EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AGENT_SAVED_OBJECT_TYPE } from '../../../constants'; @@ -110,69 +110,67 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil } return ( - - - } - onCancel={closeModal} - onConfirm={deleteAgentPolicy} - cancelButtonText={ + + } + onCancel={closeModal} + onConfirm={deleteAgentPolicy} + cancelButtonText={ + + } + confirmButtonText={ + isLoading || isLoadingAgentsCount ? ( - } - confirmButtonText={ - isLoading || isLoadingAgentsCount ? ( - - ) : ( - - ) - } - buttonColor="danger" - confirmButtonDisabled={isLoading || isLoadingAgentsCount || !!agentsCount} - > - {isLoadingAgentsCount ? ( + ) : ( - ) : agentsCount ? ( - - - - ) : ( + ) + } + buttonColor="danger" + confirmButtonDisabled={isLoading || isLoadingAgentsCount || !!agentsCount} + > + {isLoadingAgentsCount ? ( + + ) : agentsCount ? ( + - )} - - + + ) : ( + + )} + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx index 63fb1f5b4b6385..9ed4bb6ff6ff4f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx @@ -52,8 +52,6 @@ export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => voi {error.message} ) : ( - // Property 'whiteSpace' does not exist on type 'IntrinsicAttributes & CommonProps & OwnProps & HTMLAttributes & { children?: ReactNode; }'. - // @ts-expect-error linter complains whiteSpace isn't available but docs show it on EuiCodeBlockImpl {fullAgentPolicyToYaml(yamlData!.item)} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx index 02d7a6423edc84..f3d01e6b528cae 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiCallOut, EuiOverlayMask, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { AgentPolicy } from '../../../types'; @@ -18,58 +18,56 @@ export const ConfirmDeployAgentPolicyModal: React.FunctionComponent<{ agentPolicy: AgentPolicy; }> = ({ onConfirm, onCancel, agentCount, agentPolicy }) => { return ( - - - } - onCancel={onCancel} - onConfirm={onConfirm} - cancelButtonText={ - - } - confirmButtonText={ - - } - buttonColor="primary" + + } + onCancel={onCancel} + onConfirm={onConfirm} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor="primary" + > + - -
- + {agentPolicy.name}, - }} - /> -
-
- - -
-
+ values={{ + policyName: {agentPolicy.name}, + }} + /> +
+ + + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx index 2ea94e88ed8c61..80952fee05bb4d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useMemo, useRef, useState } from 'react'; -import { EuiCallOut, EuiConfirmModal, EuiOverlayMask, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useStartServices, sendRequest, sendDeletePackagePolicy, useConfig } from '../../../hooks'; @@ -142,78 +142,76 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ } return ( - - + } + onCancel={closeModal} + onConfirm={deletePackagePolicies} + cancelButtonText={ + + } + confirmButtonText={ + isLoading || isLoadingAgentsCount ? ( - } - onCancel={closeModal} - onConfirm={deletePackagePolicies} - cancelButtonText={ + ) : ( - } - confirmButtonText={ - isLoading || isLoadingAgentsCount ? ( - - ) : ( + ) + } + buttonColor="danger" + confirmButtonDisabled={isLoading || isLoadingAgentsCount} + > + {isLoadingAgentsCount ? ( + + ) : agentsCount ? ( + <> + + } + > {agentPolicy.name}, }} /> - ) - } - buttonColor="danger" - confirmButtonDisabled={isLoading || isLoadingAgentsCount} - > - {isLoadingAgentsCount ? ( - - ) : agentsCount ? ( - <> - - } - > - {agentPolicy.name}, - }} - /> - - - - ) : null} - {!isLoadingAgentsCount && ( - - )} - - + + + + ) : null} + {!isLoadingAgentsCount && ( + + )} + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx index 69bff78d604132..a50cc18d46f550 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx @@ -7,7 +7,7 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiOverlayMask, EuiFormFieldset, EuiCheckbox } from '@elastic/eui'; +import { EuiConfirmModal, EuiFormFieldset, EuiCheckbox } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Agent } from '../../../../types'; import { @@ -81,90 +81,88 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ } return ( - - - ) : ( - - ) - } - onCancel={onClose} - onConfirm={onSubmit} - cancelButtonText={ + - } - confirmButtonDisabled={isSubmitting} - confirmButtonText={ - isSingleAgent ? ( - - ) : ( + ) : ( + + ) + } + onCancel={onClose} + onConfirm={onSubmit} + cancelButtonText={ + + } + confirmButtonDisabled={isSubmitting} + confirmButtonText={ + isSingleAgent ? ( + + ) : ( + + ) + } + buttonColor="danger" + > +

+ {isSingleAgent ? ( + + ) : ( + + )} +

+ - ) - } - buttonColor="danger" + ), + }} > -

- {isSingleAgent ? ( + - ) : ( - - )} -

- - ), - }} - > - - } - checked={forceUnenroll} - onChange={(e) => setForceUnenroll(e.target.checked)} - disabled={useForceUnenroll} - /> - -
-
+ values={{ count: agentCount }} + /> + } + checked={forceUnenroll} + onChange={(e) => setForceUnenroll(e.target.checked)} + disabled={useForceUnenroll} + /> + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx index a836e3ec3149bc..57f4007a002740 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx @@ -7,13 +7,7 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiConfirmModal, - EuiOverlayMask, - EuiBetaBadge, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; +import { EuiConfirmModal, EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Agent } from '../../../../types'; import { @@ -74,85 +68,83 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ } return ( - - - - {isSingleAgent ? ( + + + {isSingleAgent ? ( + + ) : ( + + )} + + + - ) : ( + } + tooltipContent={ - )} - - - - } - tooltipContent={ - - } - /> - - - } - onCancel={onClose} - onConfirm={onSubmit} - cancelButtonText={ + } + /> + + + } + onCancel={onClose} + onConfirm={onSubmit} + cancelButtonText={ + + } + confirmButtonDisabled={isSubmitting} + confirmButtonText={ + isSingleAgent ? ( - } - confirmButtonDisabled={isSubmitting} - confirmButtonText={ - isSingleAgent ? ( - - ) : ( - - ) - } - > -

- {isSingleAgent ? ( - - ) : ( - - )} -

-
-
+ ) : ( + + ) + } + > +

+ {isSingleAgent ? ( + + ) : ( + + )} +

+ ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/confirm_delete_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/confirm_delete_modal.tsx index 22e2e68e6d83e9..565657c70e17f6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/confirm_delete_modal.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/confirm_delete_modal.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiCallOut, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal, EuiCallOut } from '@elastic/eui'; import { EnrollmentAPIKey } from '../../../../types'; interface Props { @@ -19,33 +19,31 @@ interface Props { export const ConfirmEnrollmentTokenDelete = (props: Props) => { const { onCancel, onConfirm, enrollmentKey } = props; return ( - - + - - - + color="danger" + /> + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_install.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_install.tsx index ef3ca3ce664c11..5144b2a6487862 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_install.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_install.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiCallOut, EuiConfirmModal, EuiOverlayMask, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -18,50 +18,48 @@ interface ConfirmPackageInstallProps { export const ConfirmPackageInstall = (props: ConfirmPackageInstallProps) => { const { onCancel, onConfirm, packageName, numOfAssets } = props; return ( - - + } + onCancel={onCancel} + onConfirm={onConfirm} + cancelButtonText={ + + } + confirmButtonText={ + + } + defaultFocusedButton="confirm" + > + - } - onCancel={onCancel} - onConfirm={onConfirm} - cancelButtonText={ - } - confirmButtonText={ - - } - defaultFocusedButton="confirm" - > - - } + /> + +

+ - -

- -

-
-
+

+ ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_uninstall.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_uninstall.tsx index 7688c0269d3588..2def57b0409447 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_uninstall.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/settings/confirm_package_uninstall.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiCallOut, EuiConfirmModal, EuiOverlayMask, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -18,58 +18,56 @@ interface ConfirmPackageUninstallProps { export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) => { const { onCancel, onConfirm, packageName, numOfAssets } = props; return ( - - + } + onCancel={onCancel} + onConfirm={onConfirm} + cancelButtonText={ + + } + confirmButtonText={ + + } + defaultFocusedButton="confirm" + buttonColor="danger" + > + } - onCancel={onCancel} - onConfirm={onConfirm} - cancelButtonText={ - - } - confirmButtonText={ - - } - defaultFocusedButton="confirm" - buttonColor="danger" > - - } - > -

- -

-
-

-
-
+ + +

+ +

+ ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/add_policy_to_template_confirm_modal.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/add_policy_to_template_confirm_modal.tsx index f20ea0f5d1bf46..8971f18ef8e5fe 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/add_policy_to_template_confirm_modal.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/add_policy_to_template_confirm_modal.tsx @@ -13,7 +13,6 @@ import { EuiComboBox, EuiForm, EuiFormRow, - EuiOverlayMask, EuiConfirmModal, EuiFieldText, EuiSpacer, @@ -257,46 +256,44 @@ export const AddPolicyToTemplateConfirmModal: React.FunctionComponent = ( ); return ( - - - -

- {' '} - - } - /> -

-
- - {renderForm()} -
-
+ />{' '} + + } + /> +

+ + + {renderForm()} + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/confirm_delete.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/confirm_delete.tsx index 80039a18ef17a9..e42aa97a10d4f1 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/confirm_delete.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/confirm_delete.tsx @@ -8,7 +8,7 @@ import React, { Component } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { PolicyFromES } from '../../../../../common/types'; import { toasts } from '../../../services/notification'; @@ -50,33 +50,31 @@ export class ConfirmDelete extends Component { values: { name: policyToDelete.name }, }); return ( - - - } - confirmButtonText={ - - } - buttonColor="danger" - > -
- -
-
-
+ + } + confirmButtonText={ + + } + buttonColor="danger" + > +
+ +
+
); } } diff --git a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.tsx b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.tsx index 550cefb488f667..36df4d9527a5c8 100644 --- a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/add_lifecycle_confirm_modal.tsx @@ -16,7 +16,6 @@ import { EuiSelect, EuiForm, EuiFormRow, - EuiOverlayMask, EuiConfirmModal, EuiModal, EuiModalBody, @@ -246,63 +245,59 @@ export class AddLifecyclePolicyConfirmModal extends Component { ); if (!policies.length) { return ( - - - - {title} - + + + {title} + - - + + } + color="warning" + > +

+ - } - color="warning" - > -

- - - -

-
-
-
-
+ +

+ + + ); } return ( - - - } - confirmButtonText={ - - } - > - {this.renderForm()} - - + + } + confirmButtonText={ + + } + > + {this.renderForm()} + ); } } diff --git a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.tsx b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.tsx index 8ce4ac052fce23..2f22a0b347db95 100644 --- a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/remove_lifecycle_confirm_modal.tsx @@ -8,7 +8,7 @@ import React, { Component, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { removeLifecycleForIndex } from '../../application/services/api'; import { showApiError } from '../../application/services/api_errors'; @@ -57,54 +57,52 @@ export class RemoveLifecyclePolicyConfirmModal extends Component { const { closeModal, indexNames } = this.props; return ( - - + } + onCancel={closeModal} + onConfirm={this.removePolicy} + cancelButtonText={ + + } + buttonColor="danger" + confirmButtonText={ + + } + > + +

- } - onCancel={closeModal} - onConfirm={this.removePolicy} - cancelButtonText={ - - } - buttonColor="danger" - confirmButtonText={ - - } - > - -

- -

+

-
    - {indexNames.map((indexName) => ( -
  • {indexName}
  • - ))} -
-
-
-
+
    + {indexNames.map((indexName) => ( +
  • {indexName}
  • + ))} +
+ + ); } } diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/delete_modal.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/delete_modal.tsx index cac26d948b11aa..0b20bebf431436 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/delete_modal.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/delete_modal.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -81,49 +81,47 @@ export const ComponentTemplatesDeleteModal = ({ }; return ( - - + } + onCancel={handleOnCancel} + onConfirm={handleDeleteComponentTemplates} + cancelButtonText={ + + } + confirmButtonText={ + + } + > + <> +

- } - onCancel={handleOnCancel} - onConfirm={handleDeleteComponentTemplates} - cancelButtonText={ - - } - confirmButtonText={ - - } - > - <> -

- -

+

-
    - {componentTemplatesToDelete.map((name) => ( -
  • {name}
  • - ))} -
- -
-
+
    + {componentTemplatesToDelete.map((name) => ( +
  • {name}
  • + ))} +
+ + ); }; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/modal_confirmation_delete_fields.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/modal_confirmation_delete_fields.tsx index e6a7e42c089365..2a65906ea56b40 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/modal_confirmation_delete_fields.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/modal_confirmation_delete_fields.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EuiOverlayMask, EuiBadge, EuiCode } from '@elastic/eui'; +import { EuiConfirmModal, EuiBadge, EuiCode } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { NormalizedFields, NormalizedField } from '../../../types'; @@ -59,55 +59,53 @@ export const ModalConfirmationDeleteFields = ({ : null; return ( - - + <> + {fieldsTree && ( + <> +

+ {i18n.translate( + 'xpack.idxMgmt.mappingsEditor.confirmationModal.deleteFieldsDescription', + { + defaultMessage: 'This will also delete the following fields.', + } + )} +

+ + + )} + {aliases && ( + <> +

+ {i18n.translate( + 'xpack.idxMgmt.mappingsEditor.confirmationModal.deleteAliasesDescription', + { + defaultMessage: 'The following aliases will also be deleted.', + } + )} +

+
    + {aliases.map((aliasPath) => ( +
  • + {aliasPath} +
  • + ))} +
+ )} - buttonColor="danger" - confirmButtonText={confirmButtonText} - > - <> - {fieldsTree && ( - <> -

- {i18n.translate( - 'xpack.idxMgmt.mappingsEditor.confirmationModal.deleteFieldsDescription', - { - defaultMessage: 'This will also delete the following fields.', - } - )} -

- - - )} - {aliases && ( - <> -

- {i18n.translate( - 'xpack.idxMgmt.mappingsEditor.confirmationModal.deleteAliasesDescription', - { - defaultMessage: 'The following aliases will also be deleted.', - } - )} -

-
    - {aliases.map((aliasPath) => ( -
  • - {aliasPath} -
  • - ))} -
- - )} - -
-
+ + ); }; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx index a4c88b1e61b8b4..8f023156456dcb 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx @@ -8,14 +8,7 @@ import React, { useState, useRef, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiConfirmModal, - EuiOverlayMask, - EuiCallOut, - EuiText, - EuiSpacer, - EuiButtonEmpty, -} from '@elastic/eui'; +import { EuiConfirmModal, EuiCallOut, EuiText, EuiSpacer, EuiButtonEmpty } from '@elastic/eui'; import { JsonEditor, OnJsonEditorUpdateHandler } from '../../shared_imports'; import { validateMappings, MappingsValidationError } from '../../lib'; @@ -220,61 +213,55 @@ export const LoadMappingsProvider = ({ onJson, children }: Props) => { {children(openModal)} {state.isModalOpen && ( - - - {view === 'json' ? ( - // The CSS override for the EuiCodeEditor requires a parent .application css class -
- - mappings, - }} - /> - - - - - + {view === 'json' ? ( + // The CSS override for the EuiCodeEditor requires a parent .application css class +
+ + mappings, }} /> -
- ) : ( - <> - - -

{i18nTexts.validationErrors.description}

-
- -
    - {state.errors!.slice(0, totalErrorsToDisplay).map((error, i) => ( -
  1. {getErrorMessage(error)}
  2. - ))} -
- {state.errors!.length > MAX_ERRORS_TO_DISPLAY && renderErrorsFilterButton()} -
- - )} - - + + + + + +
+ ) : ( + <> + + +

{i18nTexts.validationErrors.description}

+
+ +
    + {state.errors!.slice(0, totalErrorsToDisplay).map((error, i) => ( +
  1. {getErrorMessage(error)}
  2. + ))} +
+ {state.errors!.length > MAX_ERRORS_TO_DISPLAY && renderErrorsFilterButton()} +
+ + )} +
)} ); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/runtime_fields/delete_field_provider.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/runtime_fields/delete_field_provider.tsx index e48172c417d0ad..f9ecca1f8cb61b 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/runtime_fields/delete_field_provider.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/runtime_fields/delete_field_provider.tsx @@ -7,7 +7,7 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { useDispatch } from '../../mappings_state_context'; import { NormalizedRuntimeField } from '../../types'; @@ -68,22 +68,20 @@ export const DeleteRuntimeFieldProvider = ({ children }: Props) => { {children(deleteField)} {state.isModalOpen && ( - - - + )} ); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx index 2f49e95a1bd62a..d7db98731427db 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx @@ -86,7 +86,7 @@ export const TYPE_DEFINITION: { [key in DataType]: DataTypeDefinition } = { id="xpack.idxMgmt.mappingsEditor.dataType.constantKeywordLongDescription" defaultMessage="Constant keyword fields are a special type of keyword fields for fields that contain the same keyword across all documents in the index. Supports the same queries and aggregations as {keyword} fields." values={{ - keyword: {'keyword'}, + keyword: {'keyword'}, }} />

@@ -836,7 +836,7 @@ export const TYPE_DEFINITION: { [key in DataType]: DataTypeDefinition } = { id="xpack.idxMgmt.mappingsEditor.dataType.pointLongDescription" defaultMessage="Point fields enable searching of {code} pairs that fall in a 2-dimensional planar coordinate system." values={{ - code: {'x,y'}, + code: {'x,y'}, }} />

diff --git a/x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx b/x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx index 0dc2407d22c294..f22fa2a3b4f8a5 100644 --- a/x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useState } from 'react'; -import { EuiConfirmModal, EuiOverlayMask, EuiCallOut, EuiCheckbox, EuiBadge } from '@elastic/eui'; +import { EuiConfirmModal, EuiCallOut, EuiCheckbox, EuiBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -81,95 +81,93 @@ export const TemplateDeleteModal = ({ }; return ( - - - } - onCancel={handleOnCancel} - onConfirm={handleDeleteTemplates} - cancelButtonText={ - - } - confirmButtonText={ + + } + onCancel={handleOnCancel} + onConfirm={handleDeleteTemplates} + cancelButtonText={ + + } + confirmButtonText={ + + } + confirmButtonDisabled={hasSystemTemplate ? !isDeleteConfirmed : false} + > + +

- } - confirmButtonDisabled={hasSystemTemplate ? !isDeleteConfirmed : false} - > - -

- -

+

-
    - {templatesToDelete.map(({ name }) => ( -
  • - {name} - {name.startsWith('.') ? ( - - {' '} - - - - - ) : null} -
  • - ))} -
- {hasSystemTemplate && ( - + {templatesToDelete.map(({ name }) => ( +
  • + {name} + {name.startsWith('.') ? ( + + {' '} + + + + + ) : null} +
  • + ))} + + {hasSystemTemplate && ( + + } + color="danger" + iconType="alert" + data-test-subj="deleteSystemTemplateCallOut" + > +

    + +

    + } - color="danger" - iconType="alert" - data-test-subj="deleteSystemTemplateCallOut" - > -

    - -

    - - } - checked={isDeleteConfirmed} - onChange={(e) => setIsDeleteConfirmed(e.target.checked)} - /> -
    - )} -
    -
    -
    + checked={isDeleteConfirmed} + onChange={(e) => setIsDeleteConfirmed(e.target.checked)} + /> + + )} + +
    ); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/delete_data_stream_confirmation_modal/delete_data_stream_confirmation_modal.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/delete_data_stream_confirmation_modal/delete_data_stream_confirmation_modal.tsx index 7475a87ca24d99..f555706a28cdd4 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/delete_data_stream_confirmation_modal/delete_data_stream_confirmation_modal.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/delete_data_stream_confirmation_modal/delete_data_stream_confirmation_modal.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment } from 'react'; -import { EuiCallOut, EuiConfirmModal, EuiOverlayMask, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -82,69 +82,67 @@ export const DeleteDataStreamConfirmationModal: React.FunctionComponent = }; return ( - - - } - onCancel={() => onClose()} - onConfirm={handleDeleteDataStreams} - cancelButtonText={ - - } - confirmButtonText={ - - } - > - - - } - color="danger" - iconType="alert" - > -

    - -

    -
    - - - + + } + onCancel={() => onClose()} + onConfirm={handleDeleteDataStreams} + cancelButtonText={ + + } + confirmButtonText={ + + } + > + + + } + color="danger" + iconType="alert" + >

    +
    + + + +

    + +

    -
      - {dataStreams.map((name) => ( -
    • {name}
    • - ))} -
    -
    -
    -
    +
      + {dataStreams.map((name) => ( +
    • {name}
    • + ))} +
    + + ); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js index 6282469b092669..20a4af59bab111 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js @@ -20,7 +20,6 @@ import { EuiPopover, EuiSpacer, EuiConfirmModal, - EuiOverlayMask, EuiCheckbox, } from '@elastic/eui'; @@ -301,102 +300,97 @@ export class IndexActionsContextMenu extends Component { const selectedIndexCount = indexNames.length; return ( - - { - if (!this.forcemergeSegmentsError()) { - this.closePopoverAndExecute(() => { - forcemergeIndices(this.state.forcemergeSegments); - this.setState({ - forcemergeSegments: null, - showForcemergeSegmentsModal: null, - }); + { + if (!this.forcemergeSegmentsError()) { + this.closePopoverAndExecute(() => { + forcemergeIndices(this.state.forcemergeSegments); + this.setState({ + forcemergeSegments: null, + showForcemergeSegmentsModal: null, }); - } - }} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.forceMerge.confirmModal.cancelButtonText', - { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.forceMerge.confirmModal.confirmButtonText', + }); + } + }} + cancelButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.forceMerge.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel', + } + )} + confirmButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.forceMerge.confirmModal.confirmButtonText', + { + defaultMessage: 'Force merge', + } + )} + > +

    + +

    + +
      + {indexNames.map((indexName) => ( +
    • {indexName}
    • + ))} +
    + +

    -

    - -
      - {indexNames.map((indexName) => ( -
    • {indexName}
    • - ))} -
    - - -

    - -

    -
    + /> +

    +
    - + - + - - { - this.setState({ forcemergeSegments: event.target.value }); - }} - min={1} - name="maxNumberSegments" - /> - - -
    -
    + { + this.setState({ forcemergeSegments: event.target.value }); + }} + min={1} + name="maxNumberSegments" + /> + + + ); }; @@ -494,39 +488,37 @@ export class IndexActionsContextMenu extends Component { ); return ( - - { - this.confirmAction(false); - this.closeConfirmModal(); - }} - onConfirm={() => this.closePopoverAndExecute(deleteIndices)} - buttonColor="danger" - confirmButtonDisabled={hasSystemIndex ? !isActionConfirmed : false} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.cancelButtonText', - { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.confirmButtonText', - { - defaultMessage: 'Delete {selectedIndexCount, plural, one {index} other {indices} }', - values: { selectedIndexCount }, - } - )} - > - {hasSystemIndex ? systemIndexModalBody : standardIndexModalBody} - - + { + this.confirmAction(false); + this.closeConfirmModal(); + }} + onConfirm={() => this.closePopoverAndExecute(deleteIndices)} + buttonColor="danger" + confirmButtonDisabled={hasSystemIndex ? !isActionConfirmed : false} + cancelButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel', + } + )} + confirmButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.confirmButtonText', + { + defaultMessage: 'Delete {selectedIndexCount, plural, one {index} other {indices} }', + values: { selectedIndexCount }, + } + )} + > + {hasSystemIndex ? systemIndexModalBody : standardIndexModalBody} + ); }; @@ -536,96 +528,91 @@ export class IndexActionsContextMenu extends Component { const selectedIndexCount = indexNames.length; return ( - - { + this.confirmAction(false); + this.closeConfirmModal(); + }} + onConfirm={() => this.closePopoverAndExecute(closeIndices)} + buttonColor="danger" + confirmButtonDisabled={!isActionConfirmed} + cancelButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel', + } + )} + confirmButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.closeIndex.confirmModal.confirmButtonText', + { + defaultMessage: 'Close {selectedIndexCount, plural, one {index} other {indices} }', + values: { selectedIndexCount }, + } + )} + > +

    + +

    + +
      + {indexNames.map((indexName) => ( +
    • + {indexName} + {isSystemIndexByName[indexName] ? ( + + {' '} + + + + + ) : ( + '' + )} +
    • + ))} +
    + + { - this.confirmAction(false); - this.closeConfirmModal(); - }} - onConfirm={() => this.closePopoverAndExecute(closeIndices)} - buttonColor="danger" - confirmButtonDisabled={!isActionConfirmed} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.cancelButtonText', + 'xpack.idxMgmt.indexActionsMenu.closeIndex.proceedWithCautionCallOutTitle', { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.closeIndex.confirmModal.confirmButtonText', - { - defaultMessage: 'Close {selectedIndexCount, plural, one {index} other {indices} }', - values: { selectedIndexCount }, + defaultMessage: 'Closing a system index can break Kibana', } )} + color="danger" + iconType="alert" >

    - -
      - {indexNames.map((indexName) => ( -
    • - {indexName} - {isSystemIndexByName[indexName] ? ( - - {' '} - - - - - ) : ( - '' - )} -
    • - ))} -
    - - -

    + -

    - - } - checked={isActionConfirmed} - onChange={(e) => this.confirmAction(e.target.checked)} - /> -
    -
    -
    + } + checked={isActionConfirmed} + onChange={(e) => this.confirmAction(e.target.checked)} + /> + + ); }; @@ -633,71 +620,69 @@ export class IndexActionsContextMenu extends Component { const { freezeIndices, indexNames } = this.props; return ( - - this.closePopoverAndExecute(freezeIndices)} + cancelButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel', + } + )} + confirmButtonText={i18n.translate( + 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.confirmButtonText', + { + defaultMessage: 'Freeze {count, plural, one {index} other {indices}}', + values: { + count: indexNames.length, + }, + } + )} + > +

    + +

    + +
      + {indexNames.map((indexName) => ( +
    • {indexName}
    • + ))} +
    + + this.closePopoverAndExecute(freezeIndices)} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.cancelButtonText', - { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.confirmButtonText', + 'xpack.idxMgmt.indexActionsMenu.freezeEntity.proceedWithCautionCallOutTitle', { - defaultMessage: 'Freeze {count, plural, one {index} other {indices}}', - values: { - count: indexNames.length, - }, + defaultMessage: 'Proceed with caution', } )} + color="warning" + iconType="help" >

    -

    - -
      - {indexNames.map((indexName) => ( -
    • {indexName}
    • - ))} -
    - - -

    - -

    -
    -
    -
    + /> +

    + + ); }; diff --git a/x-pack/plugins/infra/public/components/saved_views/create_modal.tsx b/x-pack/plugins/infra/public/components/saved_views/create_modal.tsx index 985db9872ef3f6..654cba0721bb8a 100644 --- a/x-pack/plugins/infra/public/components/saved_views/create_modal.tsx +++ b/x-pack/plugins/infra/public/components/saved_views/create_modal.tsx @@ -16,7 +16,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiFieldText, EuiSpacer, EuiSwitch, @@ -40,69 +39,67 @@ export const SavedViewCreateModal = ({ close, save, isInvalid }: Props) => { }, [includeTime, save, viewName]); return ( - - - - - - - - - - + + + - - - } - checked={includeTime} - onChange={onCheckChange} - /> - - - - - + + - - + + + + - - - - - - - + } + checked={includeTime} + onChange={onCheckChange} + /> + + + + + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/infra/public/components/saved_views/update_modal.tsx b/x-pack/plugins/infra/public/components/saved_views/update_modal.tsx index 15d0d162604a4b..c6d87d9a8ca158 100644 --- a/x-pack/plugins/infra/public/components/saved_views/update_modal.tsx +++ b/x-pack/plugins/infra/public/components/saved_views/update_modal.tsx @@ -16,7 +16,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiFieldText, EuiSpacer, EuiSwitch, @@ -46,69 +45,67 @@ export function SavedViewUpdateModal - - - - - - - - - + + + - - - } - checked={includeTime} - onChange={onCheckChange} - /> - - - - - + + - - + + + + - - - - - - -
    + } + checked={includeTime} + onChange={onCheckChange} + /> + + + + + + + + + + + + + + + ); } diff --git a/x-pack/plugins/infra/public/components/saved_views/view_list_modal.tsx b/x-pack/plugins/infra/public/components/saved_views/view_list_modal.tsx index 9ab742d720eb5e..aad50c4dcb45d0 100644 --- a/x-pack/plugins/infra/public/components/saved_views/view_list_modal.tsx +++ b/x-pack/plugins/infra/public/components/saved_views/view_list_modal.tsx @@ -9,13 +9,7 @@ import React, { useCallback, useState, useMemo } from 'react'; import { EuiButtonEmpty, EuiModalFooter, EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiOverlayMask, - EuiModal, - EuiModalHeader, - EuiModalHeaderTitle, - EuiModalBody, -} from '@elastic/eui'; +import { EuiModal, EuiModalHeader, EuiModalHeaderTitle, EuiModalBody } from '@elastic/eui'; import { EuiSelectable } from '@elastic/eui'; import { EuiSelectableOption } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -64,51 +58,49 @@ export function SavedViewListModal - - - - - - - - - {(list, search) => ( - <> - {search} -
    {list}
    - - )} -
    -
    - - - - - - - - -
    - + + + + + + + + + {(list, search) => ( + <> + {search} +
    {list}
    + + )} +
    +
    + + + + + + + + +
    ); } diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_view_log_in_context.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_view_log_in_context.tsx index df21a66a5226f4..5537ef9541f892 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_view_log_in_context.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_view_log_in_context.tsx @@ -9,7 +9,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiModal, - EuiOverlayMask, EuiText, EuiTextColor, EuiToolTip, @@ -51,33 +50,26 @@ export const PageViewLogInContext: React.FC = () => { } return ( - - - - - - - - - - - - - - + + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/load_from_json/modal_provider.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/load_from_json/modal_provider.tsx index 10da326322ad4d..c0f9c758fc2785 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/load_from_json/modal_provider.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/load_from_json/modal_provider.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { FunctionComponent, useRef, useState, useCallback } from 'react'; -import { EuiConfirmModal, EuiOverlayMask, EuiSpacer, EuiText, EuiCallOut } from '@elastic/eui'; +import { EuiConfirmModal, EuiSpacer, EuiText, EuiCallOut } from '@elastic/eui'; import { JsonEditor, OnJsonEditorUpdateHandler } from '../../../../../shared_imports'; @@ -78,64 +78,62 @@ export const ModalProvider: FunctionComponent = ({ onDone, children }) => <> {children(() => setIsModalVisible(true))} {isModalVisible ? ( - - { + { + setIsModalVisible(false); + }} + onConfirm={async () => { + try { + const json = jsonContent.current.data.format(); + const { processors, on_failure: onFailure } = json; + // This function will throw if it cannot parse the pipeline object + deserialize({ processors, onFailure }); + onDone(json as any); setIsModalVisible(false); - }} - onConfirm={async () => { - try { - const json = jsonContent.current.data.format(); - const { processors, on_failure: onFailure } = json; - // This function will throw if it cannot parse the pipeline object - deserialize({ processors, onFailure }); - onDone(json as any); - setIsModalVisible(false); - } catch (e) { - setError(e); - } - }} - cancelButtonText={i18nTexts.buttons.cancel} - confirmButtonDisabled={!isValidJson} - confirmButtonText={i18nTexts.buttons.confirm} - maxWidth={600} - > -
    - - - + } catch (e) { + setError(e); + } + }} + cancelButtonText={i18nTexts.buttons.cancel} + confirmButtonDisabled={!isValidJson} + confirmButtonText={i18nTexts.buttons.confirm} + maxWidth={600} + > +
    + + + - + - {error && ( - <> - - {i18nTexts.error.body} - - - - )} + {error && ( + <> + + {i18nTexts.error.body} + + + + )} - -
    - - + +
    +
    ) : undefined} ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/csv.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/csv.tsx index d6cf2d0ae05e89..19176a27a07781 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/csv.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/csv.tsx @@ -85,7 +85,7 @@ const fieldsConfig: FieldsConfig = { {','} }} + values={{ value: {','} }} /> ), }, @@ -104,7 +104,7 @@ const fieldsConfig: FieldsConfig = { {'"'} }} + values={{ value: {'"'} }} /> ), }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date.tsx index 17af47f1569e04..e8e956daff2074 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date.tsx @@ -61,7 +61,7 @@ const fieldsConfig: FieldsConfig = { {'UTC'} }} + values={{ timezone: {'UTC'} }} /> ), }, @@ -75,7 +75,7 @@ const fieldsConfig: FieldsConfig = { {'ENGLISH'} }} + values={{ timezone: {'ENGLISH'} }} /> ), }, @@ -102,7 +102,7 @@ export const DateProcessor: FunctionComponent = () => { id="xpack.ingestPipelines.pipelineEditor.dateForm.targetFieldHelpText" defaultMessage="Output field. If empty, the input field is updated in place. Defaults to {defaultField}." values={{ - defaultField: {'@timestamp'}, + defaultField: {'@timestamp'}, }} /> } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date_index_name.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date_index_name.tsx index d4b1ec876bfd50..182b9ecd845e92 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date_index_name.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/date_index_name.tsx @@ -82,7 +82,7 @@ const fieldsConfig: FieldsConfig = { {'yyyy-MM-dd'} }} + values={{ value: {'yyyy-MM-dd'} }} /> ), }, @@ -102,7 +102,7 @@ const fieldsConfig: FieldsConfig = { {"yyyy-MM-dd'T'HH:mm:ss.SSSXX"} }} + values={{ value: {"yyyy-MM-dd'T'HH:mm:ss.SSSXX"} }} /> ), }, @@ -119,7 +119,7 @@ const fieldsConfig: FieldsConfig = { {'UTC'} }} + values={{ timezone: {'UTC'} }} /> ), }, @@ -136,7 +136,7 @@ const fieldsConfig: FieldsConfig = { {'ENGLISH'} }} + values={{ locale: {'ENGLISH'} }} /> ), }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx index 609ce8a1f8ae63..641a6e73d90251 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx @@ -82,7 +82,7 @@ const getFieldsConfig = (esDocUrl: string): Record => { {'""'} }} + values={{ value: {'""'} }} /> ), }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/geoip.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/geoip.tsx index 2f0699fac729d8..7848872800df45 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/geoip.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/geoip.tsx @@ -31,8 +31,8 @@ const fieldsConfig: FieldsConfig = { id="xpack.ingestPipelines.pipelineEditor.geoIPForm.databaseFileHelpText" defaultMessage="GeoIP2 database file in the {ingestGeoIP} configuration directory. Defaults to {databaseFile}." values={{ - databaseFile: {'GeoLite2-City.mmdb'}, - ingestGeoIP: {'ingest-geoip'}, + databaseFile: {'GeoLite2-City.mmdb'}, + ingestGeoIP: {'ingest-geoip'}, }} /> ), diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx index 2b14a79afb8df1..9575e6d690e006 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx @@ -168,7 +168,7 @@ export const Inference: FunctionComponent = () => { {'ml.inference.'} }} + values={{ targetField: {'ml.inference.'} }} /> } /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx index 4309df214410b2..d14048c4e00dce 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/user_agent.tsx @@ -66,7 +66,7 @@ export const UserAgent: FunctionComponent = () => { id="xpack.ingestPipelines.pipelineEditor.userAgentForm.targetFieldHelpText" defaultMessage="Output field. Defaults to {defaultField}." values={{ - defaultField: {'user_agent'}, + defaultField: {'user_agent'}, }} /> } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_remove_modal.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_remove_modal.tsx index eb5a1baac78fb9..26ae69ead3b5b6 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_remove_modal.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_remove_modal.tsx @@ -7,7 +7,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { ProcessorInternal, ProcessorSelector } from '../types'; interface Props { @@ -18,39 +18,37 @@ interface Props { export const ProcessorRemoveModal = ({ processor, onResult, selector }: Props) => { return ( - - - } - onCancel={() => onResult({ confirmed: false, selector })} - onConfirm={() => onResult({ confirmed: true, selector })} - cancelButtonText={ - - } - confirmButtonText={ - - } - > -

    - -

    -
    -
    + + } + onCancel={() => onResult({ confirmed: false, selector })} + onConfirm={() => onResult({ confirmed: true, selector })} + cancelButtonText={ + + } + confirmButtonText={ + + } + > +

    + +

    +
    ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index aac4da7c16bbf0..9095ab1927cb98 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -135,7 +135,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { {'my-index-yyyy-MM-dd'} }} + values={{ value: {'my-index-yyyy-MM-dd'} }} /> ), }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/reset_documents_modal.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/reset_documents_modal.tsx index 305ccce4e31b5a..d71a6fb80bde1e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/reset_documents_modal.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/reset_documents_modal.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; interface Props { confirmResetTestOutput: () => void; @@ -46,18 +46,16 @@ export const ResetDocumentsModal: FunctionComponent = ({ closeModal, }) => { return ( - - -

    {i18nTexts.modalDescription}

    -
    -
    + +

    {i18nTexts.modalDescription}

    +
    ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx index 230cc52a1c1696..63cf7af2737aa3 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -78,49 +78,47 @@ export const PipelineDeleteModal = ({ }; return ( - - + } + onCancel={handleOnCancel} + onConfirm={handleDeletePipelines} + cancelButtonText={ + + } + confirmButtonText={ + + } + > + <> +

    - } - onCancel={handleOnCancel} - onConfirm={handleDeletePipelines} - cancelButtonText={ - - } - confirmButtonText={ - - } - > - <> -

    - -

    +

    -
      - {pipelinesToDelete.map((name) => ( -
    • {name}
    • - ))} -
    - -
    -
    +
      + {pipelinesToDelete.map((name) => ( +
    • {name}
    • + ))} +
    + +
    ); }; diff --git a/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap b/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap index 9db44bd8225ea2..bc69ab5352a4f5 100644 --- a/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap +++ b/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap @@ -296,140 +296,140 @@ exports[`UploadLicense should display a modal when license requires acknowledgem className="euiSpacer euiSpacer--l" />
    - - -
    + + } + confirmButtonText={ + + } + onCancel={[Function]} + onConfirm={[Function]} + title={ + + } + > + + + -
    -
    - Confirm License Upload -
    -
    -
    +
    -
    -
    - } - > - - } - confirmButtonText={ - - } - onCancel={[Function]} - onConfirm={[Function]} - title={ - - } - > -
    -
    -
    - - + + + +
    - - } - onCancel={cancelStartBasicLicense} - onConfirm={() => startBasicLicense(licenseType, true)} - cancelButtonText={ - - } - confirmButtonText={ - - } - > -
    - {firstLine} - -
      - {messages.map((message) => ( -
    • {message}
    • - ))} -
    -
    -
    -
    - + + } + onCancel={cancelStartBasicLicense} + onConfirm={() => startBasicLicense(licenseType, true)} + cancelButtonText={ + + } + confirmButtonText={ + + } + > +
    + {firstLine} + +
      + {messages.map((message) => ( +
    • {message}
    • + ))} +
    +
    +
    +
    ); } render() { diff --git a/x-pack/plugins/license_management/public/application/sections/license_dashboard/start_trial/start_trial.tsx b/x-pack/plugins/license_management/public/application/sections/license_dashboard/start_trial/start_trial.tsx index 4f7d1ab4365b68..36af5c3b9c7adc 100644 --- a/x-pack/plugins/license_management/public/application/sections/license_dashboard/start_trial/start_trial.tsx +++ b/x-pack/plugins/license_management/public/application/sections/license_dashboard/start_trial/start_trial.tsx @@ -14,7 +14,6 @@ import { EuiFlexItem, EuiCard, EuiLink, - EuiOverlayMask, EuiText, EuiModal, EuiModalFooter, @@ -78,154 +77,152 @@ export class StartTrial extends Component { } return ( - - - - - - - - - -
    - -

    - + + + + + + + +

    + +

    + - - - ), - }} + values={{ + subscriptionFeaturesLinkText: ( + + + + ), + }} + /> +

    +
      +
    • + -

      -
        -
      • - -
      • -
      • - -
      • -
      • - -
      • -
      • - -
      • -
      -

      +

    • +
    • - - - ), - }} + id="xpack.licenseMgmt.licenseDashboard.startTrial.confirmModalDescription.alertingFeatureTitle" + defaultMessage="Alerting" + /> +
    • +
    • + -

      -

      +

    • +
    • - - - ), + jdbcStandard: 'JDBC', + odbcStandard: 'ODBC', + sqlDataBase: 'SQL', }} /> -

      - -
    -
    - - - - - - {shouldShowTelemetryOptIn(telemetry) && ( - + +

    + + + + ), + }} + /> +

    +

    + + + + ), + }} /> - )} - - - - - - - - - - - - - - - - - - - +

    + +
    +
    +
    + + + + + {shouldShowTelemetryOptIn(telemetry) && ( + + )} + + + + + + + + + + + + + + + + + +
    ); } diff --git a/x-pack/plugins/license_management/public/application/sections/upload_license/upload_license.js b/x-pack/plugins/license_management/public/application/sections/upload_license/upload_license.js index 77efe30bbb71ea..4d639ec3123dff 100644 --- a/x-pack/plugins/license_management/public/application/sections/upload_license/upload_license.js +++ b/x-pack/plugins/license_management/public/application/sections/upload_license/upload_license.js @@ -13,7 +13,6 @@ import { EuiForm, EuiSpacer, EuiConfirmModal, - EuiOverlayMask, EuiText, EuiTitle, EuiFlexGroup, @@ -62,41 +61,39 @@ export class UploadLicense extends React.PureComponent { return null; } return ( - - - } - onCancel={this.cancel} - onConfirm={() => this.send(true)} - cancelButtonText={ - - } - confirmButtonText={ - - } - > -
    - {firstLine} - -
      - {messages.map((message) => ( -
    • {message}
    • - ))} -
    -
    -
    -
    -
    + + } + onCancel={this.cancel} + onConfirm={() => this.send(true)} + cancelButtonText={ + + } + confirmButtonText={ + + } + > +
    + {firstLine} + +
      + {messages.map((message) => ( +
    • {message}
    • + ))} +
    +
    +
    +
    ); } errorMessage() { diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap index 8fc0ecacd4a3c1..31b8be8aab9ce1 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap @@ -1,41 +1,39 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmDeletePipelineModal component renders as expected 1`] = ` - - - } - confirmButtonText={ - - } - defaultFocusedButton="cancel" - onCancel={[MockFunction]} - onConfirm={[MockFunction]} - title={ - + } + confirmButtonText={ + + } + defaultFocusedButton="cancel" + onCancel={[MockFunction]} + onConfirm={[MockFunction]} + title={ + - } - > -

    - You cannot recover a deleted pipeline. -

    -
    -
    + } + /> + } +> +

    + You cannot recover a deleted pipeline. +

    + `; diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js index 37ce05f42073af..d8cf85919bd425 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js @@ -7,41 +7,39 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { EuiConfirmModal, EUI_MODAL_CANCEL_BUTTON, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CANCEL_BUTTON } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { PIPELINE_EDITOR } from './constants'; export function ConfirmDeletePipelineModal({ id, cancelDeleteModal, confirmDeletePipeline }) { return ( - - - } - confirmButtonText={ - - } - defaultFocusedButton={EUI_MODAL_CANCEL_BUTTON} - onCancel={cancelDeleteModal} - onConfirm={confirmDeletePipeline} - title={ - - } - > -

    {PIPELINE_EDITOR.DELETE_PIPELINE_MODAL_MESSAGE}

    -
    -
    + + } + confirmButtonText={ + + } + defaultFocusedButton={EUI_MODAL_CANCEL_BUTTON} + onCancel={cancelDeleteModal} + onConfirm={confirmDeletePipeline} + title={ + + } + > +

    {PIPELINE_EDITOR.DELETE_PIPELINE_MODAL_MESSAGE}

    +
    ); } diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap index c58337612f2871..9eabf4120ef233 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap +++ b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap @@ -1,93 +1,89 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmDeleteModal component confirms delete for multiple pipelines 1`] = ` - - - } - confirmButtonText={ - + } + confirmButtonText={ + - } - defaultFocusedButton="cancel" - onCancel={[MockFunction]} - onConfirm={[MockFunction]} - title={ - + } + defaultFocusedButton="cancel" + onCancel={[MockFunction]} + onConfirm={[MockFunction]} + title={ + - } - > -

    - -

    -
    -
    + } + /> + } +> +

    + +

    + `; exports[`ConfirmDeleteModal component confirms delete for single pipeline 1`] = ` - - - } - confirmButtonText={ - - } - defaultFocusedButton="cancel" - onCancel={[MockFunction]} - onConfirm={[MockFunction]} - title={ - + } + confirmButtonText={ + + } + defaultFocusedButton="cancel" + onCancel={[MockFunction]} + onConfirm={[MockFunction]} + title={ + - } - > -

    - -

    -
    -
    + } + /> + } +> +

    + +

    + `; diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js index c20db3d3fc5796..5dbefd2ae58e89 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EUI_MODAL_CANCEL_BUTTON, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CANCEL_BUTTON } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; export function ConfirmDeleteModal({ @@ -67,23 +67,21 @@ export function ConfirmDeleteModal({ }; return ( - - - } - confirmButtonText={confirmText.button} - defaultFocusedButton={EUI_MODAL_CANCEL_BUTTON} - onCancel={cancelDeletePipelines} - onConfirm={deleteSelectedPipelines} - title={confirmText.title} - > -

    {confirmText.message}

    -
    -
    + + } + confirmButtonText={confirmText.button} + defaultFocusedButton={EUI_MODAL_CANCEL_BUTTON} + onCancel={cancelDeletePipelines} + onConfirm={deleteSelectedPipelines} + title={confirmText.title} + > +

    {confirmText.message}

    +
    ); } diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js index 89eef907b22593..9e5a6080c830d8 100644 --- a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js @@ -8,7 +8,7 @@ import React from 'react'; import classNames from 'classnames'; -import { EuiIcon, EuiOverlayMask, EuiButtonIcon, EuiConfirmModal } from '@elastic/eui'; +import { EuiIcon, EuiButtonIcon, EuiConfirmModal } from '@elastic/eui'; import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; import { i18n } from '@kbn/i18n'; @@ -100,20 +100,18 @@ export class TOCEntry extends React.Component { }; return ( - - -

    There are unsaved changes to your layer.

    -

    Are you sure you want to proceed?

    -
    -
    + +

    There are unsaved changes to your layer.

    +

    Are you sure you want to proceed?

    +
    ); } diff --git a/x-pack/plugins/ml/public/application/components/annotations/delete_annotation_modal/index.tsx b/x-pack/plugins/ml/public/application/components/annotations/delete_annotation_modal/index.tsx index 8469d42c16c519..9999fad89d0e1c 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/delete_annotation_modal/index.tsx +++ b/x-pack/plugins/ml/public/application/components/annotations/delete_annotation_modal/index.tsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import React, { Fragment } from 'react'; -import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -26,33 +26,31 @@ export const DeleteAnnotationModal: React.FC = ({ return ( {isVisible === true && ( - - - } - onCancel={cancelAction} - onConfirm={deleteAction} - cancelButtonText={ - - } - confirmButtonText={ - - } - buttonColor="danger" - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - className="eui-textBreakWord" - /> - + + } + onCancel={cancelAction} + onConfirm={deleteAction} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor="danger" + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + className="eui-textBreakWord" + /> )} ); diff --git a/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx b/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx index eda0509d417ca7..972ed06ba13859 100644 --- a/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx +++ b/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx @@ -13,7 +13,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiModal, - EuiOverlayMask, EuiModalHeader, EuiModalHeaderTitle, EuiModalBody, @@ -230,69 +229,67 @@ export const DeleteJobCheckModal: FC = ({ }; return ( - - - {isLoading === true && ( - <> - - - - - - - - - )} - {isLoading === false && ( - <> - - - - - + + {isLoading === true && ( + <> + + + + + + + + + )} + {isLoading === false && ( + <> + + + + + - {modalContent} + {modalContent} - - - - {!hasUntagged && + + + + {!hasUntagged && + jobCheckRespSummary?.canTakeAnyAction && + jobCheckRespSummary?.canRemoveFromSpace && + jobCheckRespSummary?.canDelete && ( + + {shouldUnTagLabel} + + )} + + + - {shouldUnTagLabel} - - )} - - - - {buttonContent} - - - - - - )} - - + !jobCheckRespSummary?.canDelete + ? onUntagClick + : onClick + } + fill + > + {buttonContent} + + + + + + )} + ); }; diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/close_job_confirm/close_job_confirm.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/close_job_confirm/close_job_confirm.tsx index 1d2bda90516b99..8fc4a0d636bce7 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/close_job_confirm/close_job_confirm.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/close_job_confirm/close_job_confirm.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { COMBINED_JOB_STATE } from '../model_snapshots_table'; @@ -25,56 +25,51 @@ export const CloseJobConfirm: FC = ({ forceCloseJob, }) => { return ( - - +

    + {combinedJobState === COMBINED_JOB_STATE.OPEN_AND_RUNNING && ( + )} - confirmButtonText={ - combinedJobState === COMBINED_JOB_STATE.OPEN_AND_RUNNING - ? i18n.translate('xpack.ml.modelSnapshotTable.closeJobConfirm.stopAndClose.button', { - defaultMessage: 'Force stop and close', - }) - : i18n.translate('xpack.ml.modelSnapshotTable.closeJobConfirm.close.button', { - defaultMessage: 'Force close', - }) - } - defaultFocusedButton="confirm" - > -

    - {combinedJobState === COMBINED_JOB_STATE.OPEN_AND_RUNNING && ( - - )} - {combinedJobState === COMBINED_JOB_STATE.OPEN_AND_STOPPED && ( - - )} -
    + {combinedJobState === COMBINED_JOB_STATE.OPEN_AND_STOPPED && ( -

    -
    -
    + )} +
    + +

    + ); }; diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/edit_model_snapshot_flyout/edit_model_snapshot_flyout.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/edit_model_snapshot_flyout/edit_model_snapshot_flyout.tsx index 833e70fc86f4c4..20c98255930b4d 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/edit_model_snapshot_flyout/edit_model_snapshot_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/edit_model_snapshot_flyout/edit_model_snapshot_flyout.tsx @@ -22,7 +22,6 @@ import { EuiFormRow, EuiSwitch, EuiConfirmModal, - EuiOverlayMask, EuiCallOut, } from '@elastic/eui'; @@ -190,23 +189,21 @@ export const EditModelSnapshotFlyout: FC = ({ snapshot, job, closeFlyout {deleteModalVisible && ( - - - + )} ); diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx index 1929cddaca6b56..6dd4e6c14589b2 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx @@ -22,7 +22,6 @@ import { EuiFormRow, EuiSwitch, EuiConfirmModal, - EuiOverlayMask, EuiCallOut, EuiHorizontalRule, EuiSuperSelect, @@ -368,34 +367,32 @@ export const RevertModelSnapshotFlyout: FC = ({ {revertModalVisible && ( - - - - - + + + )} ); diff --git a/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/delete_rule_modal.test.js.snap b/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/delete_rule_modal.test.js.snap index a132e6682ee250..3a11531f6c4bc1 100644 --- a/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/delete_rule_modal.test.js.snap +++ b/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/delete_rule_modal.test.js.snap @@ -42,34 +42,32 @@ exports[`DeleteRuleModal renders modal after clicking delete rule link 1`] = ` values={Object {}} /> - - - } - confirmButtonText={ - - } - defaultFocusedButton="confirm" - onCancel={[Function]} - onConfirm={[Function]} - title={ - - } - /> - + + } + confirmButtonText={ + + } + defaultFocusedButton="confirm" + onCancel={[Function]} + onConfirm={[Function]} + title={ + + } + /> `; diff --git a/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/delete_rule_modal.js b/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/delete_rule_modal.js index 809bb780c33239..6caa6592e96c1e 100644 --- a/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/delete_rule_modal.js +++ b/x-pack/plugins/ml/public/application/components/rule_editor/select_rule_action/delete_rule_modal.js @@ -12,7 +12,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { EuiConfirmModal, EuiLink, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiConfirmModal, EuiLink, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; export class DeleteRuleModal extends Component { @@ -43,32 +43,30 @@ export class DeleteRuleModal extends Component { if (this.state.isModalVisible) { modal = ( - - - } - onCancel={this.closeModal} - onConfirm={this.deleteRule} - buttonColor="danger" - cancelButtonText={ - - } - confirmButtonText={ - - } - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - /> - + + } + onCancel={this.closeModal} + onConfirm={this.deleteRule} + buttonColor="danger" + cancelButtonText={ + + } + confirmButtonText={ + + } + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + /> ); } diff --git a/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.js b/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.js index a93264c852dd15..2b7c89db15e2e1 100644 --- a/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.js +++ b/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.js @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, EuiText, EuiFlexGroup, @@ -161,24 +160,19 @@ const LoadingSpinner = () => ( ); const Modal = ({ close, title, children }) => ( - - - - {title} - - - {children} - - - - - - - - + + + {title} + + + {children} + + + + + + + ); Modal.propType = { close: PropTypes.func.isRequired, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx index bc99330a444ae5..e2e1ec852d1a95 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx @@ -9,7 +9,6 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, - EuiOverlayMask, EuiSwitch, EuiFlexGroup, EuiFlexItem, @@ -37,67 +36,62 @@ export const DeleteActionModal: FC = ({ const indexName = item.config.dest.index; return ( - - - - - {userCanDeleteIndex && ( - - )} - - - {userCanDeleteIndex && indexPatternExists && ( - - )} - - - - + + + + {userCanDeleteIndex && ( + + )} + + + {userCanDeleteIndex && indexPatternExists && ( + + )} + + + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_start/start_action_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_start/start_action_modal.tsx index 2a19068ca6f4e1..d63e60e43e9094 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_start/start_action_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_start/start_action_modal.tsx @@ -7,7 +7,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { StartAction } from './use_start_action'; @@ -15,37 +15,35 @@ export const StartActionModal: FC = ({ closeModal, item, startAndCl return ( <> {item !== undefined && ( - - +

    + {i18n.translate('xpack.ml.dataframe.analyticsList.startModalBody', { + defaultMessage: + 'A data frame analytics job increases search and indexing load in your cluster. If excessive load occurs, stop the job.', })} - onCancel={closeModal} - onConfirm={startAndCloseModal} - cancelButtonText={i18n.translate( - 'xpack.ml.dataframe.analyticsList.startModalCancelButton', - { - defaultMessage: 'Cancel', - } - )} - confirmButtonText={i18n.translate( - 'xpack.ml.dataframe.analyticsList.startModalStartButton', - { - defaultMessage: 'Start', - } - )} - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - buttonColor="primary" - > -

    - {i18n.translate('xpack.ml.dataframe.analyticsList.startModalBody', { - defaultMessage: - 'A data frame analytics job increases search and indexing load in your cluster. If excessive load occurs, stop the job.', - })} -

    -
    -
    +

    +
    )} ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_action_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_action_modal.tsx index a10c0c59abd973..8ee7350245be43 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_action_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_action_modal.tsx @@ -8,7 +8,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { StopAction } from './use_stop_action'; @@ -16,37 +16,35 @@ export const StopActionModal: FC = ({ closeModal, item, forceStopAnd return ( <> {item !== undefined && ( - - -

    - -

    -
    -
    + +

    + +

    +
    )} ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx index 7ff77f21a8623e..d93baee97c5330 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx @@ -8,7 +8,6 @@ import React, { FC } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -31,57 +30,55 @@ export const DeleteModelsModal: FC = ({ models, onClose .map((model) => model.model_id); return ( - - - - + + + + + + + + + {modelsWithPipelines.length > 0 && ( + - - - - - {modelsWithPipelines.length > 0 && ( - - - - )} - + + )} + - - - - + + + + - - - - - - + + + + + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index c9f78e9b0dab1a..40f97690d7790b 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -9,13 +9,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiModal, - EuiModalBody, - EuiModalHeader, - EuiModalHeaderTitle, - EuiOverlayMask, -} from '@elastic/eui'; +import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { SavedObjectFinderUi } from '../../../../../../../../../../src/plugins/saved_objects/public'; import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; @@ -41,66 +35,62 @@ export const SourceSelection: FC = ({ onClose }) => { }; return ( - <> - - - - - {' '} - /{' '} - - - - - + + + {' '} + /{' '} + + + + + 'search', + name: i18n.translate( + 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.search', { - defaultMessage: 'No matching indices or saved searches found.', + defaultMessage: 'Saved search', } - )} - savedObjectMetaData={[ + ), + }, + { + type: 'index-pattern', + getIconForSavedObject: () => 'indexPatternApp', + name: i18n.translate( + 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern', { - type: 'search', - getIconForSavedObject: () => 'search', - name: i18n.translate( - 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.search', - { - defaultMessage: 'Saved search', - } - ), - }, - { - type: 'index-pattern', - getIconForSavedObject: () => 'indexPatternApp', - name: i18n.translate( - 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern', - { - defaultMessage: 'Index pattern', - } - ), - }, - ]} - fixedPageSize={fixedPageSize} - uiSettings={uiSettings} - savedObjects={savedObjects} - /> - - - - + defaultMessage: 'Index pattern', + } + ), + }, + ]} + fixedPageSize={fixedPageSize} + uiSettings={uiSettings} + savedObjects={savedObjects} + /> + + ); }; diff --git a/x-pack/plugins/ml/public/application/explorer/add_to_dashboard_control.tsx b/x-pack/plugins/ml/public/application/explorer/add_to_dashboard_control.tsx index 3401c72a3b8549..2330eafd87825e 100644 --- a/x-pack/plugins/ml/public/application/explorer/add_to_dashboard_control.tsx +++ b/x-pack/plugins/ml/public/application/explorer/add_to_dashboard_control.tsx @@ -14,7 +14,6 @@ import { EuiModal, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, EuiButtonEmpty, EuiButton, @@ -215,103 +214,99 @@ export const AddToDashboardControl: FC = ({ const noSwimlaneSelected = Object.values(selectedSwimlanes).every((isSelected) => !isSelected); return ( - - - - + + + + + + + + - - - - - } - > - { - const newSelection = { - ...selectedSwimlanes, - [optionId]: !selectedSwimlanes[optionId as SwimlaneType], - }; - setSelectedSwimlanes(newSelection); - }} - data-test-subj="mlAddToDashboardSwimlaneTypeSelector" - /> - + } + > + { + const newSelection = { + ...selectedSwimlanes, + [optionId]: !selectedSwimlanes[optionId as SwimlaneType], + }; + setSelectedSwimlanes(newSelection); + }} + data-test-subj="mlAddToDashboardSwimlaneTypeSelector" + /> + - + - - } - data-test-subj="mlDashboardSelectionContainer" - > - - - - - - - - { - onClose(async () => { - const selectedDashboardId = selectedItems[0].id; - await addSwimlaneToDashboardCallback(); - await navigateToUrl( - await dashboardService.getDashboardEditUrl(selectedDashboardId) - ); - }); - }} - data-test-subj="mlAddAndEditDashboardButton" - > - - - + - - - - + } + data-test-subj="mlDashboardSelectionContainer" + > + + + + + + + + { + onClose(async () => { + const selectedDashboardId = selectedItems[0].id; + await addSwimlaneToDashboardCallback(); + await navigateToUrl(await dashboardService.getDashboardEditUrl(selectedDashboardId)); + }); + }} + data-test-subj="mlAddAndEditDashboardButton" + > + + + + + + + ); }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx index 3bec404276ca26..a67863ea5f803b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx @@ -10,7 +10,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiSpacer, EuiModal, - EuiOverlayMask, EuiModalHeader, EuiModalHeaderTitle, EuiModalBody, @@ -77,74 +76,72 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, if (canDelete) { return ( - - - - - - - - -

    - {deleting === true ? ( -

    - - -
    - -
    + + + + + + + +

    + {deleting === true ? ( +

    + + +
    +
    - ) : ( - - - - )} -

    - - <> - - - - - + + )} +

    + + <> + + + + + - - - - - - - + + + +
    + + ); } else { return ( diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js index 8769c2c3cca20e..b23bbedb7413a2 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js @@ -21,7 +21,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiTabbedContent, - EuiOverlayMask, EuiConfirmModal, } from '@elastic/eui'; @@ -443,38 +442,36 @@ export class EditJobFlyoutUI extends Component { if (this.state.isConfirmationModalVisible) { confirmationModal = ( - - - } - onCancel={() => this.closeFlyout(true)} - onConfirm={() => this.save()} - cancelButtonText={ - - } - confirmButtonText={ - - } - defaultFocusedButton="confirm" - > -

    - -

    -
    -
    + + } + onCancel={() => this.closeFlyout(true)} + onConfirm={() => this.save()} + cancelButtonText={ + + } + confirmButtonText={ + + } + defaultFocusedButton="confirm" + > +

    + +

    +
    ); } diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx index a1bac4b6a35979..da4c9b0b0cc004 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx @@ -14,7 +14,6 @@ import { EuiFlexItem, EuiPanel, EuiSpacer, - EuiOverlayMask, EuiModal, EuiModalBody, EuiModalHeader, @@ -282,30 +281,28 @@ class CustomUrlsUI extends Component { ) : ( - - - - - - - + + + + + + - {editor} + {editor} - - {testButton} - {addButton} - - - + + {testButton} + {addButton} + + ); } diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js index 5f5759e49208cb..361e8956c714e3 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js @@ -16,7 +16,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiHorizontalRule, EuiCheckbox, } from '@elastic/eui'; @@ -138,78 +137,76 @@ export class StartDatafeedModal extends Component { if (this.state.isModalVisible) { modal = ( - - - - - - - - - - + + + - {this.state.endTime === undefined && ( -
    - - - } - checked={createAlert} - onChange={this.setCreateAlert} - /> -
    - )} -
    - - - - - - - - + + + + + {this.state.endTime === undefined && ( +
    + + + } + checked={createAlert} + onChange={this.setCreateAlert} /> - - - - +
    + )} +
    + + + + + + + + + + +
    ); } return
    {modal}
    ; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/reset_query/reset_query.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/reset_query/reset_query.tsx index 02f53c77c088c0..e42ec414e9641f 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/reset_query/reset_query.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/reset_query/reset_query.tsx @@ -8,13 +8,7 @@ import React, { FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiButtonEmpty, - EuiConfirmModal, - EuiOverlayMask, - EuiCodeBlock, - EuiSpacer, -} from '@elastic/eui'; +import { EuiButtonEmpty, EuiConfirmModal, EuiCodeBlock, EuiSpacer } from '@elastic/eui'; import { JobCreatorContext } from '../../../job_creator_context'; import { getDefaultDatafeedQuery } from '../../../../../utils/new_job_utils'; @@ -34,35 +28,33 @@ export const ResetQueryButton: FC = () => { return ( <> {confirmModalVisible && ( - - - + + - + - - {defaultQueryString} - - - + + {defaultQueryString} + + )} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx index 3f4a0f6ea6b3d2..aaed47cc7a02bb 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx @@ -9,7 +9,6 @@ import React, { FC } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -28,44 +27,42 @@ interface Props { export const ModalWrapper: FC = ({ onCreateClick, closeModal, saveEnabled, children }) => { return ( - - - - - - - + + + + + + - {children} + {children} - - - - + + + + - - - - - - + + + + + ); }; diff --git a/x-pack/plugins/ml/public/application/settings/calendars/edit/new_calendar.js b/x-pack/plugins/ml/public/application/settings/calendars/edit/new_calendar.js index 7f3c8ce9a1a6e5..42d8b32691c205 100644 --- a/x-pack/plugins/ml/public/application/settings/calendars/edit/new_calendar.js +++ b/x-pack/plugins/ml/public/application/settings/calendars/edit/new_calendar.js @@ -10,7 +10,7 @@ import { PropTypes } from 'prop-types'; import { i18n } from '@kbn/i18n'; -import { EuiPage, EuiPageBody, EuiPageContent, EuiOverlayMask } from '@elastic/eui'; +import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui'; import { NavigationMenu } from '../../../components/navigation_menu'; @@ -336,19 +336,13 @@ class NewCalendarUI extends Component { let modal = ''; if (isNewEventModalVisible) { - modal = ( - - - - ); + modal = ; } else if (isImportModalVisible) { modal = ( - - - + ); } diff --git a/x-pack/plugins/ml/public/application/settings/calendars/list/calendars_list.js b/x-pack/plugins/ml/public/application/settings/calendars/list/calendars_list.js index afd1433b7ae698..bba28ab481ea11 100644 --- a/x-pack/plugins/ml/public/application/settings/calendars/list/calendars_list.js +++ b/x-pack/plugins/ml/public/application/settings/calendars/list/calendars_list.js @@ -10,7 +10,6 @@ import { PropTypes } from 'prop-types'; import { EuiConfirmModal, - EuiOverlayMask, EuiPage, EuiPageBody, EuiPageContent, @@ -111,37 +110,35 @@ export class CalendarsListUI extends Component { if (this.state.isDestroyModalVisible) { destroyModal = ( - - c.calendar_id).join(', '), - }} - /> - } - onCancel={this.closeDestroyModal} - onConfirm={this.deleteCalendars} - cancelButtonText={ - - } - confirmButtonText={ - - } - buttonColor="danger" - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - /> - + c.calendar_id).join(', '), + }} + /> + } + onCancel={this.closeDestroyModal} + onConfirm={this.deleteCalendars} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor="danger" + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + /> ); } diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/__snapshots__/delete_filter_list_modal.test.js.snap b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/__snapshots__/delete_filter_list_modal.test.js.snap index 93ca044cb0c830..8cadb8270f680a 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/__snapshots__/delete_filter_list_modal.test.js.snap +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/__snapshots__/delete_filter_list_modal.test.js.snap @@ -92,41 +92,39 @@ exports[`DeleteFilterListModal renders modal after clicking delete button 1`] = values={Object {}} /> - - - } - className="eui-textBreakWord" - confirmButtonText={ - - } - data-test-subj="mlFilterListDeleteConfirmation" - defaultFocusedButton="confirm" - onCancel={[Function]} - onConfirm={[Function]} - title={ - + } + className="eui-textBreakWord" + confirmButtonText={ + + } + data-test-subj="mlFilterListDeleteConfirmation" + defaultFocusedButton="confirm" + onCancel={[Function]} + onConfirm={[Function]} + title={ + - } - /> - + } + /> + } + />
    `; diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js index bed0e7ca281e5b..20b716586b97d1 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js @@ -9,7 +9,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButton, EuiConfirmModal, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiButton, EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { deleteFilterLists } from './delete_filter_lists'; @@ -67,29 +67,27 @@ export class DeleteFilterListModal extends Component { /> ); modal = ( - - - } - confirmButtonText={ - - } - buttonColor="danger" - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - data-test-subj={'mlFilterListDeleteConfirmation'} - /> - + + } + confirmButtonText={ + + } + buttonColor="danger" + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + data-test-subj={'mlFilterListDeleteConfirmation'} + /> ); } diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/modal.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/modal.js index 613bd51bc16c3c..3261846a5fdd5b 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/modal.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/modal.js @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, } from '@elastic/eui'; @@ -31,48 +30,42 @@ import { FormattedMessage } from '@kbn/i18n/react'; export function Modal(props) { return ( - - - - - - - + + + + + + - - {props.messages.map((message, i) => ( - - - - - ))} + + {props.messages.map((message, i) => ( + + + + + ))} - {props.forecasts.length > 0 && ( - - - - - )} - - + {props.forecasts.length > 0 && ( + + + + + )} + + - - - - - - - + + + + + +
    ); } diff --git a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js index fd9f4e3503d106..4db5d1b333b7cf 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js +++ b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_list/components/remove_cluster_button_provider/remove_cluster_button_provider.js @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; export class RemoveClusterButtonProvider extends Component { static propTypes = { @@ -84,7 +84,7 @@ export class RemoveClusterButtonProvider extends Component { ); modal = ( - + <> {/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} {!isSingleCluster && content} - + ); } diff --git a/x-pack/plugins/reporting/public/components/buttons/__snapshots__/report_info_button.test.tsx.snap b/x-pack/plugins/reporting/public/components/buttons/__snapshots__/report_info_button.test.tsx.snap index 09e487591c164a..692b410bd7e5f3 100644 --- a/x-pack/plugins/reporting/public/components/buttons/__snapshots__/report_info_button.test.tsx.snap +++ b/x-pack/plugins/reporting/public/components/buttons/__snapshots__/report_info_button.test.tsx.snap @@ -58,7 +58,7 @@ Array [ >
    ,
    ,
    { }); return ( - - this.hideConfirm()} - onConfirm={() => this.props.performDelete()} - confirmButtonText={confirmButtonText} - cancelButtonText={cancelButtonText} - defaultFocusedButton="confirm" - buttonColor="danger" - > - {message} - - + this.hideConfirm()} + onConfirm={() => this.props.performDelete()} + confirmButtonText={confirmButtonText} + cancelButtonText={cancelButtonText} + defaultFocusedButton="confirm" + buttonColor="danger" + > + {message} + ); } diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js index 650d63f38eeb52..ec7473c69dec19 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; export class ConfirmDeleteModal extends Component { static propTypes = { @@ -91,28 +91,26 @@ export class ConfirmDeleteModal extends Component { } return ( - - - {content} - - + + {content} + ); } } diff --git a/x-pack/plugins/security/public/components/confirm_modal.tsx b/x-pack/plugins/security/public/components/confirm_modal.tsx index d0ca1de07314e2..3802ee368d735b 100644 --- a/x-pack/plugins/security/public/components/confirm_modal.tsx +++ b/x-pack/plugins/security/public/components/confirm_modal.tsx @@ -18,7 +18,6 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiModalProps, - EuiOverlayMask, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -29,13 +28,11 @@ export interface ConfirmModalProps extends Omit = ({ children, @@ -45,51 +42,42 @@ export const ConfirmModal: FunctionComponent = ({ isDisabled, onCancel, onConfirm, - ownFocus = true, title, ...rest -}) => { - const modal = ( - - - {title} - - {children} - - - - - - - - - - {confirmButtonText} - - - - - - ); - - return ownFocus ? ( - {modal} - ) : ( - modal - ); -}; +}) => ( + + + {title} + + {children} + + + + + + + + + + {confirmButtonText} + + + + + +); diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx index ae142e76877cef..232847b63cb1ab 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useRef, useState } from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { i18n } from '@kbn/i18n'; import { NotificationsStart } from 'src/core/public'; @@ -127,58 +127,56 @@ export const InvalidateProvider: React.FunctionComponent = ({ const isSingle = apiKeys.length === 1; return ( - - - {!isSingle ? ( - -

    - {i18n.translate( - 'xpack.security.management.apiKeys.invalidateApiKey.confirmModal.invalidateMultipleListDescription', - { defaultMessage: 'You are about to invalidate these API keys:' } - )} -

    -
      - {apiKeys.map(({ name, id }) => ( -
    • {name}
    • - ))} -
    -
    - ) : null} -
    -
    + )} + buttonColor="danger" + data-test-subj="invalidateApiKeyConfirmationModal" + > + {!isSingle ? ( + +

    + {i18n.translate( + 'xpack.security.management.apiKeys.invalidateApiKey.confirmModal.invalidateMultipleListDescription', + { defaultMessage: 'You are about to invalidate these API keys:' } + )} +

    +
      + {apiKeys.map(({ name, id }) => ( +
    • {name}
    • + ))} +
    +
    + ) : null} + ); }; diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx index c5e6e3cb9860d0..680a4a40a7d9a1 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx @@ -6,7 +6,7 @@ */ import React, { Fragment, useRef, useState, ReactElement } from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart } from 'src/core/public'; @@ -140,59 +140,57 @@ export const DeleteProvider: React.FunctionComponent = ({ const isSingle = roleMappings.length === 1; return ( - - - {!isSingle ? ( - -

    - {i18n.translate( - 'xpack.security.management.roleMappings.deleteRoleMapping.confirmModal.deleteMultipleListDescription', - { defaultMessage: 'You are about to delete these role mappings:' } - )} -

    -
      - {roleMappings.map(({ name }) => ( -
    • {name}
    • - ))} -
    -
    - ) : null} -
    -
    + )} + confirmButtonDisabled={isDeleteInProgress} + buttonColor="danger" + data-test-subj="deleteRoleMappingConfirmationModal" + > + {!isSingle ? ( + +

    + {i18n.translate( + 'xpack.security.management.roleMappings.deleteRoleMapping.confirmModal.deleteMultipleListDescription', + { defaultMessage: 'You are about to delete these role mappings:' } + )} +

    +
      + {roleMappings.map(({ name }) => ( +
    • {name}
    • + ))} +
    +
    + ) : null} + ); }; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx index b094f78a53e778..d027a1aeb7e1fc 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx @@ -9,7 +9,6 @@ import React, { Component, Fragment } from 'react'; import { EuiSpacer, EuiConfirmModal, - EuiOverlayMask, EuiCallOut, EuiErrorBoundary, EuiIcon, @@ -228,40 +227,38 @@ export class RuleEditorPanel extends Component { return null; } return ( - - - } - onCancel={() => this.setState({ showConfirmModeChange: false })} - onConfirm={() => { - this.setState({ mode: 'visual', showConfirmModeChange: false }); - this.onValidityChange(true); - }} - cancelButtonText={ - - } - confirmButtonText={ - - } - > -

    - -

    -
    -
    + + } + onCancel={() => this.setState({ showConfirmModeChange: false })} + onConfirm={() => { + this.setState({ mode: 'visual', showConfirmModeChange: false }); + this.onValidityChange(true); + }} + cancelButtonText={ + + } + confirmButtonText={ + + } + > +

    + +

    +
    ); }; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx index 6e94abfb3f4a20..478e8d87abf95c 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx @@ -12,7 +12,6 @@ import { EuiContextMenuItem, EuiLink, EuiIcon, - EuiOverlayMask, EuiConfirmModal, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -87,45 +86,43 @@ export const RuleGroupTitle = (props: Props) => { ); const confirmChangeModal = showConfirmChangeModal ? ( - - - } - onCancel={() => { - setShowConfirmChangeModal(false); - setPendingNewRule(null); - }} - onConfirm={() => { - setShowConfirmChangeModal(false); - changeRuleDiscardingSubRules(pendingNewRule!); - setPendingNewRule(null); - }} - cancelButtonText={ - - } - confirmButtonText={ - - } - > -

    - -

    -
    -
    + + } + onCancel={() => { + setShowConfirmChangeModal(false); + setPendingNewRule(null); + }} + onConfirm={() => { + setShowConfirmChangeModal(false); + changeRuleDiscardingSubRules(pendingNewRule!); + setPendingNewRule(null); + }} + cancelButtonText={ + + } + confirmButtonText={ + + } + > +

    + +

    +
    ) : null; return ( diff --git a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx index bd3c86575c61a4..1b3a7fa024dd16 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonEmpty, EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiButtonEmpty, EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; @@ -46,44 +46,42 @@ export class DeleteRoleButton extends Component { return null; } return ( - - - } - onCancel={this.closeModal} - onConfirm={this.onConfirmDelete} - cancelButtonText={ - - } - confirmButtonText={ - - } - buttonColor={'danger'} - > -

    - -

    -

    - -

    -
    -
    + + } + onCancel={this.closeModal} + onConfirm={this.onConfirmDelete} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor={'danger'} + > +

    + +

    +

    + +

    +
    ); }; diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx index dbbb09f1598b63..81302465bb3732 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx @@ -14,7 +14,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -55,65 +54,61 @@ export class ConfirmDelete extends Component { // to disable the buttons since this could be a long-running operation return ( - - - - - {title} - - - - - {moreThanOne ? ( - -

    - -

    -
      - {rolesToDelete.map((roleName) => ( -
    • {roleName}
    • - ))} -
    -
    - ) : null} -

    - -

    -
    -
    - - + + + {title} + + + + {moreThanOne ? ( + +

    + +

    +
      + {rolesToDelete.map((roleName) => ( +
    • {roleName}
    • + ))} +
    +
    + ) : null} +

    - +

    +
    +
    + + + + - - - - -
    -
    + + + + + ); } diff --git a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx index c670a9ce99f5bb..38adca145dfc5d 100644 --- a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx +++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx @@ -6,7 +6,7 @@ */ import React, { Component, Fragment } from 'react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; @@ -35,46 +35,44 @@ export class ConfirmDeleteUsers extends Component { values: { userLength: usersToDelete[0] }, }); return ( - - -
    - {moreThanOne ? ( - -

    - -

    -
      - {usersToDelete.map((username) => ( -
    • {username}
    • - ))} -
    -
    - ) : null} -

    - -

    -
    -
    -
    + +
    + {moreThanOne ? ( + +

    + +

    +
      + {usersToDelete.map((username) => ( +
    • {username}
    • + ))} +
    +
    + ) : null} +

    + +

    +
    +
    ); } diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx index 9e8745538e0ed3..189f0c3845d635 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx @@ -68,7 +68,6 @@ export const ConfirmDeleteUsers: FunctionComponent = ({ )} confirmButtonColor="danger" isLoading={state.loading} - ownFocus >

    diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx index 793f0e6c2a420b..e0fb4e554ee3c4 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx @@ -80,7 +80,6 @@ export const ConfirmDisableUsers: FunctionComponent = } confirmButtonColor={isSystemUser ? 'danger' : undefined} isLoading={state.loading} - ownFocus > {isSystemUser ? ( diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx index a1aac5bc0a8cb4..2cb4cf8b4a9e2c 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx @@ -67,7 +67,6 @@ export const ConfirmEnableUsers: FunctionComponent = ({ } )} isLoading={state.loading} - ownFocus >

    diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index ca4c869e0f2d38..c001f1fc2bc47d 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -99,7 +99,7 @@ export const goToQueryTab = () => { export const addNotesToTimeline = (notes: string) => { goToNotesTab(); cy.get(NOTES_TEXT_AREA).type(notes); - cy.get(ADD_NOTE_BUTTON).click(); + cy.get(ADD_NOTE_BUTTON).click({ force: true }); cy.get(QUERY_TAB_BUTTON).click(); }; diff --git a/x-pack/plugins/security_solution/public/cases/components/confirm_delete_case/index.tsx b/x-pack/plugins/security_solution/public/cases/components/confirm_delete_case/index.tsx index 1b67aaeb795dd1..eb75d896ae7788 100644 --- a/x-pack/plugins/security_solution/public/cases/components/confirm_delete_case/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/confirm_delete_case/index.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import * as i18n from './translations'; interface ConfirmDeleteCaseModalProps { @@ -28,20 +28,18 @@ const ConfirmDeleteCaseModalComp: React.FC = ({ return null; } return ( - - - {isPlural ? i18n.CONFIRM_QUESTION_PLURAL : i18n.CONFIRM_QUESTION} - - + + {isPlural ? i18n.CONFIRM_QUESTION_PLURAL : i18n.CONFIRM_QUESTION} + ); }; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx index 1dfabda8068f17..eda8ed8cdfbcd5 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx @@ -6,13 +6,7 @@ */ import React, { memo } from 'react'; -import { - EuiModal, - EuiModalBody, - EuiModalHeader, - EuiModalHeaderTitle, - EuiOverlayMask, -} from '@elastic/eui'; +import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { useGetUserSavedObjectPermissions } from '../../../common/lib/kibana'; import { Case } from '../../containers/types'; @@ -34,16 +28,14 @@ const AllCasesModalComponent: React.FC = ({ const userCanCrud = userPermissions?.crud ?? false; return isModalOpen ? ( - - - - {i18n.SELECT_CASE_TITLE} - - - - - - + + + {i18n.SELECT_CASE_TITLE} + + + + + ) : null; }; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx index 3595f2c916af71..8dd5080666cb38 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx @@ -7,13 +7,7 @@ import React, { memo } from 'react'; import styled from 'styled-components'; -import { - EuiModal, - EuiModalBody, - EuiModalHeader, - EuiModalHeaderTitle, - EuiOverlayMask, -} from '@elastic/eui'; +import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { FormContext } from '../create/form_context'; import { CreateCaseForm } from '../create/form'; @@ -40,21 +34,19 @@ const CreateModalComponent: React.FC = ({ onSuccess, }) => { return isModalOpen ? ( - - - - {i18n.CREATE_TITLE} - - - - - - - - - - - + + + {i18n.CREATE_TITLE} + + + + + + + + + + ) : null; }; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx index dc7388438c012a..5ea11f61f9a7e5 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx @@ -14,7 +14,6 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiModalFooter, - EuiOverlayMask, EuiButton, EuiButtonEmpty, EuiHorizontalRule, @@ -348,133 +347,129 @@ export const AddExceptionModal = memo(function AddExceptionModal({ }, [maybeRule]); return ( - - - - {addExceptionMessage} - - {ruleName} - - - - {fetchOrCreateListError != null && ( - - - + + + {addExceptionMessage} + + {ruleName} + + + + {fetchOrCreateListError != null && ( + + + + )} + {fetchOrCreateListError == null && + (isLoadingExceptionList || + isIndexPatternLoading || + isSignalIndexLoading || + isSignalIndexPatternLoading) && ( + )} - {fetchOrCreateListError == null && - (isLoadingExceptionList || - isIndexPatternLoading || - isSignalIndexLoading || - isSignalIndexPatternLoading) && ( - - )} - {fetchOrCreateListError == null && - !isSignalIndexLoading && - !isSignalIndexPatternLoading && - !isLoadingExceptionList && - !isIndexPatternLoading && - !isRuleLoading && - !mlJobLoading && - ruleExceptionList && ( - <> - - {isRuleEQLSequenceStatement && ( - <> - - - - )} - {i18n.EXCEPTION_BUILDER_INFO} - - - - - - - - - - {alertData !== undefined && alertStatus !== 'closed' && ( - - - - )} + {fetchOrCreateListError == null && + !isSignalIndexLoading && + !isSignalIndexPatternLoading && + !isLoadingExceptionList && + !isIndexPatternLoading && + !isRuleLoading && + !mlJobLoading && + ruleExceptionList && ( + <> + + {isRuleEQLSequenceStatement && ( + <> + + + + )} + {i18n.EXCEPTION_BUILDER_INFO} + + + + + + + + + + {alertData !== undefined && alertStatus !== 'closed' && ( - {exceptionListType === 'endpoint' && ( - <> - - - {i18n.ENDPOINT_QUARANTINE_TEXT} - - - )} - - - )} - {fetchOrCreateListError == null && ( - - {i18n.CANCEL} - - - {addExceptionMessage} - - + )} + + + + {exceptionListType === 'endpoint' && ( + <> + + + {i18n.ENDPOINT_QUARANTINE_TEXT} + + + )} + + )} - - + {fetchOrCreateListError == null && ( + + {i18n.CANCEL} + + + {addExceptionMessage} + + + )} + ); }); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/index.tsx index 75b7bf2aabd7fd..336732016e9369 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/index.tsx @@ -12,7 +12,6 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiModalFooter, - EuiOverlayMask, EuiButton, EuiButtonEmpty, EuiHorizontalRule, @@ -281,125 +280,121 @@ export const EditExceptionModal = memo(function EditExceptionModal({ }, [maybeRule]); return ( - - - - - {exceptionListType === 'endpoint' - ? i18n.EDIT_ENDPOINT_EXCEPTION_TITLE - : i18n.EDIT_EXCEPTION_TITLE} - - - {ruleName} - - - {(addExceptionIsLoading || isIndexPatternLoading || isSignalIndexLoading) && ( - - )} - {!isSignalIndexLoading && - !addExceptionIsLoading && - !isIndexPatternLoading && - !isRuleLoading && - !mlJobLoading && ( - <> - - {isRuleEQLSequenceStatement && ( - <> - - - - )} - {i18n.EXCEPTION_BUILDER_INFO} - - - - - - - - - - - + + + {exceptionListType === 'endpoint' + ? i18n.EDIT_ENDPOINT_EXCEPTION_TITLE + : i18n.EDIT_EXCEPTION_TITLE} + + + {ruleName} + + + {(addExceptionIsLoading || isIndexPatternLoading || isSignalIndexLoading) && ( + + )} + {!isSignalIndexLoading && + !addExceptionIsLoading && + !isIndexPatternLoading && + !isRuleLoading && + !mlJobLoading && ( + <> + + {isRuleEQLSequenceStatement && ( + <> + - - {exceptionListType === 'endpoint' && ( - <> - - - {i18n.ENDPOINT_QUARANTINE_TEXT} - - - )} - - - )} - {updateError != null && ( - - - - )} - {hasVersionConflict && ( - - -

    {i18n.VERSION_CONFLICT_ERROR_DESCRIPTION}

    - - - )} - {updateError == null && ( - - {i18n.CANCEL} - - - {i18n.EDIT_EXCEPTION_SAVE_BUTTON} - - + + + )} + {i18n.EXCEPTION_BUILDER_INFO} + + + + + + + + + + + + + {exceptionListType === 'endpoint' && ( + <> + + + {i18n.ENDPOINT_QUARANTINE_TEXT} + + + )} + + )} - - + {updateError != null && ( + + + + )} + {hasVersionConflict && ( + + +

    {i18n.VERSION_CONFLICT_ERROR_DESCRIPTION}

    +
    +
    + )} + {updateError == null && ( + + {i18n.CANCEL} + + + {i18n.EDIT_EXCEPTION_SAVE_BUTTON} + + + )} + ); }); diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap index 6503dd8dfb5086..d1a41b1c32c102 100644 --- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap @@ -2,64 +2,62 @@ exports[`ImportDataModal renders correctly against snapshot 1`] = ` - - - - - title - - - - -

    - description -

    -
    - - - - -
    - - - Cancel - - - submitBtnText - - -
    -
    + + + + title + + + + +

    + description +

    +
    + + + + +
    + + + Cancel + + + submitBtnText + + +
    `; diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx index 8a29ce3799321f..4c3dc2a249b4ff 100644 --- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx @@ -15,7 +15,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiSpacer, EuiText, } from '@elastic/eui'; @@ -132,51 +131,49 @@ export const ImportDataModalComponent = ({ return ( <> {showModal && ( - - - - {title} - - - - -

    {description}

    -
    - - - { - setSelectedFiles(files && files.length > 0 ? files : null); - }} - display={'large'} - fullWidth={true} - isLoading={isImporting} + + + {title} + + + + +

    {description}

    +
    + + + { + setSelectedFiles(files && files.length > 0 ? files : null); + }} + display={'large'} + fullWidth={true} + isLoading={isImporting} + /> + + {showCheckBox && ( + setOverwrite(!overwrite)} /> - - {showCheckBox && ( - setOverwrite(!overwrite)} - /> - )} -
    - - - {i18n.CANCEL_BUTTON} - - {submitBtnText} - - -
    -
    + )} + + + + {i18n.CANCEL_BUTTON} + + {submitBtnText} + + + )} ); diff --git a/x-pack/plugins/security_solution/public/common/components/inspect/modal.tsx b/x-pack/plugins/security_solution/public/common/components/inspect/modal.tsx index ece29cd360ce71..a5c0144531110a 100644 --- a/x-pack/plugins/security_solution/public/common/components/inspect/modal.tsx +++ b/x-pack/plugins/security_solution/public/common/components/inspect/modal.tsx @@ -15,7 +15,6 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiModalFooter, - EuiOverlayMask, EuiSpacer, EuiTabbedContent, } from '@elastic/eui'; @@ -211,24 +210,22 @@ export const ModalInspectQuery = ({ ]; return ( - - - - - {i18n.INSPECT} {title} - - - - - - - - - - {i18n.CLOSE} - - - - + + + + {i18n.INSPECT} {title} + + + + + + + + + + {i18n.CLOSE} + + + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/paginated_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/paginated_table/__snapshots__/index.test.tsx.snap index 778916ad2d07ac..be5702550a44c8 100644 --- a/x-pack/plugins/security_solution/public/common/components/paginated_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/paginated_table/__snapshots__/index.test.tsx.snap @@ -246,6 +246,12 @@ exports[`Paginated Table Component rendering it renders the default load more ta }, "euiFilePickerTallHeight": "128px", "euiFlyoutBorder": "1px solid #343741", + "euiFlyoutPaddingModifiers": Object { + "paddingLarge": "24px", + "paddingMedium": "16px", + "paddingNone": 0, + "paddingSmall": "8px", + }, "euiFocusBackgroundColor": "#08334a", "euiFocusRingAnimStartColor": "rgba(27, 169, 245, 0)", "euiFocusRingAnimStartSize": "6px", @@ -357,6 +363,7 @@ exports[`Paginated Table Component rendering it renders the default load more ta }, "euiMarkdownEditorMinHeight": "150px", "euiPageBackgroundColor": "#1a1b20", + "euiPageDefaultMaxWidth": "1000px", "euiPaletteColorBlind": Object { "euiColorVis0": Object { "behindText": "#6dccb1", @@ -534,6 +541,7 @@ exports[`Paginated Table Component rendering it renders the default load more ta "euiSwitchWidthCompressed": "28px", "euiSwitchWidthMini": "22px", "euiTabFontSize": "16px", + "euiTabFontSizeL": "18px", "euiTabFontSizeS": "14px", "euiTableActionsAreaWidth": "40px", "euiTableActionsBorderColor": "rgba(83, 89, 102, 0.09999999999999998)", diff --git a/x-pack/plugins/security_solution/public/common/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap index f7924f37d2c173..5e008e28073de1 100644 --- a/x-pack/plugins/security_solution/public/common/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap @@ -1,50 +1,48 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Modal all errors rendering it renders the default all errors modal when isShowing is positive 1`] = ` - - - - - Your visualization has error(s) - - - - - - - - Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - - - - - - Close - - - - + + + + Your visualization has error(s) + + + + + + + + Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + + + + + Close + + + `; diff --git a/x-pack/plugins/security_solution/public/common/components/toasters/modal_all_errors.tsx b/x-pack/plugins/security_solution/public/common/components/toasters/modal_all_errors.tsx index 873ebe97317f4f..0a78139f5fe3a1 100644 --- a/x-pack/plugins/security_solution/public/common/components/toasters/modal_all_errors.tsx +++ b/x-pack/plugins/security_solution/public/common/components/toasters/modal_all_errors.tsx @@ -7,7 +7,6 @@ import { EuiButton, - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -36,36 +35,34 @@ const ModalAllErrorsComponent: React.FC = ({ isShowing, toast, t if (!isShowing || toast == null) return null; return ( - - - - {i18n.TITLE_ERROR_MODAL} - + + + {i18n.TITLE_ERROR_MODAL} + - - - - {toast.errors != null && - toast.errors.map((error, index) => ( - 100 ? `${error.substring(0, 100)} ...` : error} - data-test-subj="modal-all-errors-accordion" - > - {error} - - ))} - + + + + {toast.errors != null && + toast.errors.map((error, index) => ( + 100 ? `${error.substring(0, 100)} ...` : error} + data-test-subj="modal-all-errors-accordion" + > + {error} + + ))} + - - - {i18n.CLOSE_ERROR_MODAL} - - - - + + + {i18n.CLOSE_ERROR_MODAL} + + + ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/modal.tsx b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/modal.tsx index adc46f08272d7e..aefa447269f46c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/modal.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/modal.tsx @@ -15,7 +15,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiPanel, EuiSpacer, EuiText, @@ -211,7 +210,7 @@ export const ValueListsModalComponent: React.FC = ({ const columns = buildColumns(handleExport, handleDelete); return ( - + <> {i18n.MODAL_TITLE} @@ -255,7 +254,7 @@ export const ValueListsModalComponent: React.FC = ({ name={exportDownload.name} onDownload={() => setExportDownload({})} /> - + ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/reference_error_modal/reference_error_modal.tsx b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/reference_error_modal/reference_error_modal.tsx index 20744c3a22515f..e4d8e2cee32685 100644 --- a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/reference_error_modal/reference_error_modal.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_modal/reference_error_modal/reference_error_modal.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiConfirmModal, EuiListGroup, EuiListGroupItem, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal, EuiListGroup, EuiListGroupItem } from '@elastic/eui'; import styled from 'styled-components'; import { rgba } from 'polished'; @@ -59,28 +59,26 @@ export const ReferenceErrorModalComponent: React.FC = } return ( - - -

    {contentText}

    - - - {references.map((r, index) => ( - - ))} - - -
    -
    + +

    {contentText}

    + + + {references.map((r, index) => ( + + ))} + + +
    ); }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index 89785efbb5047a..04bf3c544030a4 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -9,7 +9,6 @@ import { EuiBasicTable, EuiLoadingContent, EuiProgress, - EuiOverlayMask, EuiConfirmModal, EuiWindowEvent, } from '@elastic/eui'; @@ -490,18 +489,16 @@ export const RulesTables = React.memo( )} {showIdleModal && ( - - -

    {i18n.REFRESH_PROMPT_BODY}

    -
    -
    + +

    {i18n.REFRESH_PROMPT_BODY}

    +
    )} {shouldShowRulesTable && ( <> diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx index ec0198de585589..e14f56881d6733 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx @@ -12,7 +12,6 @@ import { EuiButton, EuiButtonEmpty, EuiSpacer, - EuiOverlayMask, EuiConfirmModal, EuiCallOut, EuiLoadingSpinner, @@ -234,59 +233,54 @@ const ConfirmUpdate = React.memo<{ onCancel: () => void; }>(({ hostCount, onCancel, onConfirm }) => { return ( - - - {hostCount > 0 && ( - <> - - - - - - )} -

    - -

    -
    -
    + + {hostCount > 0 && ( + <> + + + + + + )} +

    + +

    +
    ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_app_deletion_dialog.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_app_deletion_dialog.tsx index 4e3dc953b539e2..bffd9806103721 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_app_deletion_dialog.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_app_deletion_dialog.tsx @@ -19,7 +19,6 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiOverlayMask, EuiText, } from '@elastic/eui'; @@ -100,36 +99,34 @@ export const TrustedAppDeletionDialog = memo(() => { if (useTrustedAppsSelector(isDeletionDialogOpen)) { return ( - - - - {translations.title} - + + + {translations.title} + - - -

    {translations.mainMessage}

    -

    {translations.subMessage}

    -
    -
    + + +

    {translations.mainMessage}

    +

    {translations.subMessage}

    +
    +
    - - - {translations.cancelButton} - + + + {translations.cancelButton} + - - {translations.confirmButton} - - -
    -
    + + {translations.confirmButton} + + + ); } else { return <>; diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/delete_timeline_modal/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/delete_timeline_modal/index.tsx index a87f486a9d5d1f..7dde3fbe4cd2a6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/delete_timeline_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/delete_timeline_modal/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiModal } from '@elastic/eui'; import React, { useCallback } from 'react'; import { createGlobalStyle } from 'styled-components'; @@ -46,16 +46,14 @@ export const DeleteTimelineModalOverlay = React.memo( <> {isModalOpen && } {isModalOpen ? ( - - - - - + + + ) : null} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx index 5b7fbcffd14ad7..c23cffa854514f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiModal } from '@elastic/eui'; import React from 'react'; import { TimelineModel } from '../../../../timelines/store/timeline/model'; @@ -26,22 +26,20 @@ const OPEN_TIMELINE_MODAL_WIDTH = 1100; // px export const OpenTimelineModal = React.memo( ({ hideActions = [], modalTitle, onClose, onOpen }) => ( - - - - - + + + ) ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index 124c8012fd533c..aece377ee4f2dc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -287,7 +287,7 @@ Array [ data-eui="EuiFocusTrap" >
    - - {isSaving && ( - + + {isSaving && ( + + )} + {modalHeader} + + + {showWarning && ( + + + + )} - {modalHeader} - - - {showWarning && ( - - - - - )} -
    - - - - - - - - - - - - - {closeModalText} - - - - - {saveButtonTitle} - - - - -
    -
    -
    - +
    + + + + + + + + + + + + + {closeModalText} + + + + + {saveButtonTitle} + + + + +
    + +
    ); } ); diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_delete_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_delete_provider.tsx index 0638d3349206d6..792538a730ebe8 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_delete_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_delete_provider.tsx @@ -7,7 +7,7 @@ import React, { Fragment, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { useServices, useToastNotifications } from '../app_context'; import { deletePolicies } from '../services/http'; @@ -96,58 +96,56 @@ export const PolicyDeleteProvider: React.FunctionComponent = ({ children const isSingle = policyNames.length === 1; return ( - - - ) : ( - - ) - } - onCancel={closeModal} - onConfirm={deletePolicy} - cancelButtonText={ + - } - confirmButtonText={ + ) : ( - } - buttonColor="danger" - data-test-subj="srdeletePolicyConfirmationModal" - > - {!isSingle ? ( - -

    - -

    -
      - {policyNames.map((name) => ( -
    • {name}
    • - ))} -
    -
    - ) : null} -
    -
    + ) + } + onCancel={closeModal} + onConfirm={deletePolicy} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor="danger" + data-test-subj="srdeletePolicyConfirmationModal" + > + {!isSingle ? ( + +

    + +

    +
      + {policyNames.map((name) => ( +
    • {name}
    • + ))} +
    +
    + ) : null} + ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_execute_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_execute_provider.tsx index 3fcf5a35b34551..5636ca651b6285 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_execute_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_execute_provider.tsx @@ -7,7 +7,7 @@ import React, { Fragment, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { useServices, useToastNotifications } from '../app_context'; import { executePolicy as executePolicyRequest } from '../services/http'; @@ -81,32 +81,30 @@ export const PolicyExecuteProvider: React.FunctionComponent = ({ children } return ( - - - } - onCancel={closeModal} - onConfirm={executePolicy} - cancelButtonText={ - - } - confirmButtonText={ - - } - data-test-subj="srExecutePolicyConfirmationModal" - /> - + + } + onCancel={closeModal} + onConfirm={executePolicy} + cancelButtonText={ + + } + confirmButtonText={ + + } + data-test-subj="srExecutePolicyConfirmationModal" + /> ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_delete_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_delete_provider.tsx index 3009413541111c..f02f160958a203 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_delete_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_delete_provider.tsx @@ -7,7 +7,7 @@ import React, { Fragment, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { Repository } from '../../../common/types'; import { useServices, useToastNotifications } from '../app_context'; @@ -109,79 +109,77 @@ export const RepositoryDeleteProvider: React.FunctionComponent = ({ child const isSingle = repositoryNames.length === 1; return ( - - - ) : ( - - ) - } - onCancel={closeModal} - onConfirm={deleteRepository} - cancelButtonText={ + - } - confirmButtonText={ - isSingle ? ( - - ) : ( + ) : ( + + ) + } + onCancel={closeModal} + onConfirm={deleteRepository} + cancelButtonText={ + + } + confirmButtonText={ + isSingle ? ( + + ) : ( + + ) + } + buttonColor="danger" + data-test-subj="deleteRepositoryConfirmation" + > + {isSingle ? ( +

    + +

    + ) : ( + +

    - ) - } - buttonColor="danger" - data-test-subj="deleteRepositoryConfirmation" - > - {isSingle ? ( +

    +
      + {repositoryNames.map((name) => ( +
    • {name}
    • + ))} +

    - ) : ( - -

    - -

    -
      - {repositoryNames.map((name) => ( -
    • {name}
    • - ))} -
    -

    - -

    -
    - )} -
    -
    + + )} +
    ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/retention_execute_modal_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/retention_execute_modal_provider.tsx index 9366815a0256e2..4ce1d93955952f 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/retention_execute_modal_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/retention_execute_modal_provider.tsx @@ -7,7 +7,7 @@ import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { useServices, useToastNotifications } from '../app_context'; import { executeRetention as executeRetentionRequest } from '../services/http'; @@ -58,31 +58,29 @@ export const RetentionExecuteModalProvider: React.FunctionComponent = ({ } return ( - - - } - onCancel={closeModal} - onConfirm={executeRetention} - cancelButtonText={ - - } - confirmButtonText={ - - } - data-test-subj="executeRetentionModal" - /> - + + } + onCancel={closeModal} + onConfirm={executeRetention} + cancelButtonText={ + + } + confirmButtonText={ + + } + data-test-subj="executeRetentionModal" + /> ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/retention_update_modal_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/retention_update_modal_provider.tsx index d8916ce9858f80..73e19eee8bf7a7 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/retention_update_modal_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/retention_update_modal_provider.tsx @@ -8,7 +8,6 @@ import React, { Fragment, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -129,165 +128,161 @@ export const RetentionSettingsUpdateModalProvider: React.FunctionComponent - - - - {isEditing ? ( - - ) : ( - - )} - - - - - {saveError && ( - - - } - color="danger" - iconType="alert" - > - {saveError.data && saveError.data.message ? ( -

    {saveError.data.message}

    - ) : null} -
    - -
    + + + + {isEditing ? ( + + ) : ( + )} - {isAdvancedCronVisible ? ( - - - } - isInvalid={isInvalid} - error={i18n.translate( - 'xpack.snapshotRestore.policyForm.stepRetention.policyUpdateRetentionScheduleFieldErrorMessage', - { - defaultMessage: 'Retention schedule is required.', - } - )} - helpText={ - - - - ), - }} - /> + + + + + {saveError && ( + + + } + color="danger" + iconType="alert" + > + {saveError.data && saveError.data.message ?

    {saveError.data.message}

    : null} +
    + +
    + )} + {isAdvancedCronVisible ? ( + + + } + isInvalid={isInvalid} + error={i18n.translate( + 'xpack.snapshotRestore.policyForm.stepRetention.policyUpdateRetentionScheduleFieldErrorMessage', + { + defaultMessage: 'Retention schedule is required.', } - fullWidth - > - setRetentionSchedule(e.target.value)} + )} + helpText={ + + + + ), + }} /> - + } + fullWidth + > + setRetentionSchedule(e.target.value)} + /> + - + - - { - setIsAdvancedCronVisible(false); - setRetentionSchedule(simpleCron.expression); - }} - data-test-subj="showBasicCronLink" - > - - - - - ) : ( - - { - setSimpleCron({ - expression, - frequency, - }); - setFieldToPreferredValueMap(newFieldToPreferredValueMap); - setRetentionSchedule(expression); + + { + setIsAdvancedCronVisible(false); + setRetentionSchedule(simpleCron.expression); }} - /> - - + data-test-subj="showBasicCronLink" + > + + + + + ) : ( + + { + setSimpleCron({ + expression, + frequency, + }); + setFieldToPreferredValueMap(newFieldToPreferredValueMap); + setRetentionSchedule(expression); + }} + /> - - { - setIsAdvancedCronVisible(true); - }} - data-test-subj="showAdvancedCronLink" - > - - - - - )} -
    + - - + + { + setIsAdvancedCronVisible(true); + }} + data-test-subj="showAdvancedCronLink" + > + + + + + )} +
    + + + + + + + + {isEditing ? ( - - - - {isEditing ? ( - - ) : ( - - )} - - -
    - + ) : ( + + )} + + + ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/snapshot_delete_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/components/snapshot_delete_provider.tsx index 40af1b07a50bc1..74614efb314aae 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/snapshot_delete_provider.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/snapshot_delete_provider.tsx @@ -9,7 +9,6 @@ import React, { Fragment, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, - EuiOverlayMask, EuiCallOut, EuiLoadingSpinner, EuiFlexGroup, @@ -118,95 +117,93 @@ export const SnapshotDeleteProvider: React.FunctionComponent = ({ childre const isSingle = snapshotIds.length === 1; return ( - - - ) : ( - - ) - } - onCancel={closeModal} - onConfirm={deleteSnapshot} - cancelButtonText={ + - } - confirmButtonText={ + ) : ( - } - confirmButtonDisabled={isDeleting} - buttonColor="danger" - data-test-subj="srdeleteSnapshotConfirmationModal" - > - {!isSingle ? ( - + ) + } + onCancel={closeModal} + onConfirm={deleteSnapshot} + cancelButtonText={ + + } + confirmButtonText={ + + } + confirmButtonDisabled={isDeleting} + buttonColor="danger" + data-test-subj="srdeleteSnapshotConfirmationModal" + > + {!isSingle ? ( + +

    + +

    +
      + {snapshotIds.map(({ snapshot, repository }) => ( +
    • {snapshot}
    • + ))} +
    +
    + ) : null} +

    + +

    + {!isSingle && isDeleting ? ( + + + + + + + + + + + + } + >

    -
      - {snapshotIds.map(({ snapshot, repository }) => ( -
    • {snapshot}
    • - ))} -
    -
    - ) : null} -

    - -

    - {!isSingle && isDeleting ? ( - - - - - - - - - - - - } - > -

    - -

    - - - ) : null} -
    -
    + + + ) : null} +
    ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx index e7bdde2984d6f4..823ce3a122ef12 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx @@ -281,7 +281,7 @@ export const RepositoryDetails: React.FunctionComponent = ({ {verification ? ( - + {JSON.stringify( verification.valid ? verification.response : verification.error, null, @@ -350,7 +350,7 @@ export const RepositoryDetails: React.FunctionComponent = ({ /> - + {JSON.stringify(cleanup.response, null, 2)}
    diff --git a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap index b0d0933614d125..5bf93a1021c054 100644 --- a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap @@ -1,95 +1,93 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmDeleteModal renders as expected 1`] = ` - - - - + + + + + + + + +

    + + , } } /> - - - - -

    - - - , - } - } - /> -

    - - - -
    -
    - - - - - + - - - -
    -
    + + + + + + + + + + + + `; diff --git a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/confirm_delete_modal.tsx b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/confirm_delete_modal.tsx index c57bc1cef8fbee..94a5c082834ad7 100644 --- a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/confirm_delete_modal.tsx +++ b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/confirm_delete_modal.tsx @@ -20,7 +20,6 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiModalProps, - EuiOverlayMask, EuiSpacer, EuiText, } from '@elastic/eui'; @@ -97,88 +96,86 @@ class ConfirmDeleteModalUI extends Component { }; return ( - - - - + + + + + + + + +

    + + + ), }} /> - - - - -

    - - - - ), - }} - /> -

    - - - - - - {warning} -
    -
    - - + + - - - - - - - -
    -
    + + + {warning} + + + + + + + + + + + + ); } diff --git a/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/__snapshots__/confirm_alter_active_space_modal.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/__snapshots__/confirm_alter_active_space_modal.test.tsx.snap index 750afcfc44e7e3..3eb92de017927b 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/__snapshots__/confirm_alter_active_space_modal.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/__snapshots__/confirm_alter_active_space_modal.test.tsx.snap @@ -1,28 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmAlterActiveSpaceModal renders as expected 1`] = ` - - - } - > -

    - -

    -
    -
    + + } +> +

    + +

    +
    `; diff --git a/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/confirm_alter_active_space_modal.tsx b/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/confirm_alter_active_space_modal.tsx index 1839fbdfdda7da..c95bb7250a23e1 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/confirm_alter_active_space_modal.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/confirm_alter_active_space_modal/confirm_alter_active_space_modal.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React from 'react'; @@ -16,34 +16,32 @@ interface Props { } const ConfirmAlterActiveSpaceModalUI: React.FC = (props) => ( - - - } - defaultFocusedButton={'confirm'} - cancelButtonText={props.intl.formatMessage({ - id: 'xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton', - defaultMessage: 'Cancel', - })} - confirmButtonText={props.intl.formatMessage({ - id: 'xpack.spaces.management.confirmAlterActiveSpaceModal.updateSpaceButton', - defaultMessage: 'Update space', - })} - > -

    - -

    -
    -
    + + } + defaultFocusedButton={'confirm'} + cancelButtonText={props.intl.formatMessage({ + id: 'xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton', + defaultMessage: 'Cancel', + })} + confirmButtonText={props.intl.formatMessage({ + id: 'xpack.spaces.management.confirmAlterActiveSpaceModal.updateSpaceButton', + defaultMessage: 'Update space', + })} + > +

    + +

    +
    ); export const ConfirmAlterActiveSpaceModal = injectI18n(ConfirmAlterActiveSpaceModalUI); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx index b215b2af56c3a8..2d2a5b1fcad938 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx @@ -7,7 +7,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; interface Props { onCancel: () => void; @@ -59,19 +59,17 @@ const cancelButtonText = i18n.translate( ); export const SwitchModal: FC = ({ onCancel, onConfirm, type }) => ( - - -

    {type === 'pivot' ? pivotModalMessage : sourceModalMessage}

    -
    -
    + +

    {type === 'pivot' ? pivotModalMessage : sourceModalMessage}

    +
    ); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx index 148e6c1a3bac0c..d82f0769c8b74c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx @@ -12,7 +12,6 @@ import { EuiConfirmModal, EuiFlexGroup, EuiFlexItem, - EuiOverlayMask, EuiSpacer, EuiSwitch, } from '@elastic/eui'; @@ -123,22 +122,20 @@ export const DeleteActionModal: FC = ({ ); return ( - - - {isBulkAction ? bulkDeleteModalContent : deleteModalContent} - - + + {isBulkAction ? bulkDeleteModalContent : deleteModalContent} + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx index c3967dd687a632..bb01fe355a33ec 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx @@ -7,7 +7,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiConfirmModal, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { StartAction } from './use_start_action'; @@ -24,27 +24,25 @@ export const StartActionModal: FC = ({ closeModal, items, startAndC }); return ( - - +

    + {i18n.translate('xpack.transform.transformList.startModalBody', { + defaultMessage: + 'A transform increases search and indexing load in your cluster. If excessive load is experienced, stop the transform.', })} - confirmButtonText={i18n.translate('xpack.transform.transformList.startModalStartButton', { - defaultMessage: 'Start', - })} - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - buttonColor="primary" - > -

    - {i18n.translate('xpack.transform.transformList.startModalBody', { - defaultMessage: - 'A transform increases search and indexing load in your cluster. If excessive load is experienced, stop the transform.', - })} -

    -
    -
    +

    + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index b84d7fc433dfc1..bcb07c8069ab2f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -14,7 +14,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiModal, - EuiOverlayMask, EuiPageContent, EuiPageContentBody, EuiSpacer, @@ -124,15 +123,13 @@ export const TransformManagement: FC = () => { {isSearchSelectionVisible && ( - - - - - + + + )} ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx index 952ea07ba05c33..b98db1178f4623 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import { HttpSetup } from 'kibana/public'; @@ -73,56 +73,54 @@ export const DeleteModalConfirmation = ({ } ); return ( - - { - setDeleteModalVisibility(false); - onCancel(); - }} - onConfirm={async () => { - setDeleteModalVisibility(false); - setIsLoadingState(true); - const { successes, errors } = await apiDeleteCall({ ids: idsToDelete, http }); - setIsLoadingState(false); + { + setDeleteModalVisibility(false); + onCancel(); + }} + onConfirm={async () => { + setDeleteModalVisibility(false); + setIsLoadingState(true); + const { successes, errors } = await apiDeleteCall({ ids: idsToDelete, http }); + setIsLoadingState(false); - const numSuccesses = successes.length; - const numErrors = errors.length; - if (numSuccesses > 0) { - toasts.addSuccess( - i18n.translate( - 'xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText', - { - defaultMessage: - 'Deleted {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} other {{multipleTitle}}}', - values: { numSuccesses, singleTitle, multipleTitle }, - } - ) - ); - } + const numSuccesses = successes.length; + const numErrors = errors.length; + if (numSuccesses > 0) { + toasts.addSuccess( + i18n.translate( + 'xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText', + { + defaultMessage: + 'Deleted {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} other {{multipleTitle}}}', + values: { numSuccesses, singleTitle, multipleTitle }, + } + ) + ); + } - if (numErrors > 0) { - toasts.addDanger( - i18n.translate( - 'xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText', - { - defaultMessage: - 'Failed to delete {numErrors, number} {numErrors, plural, one {{singleTitle}} other {{multipleTitle}}}', - values: { numErrors, singleTitle, multipleTitle }, - } - ) - ); - await onErrors(); - } - await onDeleted(successes); - }} - cancelButtonText={cancelButtonText} - confirmButtonText={confirmButtonText} - > - {confirmModalText} - - + if (numErrors > 0) { + toasts.addDanger( + i18n.translate( + 'xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText', + { + defaultMessage: + 'Failed to delete {numErrors, number} {numErrors, plural, one {{singleTitle}} other {{multipleTitle}}}', + values: { numErrors, singleTitle, multipleTitle }, + } + ) + ); + await onErrors(); + } + await onDeleted(successes); + }} + cancelButtonText={cancelButtonText} + confirmButtonText={confirmButtonText} + > + {confirmModalText} + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx index b7450d742bc45b..8732727b9a77a8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx @@ -7,17 +7,19 @@ import React, { useCallback, useMemo, useReducer, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiTitle, EuiFlexItem, EuiIcon, EuiFlexGroup } from '@elastic/eui'; import { EuiModal, EuiButton, + EuiButtonEmpty, EuiModalHeader, EuiModalHeaderTitle, EuiModalBody, EuiModalFooter, + EuiTitle, + EuiFlexItem, + EuiIcon, + EuiFlexGroup, } from '@elastic/eui'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { EuiOverlayMask } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ActionConnectorForm, getConnectorErrors } from './action_connector_form'; import { createConnectorReducer, InitialConnector, ConnectorReducer } from './connector_reducer'; @@ -127,92 +129,90 @@ export const ConnectorAddModal = ({ }); return ( - - - - - - {actionTypeModel && actionTypeModel.iconClass ? ( - - - - ) : null} - - -

    - -

    -
    + + + + + {actionTypeModel && actionTypeModel.iconClass ? ( + + - - - + ) : null} + + +

    + +

    +
    +
    +
    +
    +
    - - - - - - {i18n.translate( - 'xpack.triggersActionsUI.sections.addModalConnectorForm.cancelButtonLabel', - { - defaultMessage: 'Cancel', + + + + + + {i18n.translate( + 'xpack.triggersActionsUI.sections.addModalConnectorForm.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + )} + + {canSave ? ( + { + if (hasErrors) { + setConnector( + getConnectorWithInvalidatedFields( + connector, + configErrors, + secretsErrors, + connectorBaseErrors + ) + ); + return; } - )} - - {canSave ? ( - { - if (hasErrors) { - setConnector( - getConnectorWithInvalidatedFields( - connector, - configErrors, - secretsErrors, - connectorBaseErrors - ) - ); - return; - } - setIsSaving(true); - const savedAction = await onActionConnectorSave(); - setIsSaving(false); - if (savedAction) { - if (postSaveEventHandler) { - postSaveEventHandler(savedAction); - } - closeModal(); + setIsSaving(true); + const savedAction = await onActionConnectorSave(); + setIsSaving(false); + if (savedAction) { + if (postSaveEventHandler) { + postSaveEventHandler(savedAction); } - }} - > - - - ) : null} - -
    -
    + closeModal(); + } + }} + > + + + ) : null} + + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_close.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_close.tsx index 9ef7e414d505e9..6d71fe858f1c12 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_close.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_close.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -17,38 +17,36 @@ interface Props { export const ConfirmAlertClose: React.FC = ({ onConfirm, onCancel }) => { return ( - - -

    - -

    -
    -
    + +

    + +

    +
    ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_save.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_save.tsx index 48d4229bb9b303..c406ec7c802837 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_save.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/confirm_alert_save.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -17,38 +17,36 @@ interface Props { export const ConfirmAlertSave: React.FC = ({ onConfirm, onCancel }) => { return ( - - -

    - -

    -
    -
    + +

    + +

    +
    ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/manage_license_modal.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/manage_license_modal.tsx index f13e5fd96d2ad8..4a5739c8b44309 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/manage_license_modal.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/manage_license_modal.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { capitalize } from 'lodash'; interface Props { @@ -26,37 +26,35 @@ export const ManageLicenseModal: React.FC = ({ }) => { const licenseRequired = capitalize(licenseType); return ( - - -

    - -

    -
    -
    + +

    + +

    +
    ); }; diff --git a/x-pack/plugins/uptime/public/components/common/charts/__snapshots__/donut_chart.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__snapshots__/donut_chart.test.tsx.snap index 31d4322210e2b7..b689ca7ff56f0e 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/__snapshots__/donut_chart.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/common/charts/__snapshots__/donut_chart.test.tsx.snap @@ -342,6 +342,14 @@ exports[`DonutChart component passes correct props without errors for valid prop "band": Object { "fill": "rgba(245, 247, 250, 1)", }, + "crossLine": Object { + "dash": Array [ + 4, + 4, + ], + "stroke": "rgba(105, 112, 125, 1)", + "strokeWidth": 1, + }, "line": Object { "dash": Array [ 4, diff --git a/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/confirm_delete.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/confirm_delete.test.tsx.snap index d83e45fea1aece..9d670158bc53a7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/confirm_delete.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/confirm_delete.test.tsx.snap @@ -1,58 +1,54 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ML Confirm Job Delete shallow renders without errors 1`] = ` - - -

    - -

    -

    - -

    -
    -
    + +

    + +

    +

    + +

    +
    `; exports[`ML Confirm Job Delete shallow renders without errors while loading 1`] = ` - - -

    - - ) -

    - +

    + - - + ) +

    + +
    `; diff --git a/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/ml_flyout.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/ml_flyout.test.tsx.snap index fd59b14520ce17..23feec1e5181c7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/ml_flyout.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/ml/__snapshots__/ml_flyout.test.tsx.snap @@ -84,7 +84,7 @@ exports[`ML Flyout component shows license info if no ml available 1`] = ` data-eui="EuiFocusTrap" >